From 4e72d945b634605ef37d7bb13dc282bef72aeb80 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 9 Oct 2015 14:00:35 -0700
Subject: [PATCH 001/301] try debuging the sh orientation on mac

---
 libraries/render-utils/src/DeferredGlobalLight.slh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh
index 983b8002f7..6621f52124 100755
--- a/libraries/render-utils/src/DeferredGlobalLight.slh
+++ b/libraries/render-utils/src/DeferredGlobalLight.slh
@@ -125,7 +125,10 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi
     vec4 fragEyeVector = invViewMat * vec4(-position, 0.0);
     vec3 fragEyeDir = normalize(fragEyeVector.xyz);
     
-    vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, fragNormal).xyz * getLightAmbientIntensity(light);
+    vec3 mapVal = evalSkyboxLight(fragNormal, 0).xyz;
+    vec3 shVal = evalSphericalLight(ambientSphere, fragNormal).xyz;
+    vec3 ambientLight = (normal.x > 0 ? mapVal : shVal) * getLightAmbientIntensity(light);
+    vec3 color = diffuse.rgb * ambientLight;
 
     vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss);
 

From 1dfafec5afaf765fa7b44485efee9888aacbfc75 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 9 Oct 2015 15:46:54 -0700
Subject: [PATCH 002/301] Prototyping controller refactoring

---
 libraries/controllers/CMakeLists.txt          |  14 ++
 .../src/controllers/ControllerMapping.cpp     | 190 ++++++++++++++++++
 2 files changed, 204 insertions(+)
 create mode 100644 libraries/controllers/CMakeLists.txt
 create mode 100644 libraries/controllers/src/controllers/ControllerMapping.cpp

diff --git a/libraries/controllers/CMakeLists.txt b/libraries/controllers/CMakeLists.txt
new file mode 100644
index 0000000000..fbabbe1463
--- /dev/null
+++ b/libraries/controllers/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(TARGET_NAME controllers)
+
+# set a default root dir for each of our optional externals if it was not passed
+setup_hifi_library(Script)
+
+# use setup_hifi_library macro to setup our project and link appropriate Qt modules
+link_hifi_libraries(shared plugins input-plugins)
+
+GroupSources("src/controllers")
+
+add_dependency_external_projects(glm)
+find_package(GLM REQUIRED)
+target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
+
diff --git a/libraries/controllers/src/controllers/ControllerMapping.cpp b/libraries/controllers/src/controllers/ControllerMapping.cpp
new file mode 100644
index 0000000000..59f8789d31
--- /dev/null
+++ b/libraries/controllers/src/controllers/ControllerMapping.cpp
@@ -0,0 +1,190 @@
+#include <map>
+#include <list>
+
+#include <QtCore/QObject>
+#include <QtScript/QScriptValue>
+
+extern float currentTime();
+
+namespace Controllers {
+
+    /*
+    * Encapsulates a particular input / output,
+    * i.e. Hydra.Button0, Standard.X, Action.Yaw
+    */
+    class Endpoint {
+    public:
+        virtual float value() = 0;
+        virtual void apply(float newValue, float oldValue, const Endpoint& source) = 0;
+    };
+
+    using EndpointList = std::list<Endpoint*>;
+
+    const EndpointList& getHardwareEndpoints();
+
+    // Ex: xbox.RY, xbox.A .... 
+    class HardwareEndpoint : public Endpoint {
+    public:
+        virtual float value() override {
+            // ...
+        }
+
+        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
+            // Default does nothing, but in theory this could be something like vibration
+            // mapping.from(xbox.X).to(xbox.Vibrate)
+        }
+    };
+
+    class VirtualEndpoint : public Endpoint {
+    public:
+        virtual void apply(float newValue) {
+            if (newValue != _lastValue) {
+                _lastValue = newValue;
+            }
+        }
+
+        virtual float value() {
+            return _lastValue;
+        }
+
+        float _lastValue;
+    };
+
+    /*
+    * A function which provides input
+    */
+    class FunctionEndpoint : public Endpoint {
+    public:
+
+        virtual float value() override {
+            float now = currentTime();
+            float delta = now - _lastCalled;
+            float result = _inputFunction.call(_object, QScriptValue(delta)).toNumber();
+            _lastCalled = now;
+            return result;
+        }
+
+        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
+            if (newValue != oldValue) {
+                //_outputFunction.call(newValue, oldValue, source);
+            }
+        }
+
+        float _lastValue{ NAN };
+        float _lastCalled{ 0 };
+        QScriptValue _outputFunction;
+        QScriptValue _inputFunction;
+        QScriptValue _object;
+    };
+
+
+    // Encapsulates part of a filter chain
+    class Filter {
+    public:
+        virtual float apply(float newValue, float oldValue) = 0;
+    };
+
+    class ScaleFilter : public Filter {
+    public:
+        virtual float apply(float newValue, float oldValue) {
+            return newValue * _scale;
+        }
+
+        float _scale{ 1.0 };
+    };
+
+    class PulseFilter : public Filter {
+    public:
+        virtual float apply(float newValue, float oldValue) {
+            // ???
+        }
+
+        float _lastEmitValue{ 0 };
+        float _lastEmitTime{ 0 };
+        float _interval{ -1.0f };
+    };
+
+    using FilterList = std::list<Filter*>;
+
+    /*
+    * encapsulates a source, destination and filters to apply
+    */
+    class Route {
+    public:
+        Endpoint* _source;
+        Endpoint* _destination;
+        FilterList _filters;
+    };
+
+    using ValueMap = std::map<Endpoint*, float>;
+
+    class Mapping {
+    public:
+        // List of routes
+        using List = std::list<Route>;
+        // Map of source channels to route lists
+        using Map = std::map<Endpoint*, List>;
+
+        Map _channelMappings;
+        ValueMap _lastValues;
+    };
+
+    class MappingsStack {
+        std::list<Mapping> _stack;
+        ValueMap _lastValues;
+
+        void update() {
+            EndpointList hardwareInputs = getHardwareEndpoints();
+            ValueMap currentValues;
+
+            for (auto input : hardwareInputs) {
+                currentValues[input] = input->value();
+            }
+
+            // Now process the current values for each level of the stack
+            for (auto& mapping : _stack) {
+                update(mapping, currentValues);
+            }
+
+            _lastValues = currentValues;
+        }
+
+        void update(Mapping& mapping, ValueMap& values) {
+            ValueMap updates;
+            EndpointList consumedEndpoints;
+            for (const auto& entry : values) {
+                Endpoint* endpoint = entry.first;
+                if (!mapping._channelMappings.count(endpoint)) {
+                    continue;
+                }
+
+                const Mapping::List& routes = mapping._channelMappings[endpoint];
+                consumedEndpoints.push_back(endpoint);
+                for (const auto& route : routes) {
+                    float lastValue = 0;
+                    if (mapping._lastValues.count(endpoint)) {
+                        lastValue = mapping._lastValues[endpoint];
+                    }
+                    float value = entry.second;
+                    for (const auto& filter : route._filters) {
+                        value = filter->apply(value, lastValue);
+                    }
+                    updates[route._destination] = value;
+                }
+            }
+
+            // Update the last seen values
+            mapping._lastValues = values;
+
+            // Remove all the consumed inputs
+            for (auto endpoint : consumedEndpoints) {
+                values.erase(endpoint); 
+            }
+
+            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
+            for (const auto& entry : updates) {
+                values[entry.first] = entry.second;
+            }
+        }
+    };
+}

From f0af4f17753ae36a1a39109f9e03149de8abe066 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 9 Oct 2015 16:08:35 -0700
Subject: [PATCH 003/301] try debuging the sh orientation on mac

---
 libraries/render-utils/src/DeferredGlobalLight.slh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh
index 6621f52124..351a178968 100755
--- a/libraries/render-utils/src/DeferredGlobalLight.slh
+++ b/libraries/render-utils/src/DeferredGlobalLight.slh
@@ -41,7 +41,7 @@ struct SphericalHarmonics {
 
 vec4 evalSphericalLight(SphericalHarmonics sh, vec3 direction ) {
 
-    vec3 dir = direction.xzy; // we don;t understand why yet but we need to use z as vertical axis?
+    vec3 dir = direction.xyz; // we don;t understand why yet but we need to use z as vertical axis?
 
     const float C1 = 0.429043;
     const float C2 = 0.511664;

From 184e9a2209df5d4b6f7981d9bc76c41ca3b4ac88 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 9 Oct 2015 16:20:55 -0700
Subject: [PATCH 004/301] Prototyping controllers

---
 interface/CMakeLists.txt                      |   3 +-
 .../src/controllers/ControllerMapping.h       | 149 ++++++++++++++++++
 .../controllers/src/controllers/Endpoint.cpp  |  58 +++++++
 .../controllers/src/controllers/Endpoint.h    |  34 ++++
 4 files changed, 243 insertions(+), 1 deletion(-)
 create mode 100644 libraries/controllers/src/controllers/ControllerMapping.h
 create mode 100644 libraries/controllers/src/controllers/Endpoint.cpp
 create mode 100644 libraries/controllers/src/controllers/Endpoint.h

diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index 63d1445496..2ce7f9a76d 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -118,7 +118,8 @@ target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
 link_hifi_libraries(shared octree environment gpu procedural  model render fbx networking model-networking entities avatars 
                     audio audio-client animation script-engine physics 
                     render-utils entities-renderer ui auto-updater 
-                    plugins display-plugins input-plugins)
+                    plugins display-plugins input-plugins
+                    controllers)
 
 add_dependency_external_projects(sdl2)
 
diff --git a/libraries/controllers/src/controllers/ControllerMapping.h b/libraries/controllers/src/controllers/ControllerMapping.h
new file mode 100644
index 0000000000..ade9984309
--- /dev/null
+++ b/libraries/controllers/src/controllers/ControllerMapping.h
@@ -0,0 +1,149 @@
+#include <map>
+#include <list>
+
+#include <QtCore/QObject>
+#include <QtScript/QScriptValue>
+
+extern float currentTime();
+
+namespace Controllers {
+
+
+    /*
+    * A function which provides input
+    */
+    class FunctionEndpoint : public Endpoint {
+    public:
+
+        virtual float value() override {
+            float now = currentTime();
+            float delta = now - _lastCalled;
+            float result = _inputFunction.call(_object, QScriptValue(delta)).toNumber();
+            _lastCalled = now;
+            return result;
+        }
+
+        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
+            if (newValue != oldValue) {
+                //_outputFunction.call(newValue, oldValue, source);
+            }
+        }
+
+        float _lastValue{ NAN };
+        float _lastCalled{ 0 };
+        QScriptValue _outputFunction;
+        QScriptValue _inputFunction;
+        QScriptValue _object;
+    };
+
+
+    // Encapsulates part of a filter chain
+    class Filter {
+    public:
+        virtual float apply(float newValue, float oldValue) = 0;
+    };
+
+    class ScaleFilter : public Filter {
+    public:
+        virtual float apply(float newValue, float oldValue) {
+            return newValue * _scale;
+        }
+
+        float _scale{ 1.0 };
+    };
+
+    class PulseFilter : public Filter {
+    public:
+        virtual float apply(float newValue, float oldValue) {
+            // ???
+        }
+
+        float _lastEmitValue{ 0 };
+        float _lastEmitTime{ 0 };
+        float _interval{ -1.0f };
+    };
+
+    using FilterList = std::list<Filter*>;
+
+    /*
+    * encapsulates a source, destination and filters to apply
+    */
+    class Route {
+    public:
+        Endpoint* _source;
+        Endpoint* _destination;
+        FilterList _filters;
+    };
+
+    using ValueMap = std::map<Endpoint*, float>;
+
+    class Mapping {
+    public:
+        // List of routes
+        using List = std::list<Route>;
+        // Map of source channels to route lists
+        using Map = std::map<Endpoint*, List>;
+
+        Map _channelMappings;
+        ValueMap _lastValues;
+    };
+
+    class MappingsStack {
+        std::list<Mapping> _stack;
+        ValueMap _lastValues;
+
+        void update() {
+            EndpointList hardwareInputs = getHardwareEndpoints();
+            ValueMap currentValues;
+
+            for (auto input : hardwareInputs) {
+                currentValues[input] = input->value();
+            }
+
+            // Now process the current values for each level of the stack
+            for (auto& mapping : _stack) {
+                update(mapping, currentValues);
+            }
+
+            _lastValues = currentValues;
+        }
+
+        void update(Mapping& mapping, ValueMap& values) {
+            ValueMap updates;
+            EndpointList consumedEndpoints;
+            for (const auto& entry : values) {
+                Endpoint* endpoint = entry.first;
+                if (!mapping._channelMappings.count(endpoint)) {
+                    continue;
+                }
+
+                const Mapping::List& routes = mapping._channelMappings[endpoint];
+                consumedEndpoints.push_back(endpoint);
+                for (const auto& route : routes) {
+                    float lastValue = 0;
+                    if (mapping._lastValues.count(endpoint)) {
+                        lastValue = mapping._lastValues[endpoint];
+                    }
+                    float value = entry.second;
+                    for (const auto& filter : route._filters) {
+                        value = filter->apply(value, lastValue);
+                    }
+                    updates[route._destination] = value;
+                }
+            }
+
+            // Update the last seen values
+            mapping._lastValues = values;
+
+            // Remove all the consumed inputs
+            for (auto endpoint : consumedEndpoints) {
+                values.erase(endpoint); 
+            }
+
+            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
+            for (const auto& entry : updates) {
+                values[entry.first] = entry.second;
+            }
+        }
+    };
+}
diff --git a/libraries/controllers/src/controllers/Endpoint.cpp b/libraries/controllers/src/controllers/Endpoint.cpp
new file mode 100644
index 0000000000..5f9e0b0efa
--- /dev/null
+++ b/libraries/controllers/src/controllers/Endpoint.cpp
@@ -0,0 +1,58 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Endpoint.h"
+
+#include <mutex>
+#include <input-plugins/UserInputMapper.h>
+
+namespace Controllers {
+
+    // FIXME how do we handle dynamic changes in connected hardware?
+    const Endpoint::List& Endpoint::getHardwareEndpoints() {
+        static Endpoint::List ACTIVE_HARDWARE;
+        static std::once_flag once;
+        std::call_once(once, [&] {
+            auto userInputMapper = DependencyManager::get<UserInputMapper>();
+            // TODO populate ACTIVE_HARDWARE with all the connected devices
+            // For each connected device
+                // for each input channel
+                    // build a HardwareEndpoint instance around the input channel and add it to the list
+        });
+    }
+
+    // Ex: xbox.RY, xbox.A ....
+    class HardwareEndpoint : public Endpoint {
+    public:
+        virtual float value() override {
+            // ...
+        }
+
+        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
+            // Default does nothing, but in theory this could be something like vibration
+            // mapping.from(xbox.X).to(xbox.Vibrate)
+        }
+    };
+
+    // Ex: Standard.RY, Action.Yaw
+    class VirtualEndpoint : public Endpoint {
+    public:
+        virtual void apply(float newValue) {
+            if (newValue != _lastValue) {
+                _lastValue = newValue;
+            }
+        }
+
+        virtual float value() {
+            return _lastValue;
+        }
+
+        float _lastValue;
+    };
+
+}
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
new file mode 100644
index 0000000000..7361c15706
--- /dev/null
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -0,0 +1,34 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Endpoint_h
+#define hifi_Controllers_Endpoint_h
+
+#include <list>
+#include <memory>
+
+namespace Controllers {
+    /*
+    * Encapsulates a particular input / output,
+    * i.e. Hydra.Button0, Standard.X, Action.Yaw
+    */
+    class Endpoint {
+    public:
+        virtual float value() = 0;
+        virtual void apply(float newValue, float oldValue, const Endpoint& source) = 0;
+
+        using Pointer = std::shared_ptr<Endpoint>;
+        using List = std::list<Pointer>;
+
+        static const List& getHardwareEndpoints();
+    };
+
+}
+
+#endif

From c3775623aa6bd5084fee7e0fc86a68c04192d4b1 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 9 Oct 2015 17:23:52 -0700
Subject: [PATCH 005/301] Splitting files, adding test skeleton

---
 .../src/controllers/ControllerMapping.cpp     | 190 ------------------
 .../src/controllers/ControllerMapping.h       | 149 --------------
 .../controllers/src/controllers/Endpoint.cpp  |  59 ++++--
 .../controllers/src/controllers/Filter.cpp    |  41 ++++
 .../controllers/src/controllers/Filter.h      |  29 +++
 .../controllers/src/controllers/Mapping.cpp   |   9 +
 .../controllers/src/controllers/Mapping.h     |  87 ++++++++
 libraries/controllers/src/controllers/Route.h |  32 +++
 tests/controllers/CMakeLists.txt              |  13 ++
 tests/controllers/src/main.cpp                |  38 ++++
 10 files changed, 295 insertions(+), 352 deletions(-)
 delete mode 100644 libraries/controllers/src/controllers/ControllerMapping.cpp
 delete mode 100644 libraries/controllers/src/controllers/ControllerMapping.h
 create mode 100644 libraries/controllers/src/controllers/Filter.cpp
 create mode 100644 libraries/controllers/src/controllers/Filter.h
 create mode 100644 libraries/controllers/src/controllers/Mapping.cpp
 create mode 100644 libraries/controllers/src/controllers/Mapping.h
 create mode 100644 libraries/controllers/src/controllers/Route.h
 create mode 100644 tests/controllers/CMakeLists.txt
 create mode 100644 tests/controllers/src/main.cpp

diff --git a/libraries/controllers/src/controllers/ControllerMapping.cpp b/libraries/controllers/src/controllers/ControllerMapping.cpp
deleted file mode 100644
index 59f8789d31..0000000000
--- a/libraries/controllers/src/controllers/ControllerMapping.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-#include <map>
-#include <list>
-
-#include <QtCore/QObject>
-#include <QtScript/QScriptValue>
-
-extern float currentTime();
-
-namespace Controllers {
-
-    /*
-    * Encapsulates a particular input / output,
-    * i.e. Hydra.Button0, Standard.X, Action.Yaw
-    */
-    class Endpoint {
-    public:
-        virtual float value() = 0;
-        virtual void apply(float newValue, float oldValue, const Endpoint& source) = 0;
-    };
-
-    using EndpointList = std::list<Endpoint*>;
-
-    const EndpointList& getHardwareEndpoints();
-
-    // Ex: xbox.RY, xbox.A .... 
-    class HardwareEndpoint : public Endpoint {
-    public:
-        virtual float value() override {
-            // ...
-        }
-
-        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
-            // Default does nothing, but in theory this could be something like vibration
-            // mapping.from(xbox.X).to(xbox.Vibrate)
-        }
-    };
-
-    class VirtualEndpoint : public Endpoint {
-    public:
-        virtual void apply(float newValue) {
-            if (newValue != _lastValue) {
-                _lastValue = newValue;
-            }
-        }
-
-        virtual float value() {
-            return _lastValue;
-        }
-
-        float _lastValue;
-    };
-
-    /*
-    * A function which provides input
-    */
-    class FunctionEndpoint : public Endpoint {
-    public:
-
-        virtual float value() override {
-            float now = currentTime();
-            float delta = now - _lastCalled;
-            float result = _inputFunction.call(_object, QScriptValue(delta)).toNumber();
-            _lastCalled = now;
-            return result;
-        }
-
-        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
-            if (newValue != oldValue) {
-                //_outputFunction.call(newValue, oldValue, source);
-            }
-        }
-
-        float _lastValue{ NAN };
-        float _lastCalled{ 0 };
-        QScriptValue _outputFunction;
-        QScriptValue _inputFunction;
-        QScriptValue _object;
-    };
-
-
-    // Encapsulates part of a filter chain
-    class Filter {
-    public:
-        virtual float apply(float newValue, float oldValue) = 0;
-    };
-
-    class ScaleFilter : public Filter {
-    public:
-        virtual float apply(float newValue, float oldValue) {
-            return newValue * _scale;
-        }
-
-        float _scale{ 1.0 };
-    };
-
-    class PulseFilter : public Filter {
-    public:
-        virtual float apply(float newValue, float oldValue) {
-            // ???
-        }
-
-        float _lastEmitValue{ 0 };
-        float _lastEmitTime{ 0 };
-        float _interval{ -1.0f };
-    };
-
-    using FilterList = std::list<Filter*>;
-
-    /*
-    * encapsulates a source, destination and filters to apply
-    */
-    class Route {
-    public:
-        Endpoint* _source;
-        Endpoint* _destination;
-        FilterList _filters;
-    };
-
-    using ValueMap = std::map<Endpoint*, float>;
-
-    class Mapping {
-    public:
-        // List of routes
-        using List = std::list<Route>;
-        // Map of source channels to route lists
-        using Map = std::map<Endpoint*, List>;
-
-        Map _channelMappings;
-        ValueMap _lastValues;
-    };
-
-    class MappingsStack {
-        std::list<Mapping> _stack;
-        ValueMap _lastValues;
-
-        void update() {
-            EndpointList hardwareInputs = getHardwareEndpoints();
-            ValueMap currentValues;
-
-            for (auto input : hardwareInputs) {
-                currentValues[input] = input->value();
-            }
-
-            // Now process the current values for each level of the stack
-            for (auto& mapping : _stack) {
-                update(mapping, currentValues);
-            }
-
-            _lastValues = currentValues;
-        }
-
-        void update(Mapping& mapping, ValueMap& values) {
-            ValueMap updates;
-            EndpointList consumedEndpoints;
-            for (const auto& entry : values) {
-                Endpoint* endpoint = entry.first;
-                if (!mapping._channelMappings.count(endpoint)) {
-                    continue;
-                }
-
-                const Mapping::List& routes = mapping._channelMappings[endpoint];
-                consumedEndpoints.push_back(endpoint);
-                for (const auto& route : routes) {
-                    float lastValue = 0;
-                    if (mapping._lastValues.count(endpoint)) {
-                        lastValue = mapping._lastValues[endpoint];
-                    }
-                    float value = entry.second;
-                    for (const auto& filter : route._filters) {
-                        value = filter->apply(value, lastValue);
-                    }
-                    updates[route._destination] = value;
-                }
-            }
-
-            // Update the last seen values
-            mapping._lastValues = values;
-
-            // Remove all the consumed inputs
-            for (auto endpoint : consumedEndpoints) {
-                values.erase(endpoint); 
-            }
-
-            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
-            for (const auto& entry : updates) {
-                values[entry.first] = entry.second;
-            }
-        }
-    };
-}
diff --git a/libraries/controllers/src/controllers/ControllerMapping.h b/libraries/controllers/src/controllers/ControllerMapping.h
deleted file mode 100644
index ade9984309..0000000000
--- a/libraries/controllers/src/controllers/ControllerMapping.h
+++ /dev/null
@@ -1,149 +0,0 @@
-#include <map>
-#include <list>
-
-#include <QtCore/QObject>
-#include <QtScript/QScriptValue>
-
-extern float currentTime();
-
-namespace Controllers {
-
-
-    /*
-    * A function which provides input
-    */
-    class FunctionEndpoint : public Endpoint {
-    public:
-
-        virtual float value() override {
-            float now = currentTime();
-            float delta = now - _lastCalled;
-            float result = _inputFunction.call(_object, QScriptValue(delta)).toNumber();
-            _lastCalled = now;
-            return result;
-        }
-
-        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
-            if (newValue != oldValue) {
-                //_outputFunction.call(newValue, oldValue, source);
-            }
-        }
-
-        float _lastValue{ NAN };
-        float _lastCalled{ 0 };
-        QScriptValue _outputFunction;
-        QScriptValue _inputFunction;
-        QScriptValue _object;
-    };
-
-
-    // Encapsulates part of a filter chain
-    class Filter {
-    public:
-        virtual float apply(float newValue, float oldValue) = 0;
-    };
-
-    class ScaleFilter : public Filter {
-    public:
-        virtual float apply(float newValue, float oldValue) {
-            return newValue * _scale;
-        }
-
-        float _scale{ 1.0 };
-    };
-
-    class PulseFilter : public Filter {
-    public:
-        virtual float apply(float newValue, float oldValue) {
-            // ???
-        }
-
-        float _lastEmitValue{ 0 };
-        float _lastEmitTime{ 0 };
-        float _interval{ -1.0f };
-    };
-
-    using FilterList = std::list<Filter*>;
-
-    /*
-    * encapsulates a source, destination and filters to apply
-    */
-    class Route {
-    public:
-        Endpoint* _source;
-        Endpoint* _destination;
-        FilterList _filters;
-    };
-
-    using ValueMap = std::map<Endpoint*, float>;
-
-    class Mapping {
-    public:
-        // List of routes
-        using List = std::list<Route>;
-        // Map of source channels to route lists
-        using Map = std::map<Endpoint*, List>;
-
-        Map _channelMappings;
-        ValueMap _lastValues;
-    };
-
-    class MappingsStack {
-        std::list<Mapping> _stack;
-        ValueMap _lastValues;
-
-        void update() {
-            EndpointList hardwareInputs = getHardwareEndpoints();
-            ValueMap currentValues;
-
-            for (auto input : hardwareInputs) {
-                currentValues[input] = input->value();
-            }
-
-            // Now process the current values for each level of the stack
-            for (auto& mapping : _stack) {
-                update(mapping, currentValues);
-            }
-
-            _lastValues = currentValues;
-        }
-
-        void update(Mapping& mapping, ValueMap& values) {
-            ValueMap updates;
-            EndpointList consumedEndpoints;
-            for (const auto& entry : values) {
-                Endpoint* endpoint = entry.first;
-                if (!mapping._channelMappings.count(endpoint)) {
-                    continue;
-                }
-
-                const Mapping::List& routes = mapping._channelMappings[endpoint];
-                consumedEndpoints.push_back(endpoint);
-                for (const auto& route : routes) {
-                    float lastValue = 0;
-                    if (mapping._lastValues.count(endpoint)) {
-                        lastValue = mapping._lastValues[endpoint];
-                    }
-                    float value = entry.second;
-                    for (const auto& filter : route._filters) {
-                        value = filter->apply(value, lastValue);
-                    }
-                    updates[route._destination] = value;
-                }
-            }
-
-            // Update the last seen values
-            mapping._lastValues = values;
-
-            // Remove all the consumed inputs
-            for (auto endpoint : consumedEndpoints) {
-                values.erase(endpoint); 
-            }
-
-            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
-            for (const auto& entry : updates) {
-                values[entry.first] = entry.second;
-            }
-        }
-    };
-}
diff --git a/libraries/controllers/src/controllers/Endpoint.cpp b/libraries/controllers/src/controllers/Endpoint.cpp
index 5f9e0b0efa..dddacc5ae5 100644
--- a/libraries/controllers/src/controllers/Endpoint.cpp
+++ b/libraries/controllers/src/controllers/Endpoint.cpp
@@ -13,19 +13,6 @@
 
 namespace Controllers {
 
-    // FIXME how do we handle dynamic changes in connected hardware?
-    const Endpoint::List& Endpoint::getHardwareEndpoints() {
-        static Endpoint::List ACTIVE_HARDWARE;
-        static std::once_flag once;
-        std::call_once(once, [&] {
-            auto userInputMapper = DependencyManager::get<UserInputMapper>();
-            // TODO populate ACTIVE_HARDWARE with all the connected devices
-            // For each connected device
-                // for each input channel
-                    // build a HardwareEndpoint instance around the input channel and add it to the list
-        });
-    }
-
     // Ex: xbox.RY, xbox.A ....
     class HardwareEndpoint : public Endpoint {
     public:
@@ -55,4 +42,50 @@ namespace Controllers {
         float _lastValue;
     };
 
+    float currentTime() {
+        return 0;
+    }
+    /*
+    * A function which provides input
+    */
+    class FunctionEndpoint : public Endpoint {
+    public:
+
+        virtual float value() override {
+            float now = currentTime();
+            float delta = now - _lastCalled;
+            float result = _inputFunction.call(_object, QScriptValue(delta)).toNumber();
+            _lastCalled = now;
+            return result;
+        }
+
+        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
+            if (newValue != oldValue) {
+                //_outputFunction.call(newValue, oldValue, source);
+            }
+        }
+
+        float _lastValue{ NAN };
+        float _lastCalled{ 0 };
+        QScriptValue _outputFunction;
+        QScriptValue _inputFunction;
+        QScriptValue _object;
+    };
+
+
+
+    // FIXME how do we handle dynamic changes in connected hardware?
+    const Endpoint::List& Endpoint::getHardwareEndpoints() {
+        static Endpoint::List ACTIVE_HARDWARE_ENDPOINTS;
+        static std::once_flag once;
+        std::call_once(once, [&] {
+            auto userInputMapper = DependencyManager::get<UserInputMapper>();
+            // TODO populate ACTIVE_HARDWARE with all the connected devices
+            // For each connected device
+            // for each input channel
+            // build a HardwareEndpoint instance around the input channel and add it to the list
+        });
+
+        return ACTIVE_HARDWARE_ENDPOINTS;
+    }
 }
diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
new file mode 100644
index 0000000000..93f5528073
--- /dev/null
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -0,0 +1,41 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Filter.h"
+
+#include <QtCore/QObject>
+#include <QtScript/QScriptValue>
+
+namespace Controllers {
+
+    class ScaleFilter : public Filter {
+    public:
+        virtual float apply(float newValue, float oldValue) {
+            return newValue * _scale;
+        }
+
+    private:
+        float _scale{ 1.0 };
+    };
+
+    class PulseFilter : public Filter {
+    public:
+        virtual float apply(float newValue, float oldValue) {
+            // ???
+        }
+
+    private:
+
+        float _lastEmitValue{ 0 };
+        float _lastEmitTime{ 0 };
+        float _interval{ -1.0f };
+    };
+
+
+}
+
diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h
new file mode 100644
index 0000000000..9a0e4d975c
--- /dev/null
+++ b/libraries/controllers/src/controllers/Filter.h
@@ -0,0 +1,29 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filter_h
+#define hifi_Controllers_Filter_h
+
+#include <list>
+#include <memory>
+
+namespace Controllers {
+
+    // Encapsulates part of a filter chain
+    class Filter {
+    public:
+        virtual float apply(float newValue, float oldValue) = 0;
+
+        using Pointer = std::shared_ptr<Filter>;
+        using List = std::list<Pointer>;
+    };
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/Mapping.cpp
new file mode 100644
index 0000000000..dbcc6407f1
--- /dev/null
+++ b/libraries/controllers/src/controllers/Mapping.cpp
@@ -0,0 +1,9 @@
+#include "Mapping.h"
+
+#include <QtCore/QObject>
+#include <QtScript/QScriptValue>
+
+extern float currentTime();
+
+namespace Controllers {
+}
diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h
new file mode 100644
index 0000000000..46ed0f1a35
--- /dev/null
+++ b/libraries/controllers/src/controllers/Mapping.h
@@ -0,0 +1,87 @@
+#include <map>
+#include <list>
+
+#include <QtCore/QObject>
+#include <QtScript/QScriptValue>
+
+extern float currentTime();
+
+#include "Endpoint.h"
+#include "Filter.h"
+#include "Route.h"
+
+namespace Controllers {
+
+    using ValueMap = std::map<Endpoint::Pointer, float>;
+
+    class Mapping {
+    public:
+        // Map of source channels to route lists
+        using Map = std::map<Endpoint::Pointer, Route::List>;
+
+        Map _channelMappings;
+        ValueMap _lastValues;
+
+        void parse(const QString& json);
+        QString serialize();
+    };
+
+//    class MappingsStack {
+//        std::list<Mapping> _stack;
+//        ValueMap _lastValues;
+//
+//        void update() {
+//            EndpointList hardwareInputs = getHardwareEndpoints();
+//            ValueMap currentValues;
+//
+//            for (auto input : hardwareInputs) {
+//                currentValues[input] = input->value();
+//            }
+//
+//            // Now process the current values for each level of the stack
+//            for (auto& mapping : _stack) {
+//                update(mapping, currentValues);
+//            }
+//
+//            _lastValues = currentValues;
+//        }
+//
+//        void update(Mapping& mapping, ValueMap& values) {
+//            ValueMap updates;
+//            EndpointList consumedEndpoints;
+//            for (const auto& entry : values) {
+//                Endpoint* endpoint = entry.first;
+//                if (!mapping._channelMappings.count(endpoint)) {
+//                    continue;
+//                }
+//
+//                const Mapping::List& routes = mapping._channelMappings[endpoint];
+//                consumedEndpoints.push_back(endpoint);
+//                for (const auto& route : routes) {
+//                    float lastValue = 0;
+//                    if (mapping._lastValues.count(endpoint)) {
+//                        lastValue = mapping._lastValues[endpoint];
+//                    }
+//                    float value = entry.second;
+//                    for (const auto& filter : route._filters) {
+//                        value = filter->apply(value, lastValue);
+//                    }
+//                    updates[route._destination] = value;
+//                }
+//            }
+//
+//            // Update the last seen values
+//            mapping._lastValues = values;
+//
+//            // Remove all the consumed inputs
+//            for (auto endpoint : consumedEndpoints) {
+//                values.erase(endpoint);
+//            }
+//
+//            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
+//            for (const auto& entry : updates) {
+//                values[entry.first] = entry.second;
+//            }
+//        }
+//    };
+}
diff --git a/libraries/controllers/src/controllers/Route.h b/libraries/controllers/src/controllers/Route.h
new file mode 100644
index 0000000000..616a5ebc23
--- /dev/null
+++ b/libraries/controllers/src/controllers/Route.h
@@ -0,0 +1,32 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Route_h
+#define hifi_Controllers_Route_h
+
+#include "Endpoint.h"
+#include "Filter.h"
+
+namespace Controllers {
+
+    /*
+    * encapsulates a source, destination and filters to apply
+    */
+    class Route {
+    public:
+        Endpoint::Pointer _source;
+        Endpoint::Pointer _destination;
+        Filter::List _filters;
+
+        using Pointer = std::shared_ptr<Route>;
+        using List = std::list<Pointer>;
+    };
+}
+
+#endif
diff --git a/tests/controllers/CMakeLists.txt b/tests/controllers/CMakeLists.txt
new file mode 100644
index 0000000000..4e31881141
--- /dev/null
+++ b/tests/controllers/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+set(TARGET_NAME controllers-test)
+ 
+AUTOSCRIBE_SHADER_LIB(gpu model render-utils )
+
+# This is not a testcase -- just set it up as a regular hifi project
+setup_hifi_project(Script)
+set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
+
+# link in the shared libraries
+link_hifi_libraries(shared script-engine input-plugins controllers)
+
+copy_dlls_beside_windows_executable()
\ No newline at end of file
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
new file mode 100644
index 0000000000..88d29214d3
--- /dev/null
+++ b/tests/controllers/src/main.cpp
@@ -0,0 +1,38 @@
+//
+//  main.cpp
+//  tests/gpu-test/src
+//
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <unordered_map>
+#include <memory>
+#include <cstdio>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+
+#include <QtCore/QTime>
+#include <QtCore/QTimer>
+#include <QtCore/QDir>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QFile>
+#include <QtCore/QLoggingCategory>
+
+#include <QtGui/QResizeEvent>
+#include <QtGui/QWindow>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QImage>
+
+int main(int argc, char** argv) {    
+    QGuiApplication app(argc, argv);
+    QWindow window;
+    app.exec();
+    return 0;
+}
+
+#include "main.moc"
+

From c02d33c17cebb798fbf7bff43b9579c9b6419a30 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 9 Oct 2015 17:27:50 -0700
Subject: [PATCH 006/301] Adding example mapping files

---
 .../resources/controllers/mapping-config.json | 24 +++++++++++++
 .../resources/controllers/mapping-test0.json  | 36 +++++++++++++++++++
 2 files changed, 60 insertions(+)
 create mode 100644 interface/resources/controllers/mapping-config.json
 create mode 100644 interface/resources/controllers/mapping-test0.json

diff --git a/interface/resources/controllers/mapping-config.json b/interface/resources/controllers/mapping-config.json
new file mode 100644
index 0000000000..053a637c6f
--- /dev/null
+++ b/interface/resources/controllers/mapping-config.json
@@ -0,0 +1,24 @@
+{
+    "name": "Full Mapping config including the standard hydra and gamepad and one more thing",
+    "mappings": [ 
+        "src": "./mapping-hydra.json",
+        "src": "./mapping-xbox.json",
+        {
+            "name": "example mapping for standard to js function",
+            "channels": [ {
+                    "from": "Standard.B",
+                    "to": {
+                        "type":"js",
+                        "function": "function(value){  print("Standard.B = " + value );}"
+                    }
+                }, {
+                    "from": "Standard.B",
+                    "to": {
+                        "type":"js",
+                        "src": "http://www.theNextBigThing.com/hifiInputSignalHandler.js"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/interface/resources/controllers/mapping-test0.json b/interface/resources/controllers/mapping-test0.json
new file mode 100644
index 0000000000..c52b03be92
--- /dev/null
+++ b/interface/resources/controllers/mapping-test0.json
@@ -0,0 +1,36 @@
+{
+    "name": "example mapping from Standard to actions",
+    "channels": [ {
+            "from": "Standard.LY",
+            "filters": [ {
+                    "type": "clamp",
+                    "min": 0,
+                    "max": 1,
+                }
+            ],
+            "to": "Actions.Forward",
+        }, {
+            "from": "Standard.LY",
+            "filters": [ {
+                    "type": "clamp",
+                    "min": -1,
+                    "max": 0,
+                }, {
+                    "type": "invert"
+                }
+            ],
+            "to": "Actions.Backward",
+        }, {
+            "from": "Standard.LX",
+            "filters": [ {
+                    "type": "scale",
+                    "scale": 2.0,
+                }
+            ],
+            "to": "Actions.Yaw",
+        }, {
+            "from": "Standard.A",
+            "to": "Actions.Action0"
+        }
+    ]
+}
\ No newline at end of file

From 78624679ed9f2bdcb17e7d96c52fd3b75545f29f Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 9 Oct 2015 17:30:46 -0700
Subject: [PATCH 007/301] Adding more parsing functions

---
 .../controllers/src/controllers/Filter.cpp    |  4 +++
 .../controllers/src/controllers/Filter.h      |  4 +++
 .../controllers/src/controllers/Mapping.cpp   |  5 ---
 .../controllers/src/controllers/Mapping.h     |  8 ++---
 .../controllers/src/controllers/Route.cpp     | 36 +++++++++++++++++++
 libraries/controllers/src/controllers/Route.h |  4 +++
 6 files changed, 50 insertions(+), 11 deletions(-)
 create mode 100644 libraries/controllers/src/controllers/Route.cpp

diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
index 93f5528073..6733ddc3e9 100644
--- a/libraries/controllers/src/controllers/Filter.cpp
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -37,5 +37,9 @@ namespace Controllers {
     };
 
 
+    Filter::Pointer Filter::parse(const QJsonObject& json) {
+        // FIXME parse the json object and determine the instance type to create
+        return Filter::Pointer();
+    }
 }
 
diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h
index 9a0e4d975c..a2921ee47d 100644
--- a/libraries/controllers/src/controllers/Filter.h
+++ b/libraries/controllers/src/controllers/Filter.h
@@ -13,6 +13,8 @@
 #include <list>
 #include <memory>
 
+class QJsonObject;
+
 namespace Controllers {
 
     // Encapsulates part of a filter chain
@@ -22,6 +24,8 @@ namespace Controllers {
 
         using Pointer = std::shared_ptr<Filter>;
         using List = std::list<Pointer>;
+
+        static Filter::Pointer parse(const QJsonObject& json);
     };
 
 }
diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/Mapping.cpp
index dbcc6407f1..3fdbd71d1c 100644
--- a/libraries/controllers/src/controllers/Mapping.cpp
+++ b/libraries/controllers/src/controllers/Mapping.cpp
@@ -1,9 +1,4 @@
 #include "Mapping.h"
 
-#include <QtCore/QObject>
-#include <QtScript/QScriptValue>
-
-extern float currentTime();
-
 namespace Controllers {
 }
diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h
index 46ed0f1a35..f7e0899c15 100644
--- a/libraries/controllers/src/controllers/Mapping.h
+++ b/libraries/controllers/src/controllers/Mapping.h
@@ -1,15 +1,11 @@
 #include <map>
-#include <list>
-
-#include <QtCore/QObject>
-#include <QtScript/QScriptValue>
-
-extern float currentTime();
 
 #include "Endpoint.h"
 #include "Filter.h"
 #include "Route.h"
 
+class QString;
+
 namespace Controllers {
 
     using ValueMap = std::map<Endpoint::Pointer, float>;
diff --git a/libraries/controllers/src/controllers/Route.cpp b/libraries/controllers/src/controllers/Route.cpp
new file mode 100644
index 0000000000..29fb9b04eb
--- /dev/null
+++ b/libraries/controllers/src/controllers/Route.cpp
@@ -0,0 +1,36 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Route_h
+#define hifi_Controllers_Route_h
+
+#include "Endpoint.h"
+#include "Filter.h"
+
+class QJsonObject;
+
+namespace Controllers {
+
+    /*
+    * encapsulates a source, destination and filters to apply
+    */
+    class Route {
+    public:
+        Endpoint::Pointer _source;
+        Endpoint::Pointer _destination;
+        Filter::List _filters;
+
+        using Pointer = std::shared_ptr<Route>;
+        using List = std::list<Pointer>;
+
+        void parse(const QJsonObject& json);
+    };
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/Route.h b/libraries/controllers/src/controllers/Route.h
index 616a5ebc23..9459369d18 100644
--- a/libraries/controllers/src/controllers/Route.h
+++ b/libraries/controllers/src/controllers/Route.h
@@ -13,6 +13,8 @@
 #include "Endpoint.h"
 #include "Filter.h"
 
+class QJsonObject;
+
 namespace Controllers {
 
     /*
@@ -26,6 +28,8 @@ namespace Controllers {
 
         using Pointer = std::shared_ptr<Route>;
         using List = std::list<Pointer>;
+
+        void parse(const QJsonObject);
     };
 }
 

From 297c3c9ed0dbacd7bcd3e9b82e6f98c69703451e Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 9 Oct 2015 17:37:51 -0700
Subject: [PATCH 008/301] Fixing json issues

---
 interface/resources/controllers/mapping-config.json | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/interface/resources/controllers/mapping-config.json b/interface/resources/controllers/mapping-config.json
index 053a637c6f..dd3bc7b05e 100644
--- a/interface/resources/controllers/mapping-config.json
+++ b/interface/resources/controllers/mapping-config.json
@@ -1,15 +1,15 @@
 {
     "name": "Full Mapping config including the standard hydra and gamepad and one more thing",
-    "mappings": [ 
-        "src": "./mapping-hydra.json",
-        "src": "./mapping-xbox.json",
+    "mappings": [
+        { "src": "./mapping-hydra.json" },
+        { "src": "./mapping-xbox.json" },
         {
             "name": "example mapping for standard to js function",
             "channels": [ {
                     "from": "Standard.B",
                     "to": {
                         "type":"js",
-                        "function": "function(value){  print("Standard.B = " + value );}"
+                        "function": "function(value){  print(\"Standard.B = \" + value );}"
                     }
                 }, {
                     "from": "Standard.B",

From 3d607f406f99a349504b32aedbfacef4d5ec296d Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 9 Oct 2015 17:40:36 -0700
Subject: [PATCH 009/301] revert change to the slf file

---
 libraries/render-utils/src/DeferredGlobalLight.slh | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh
index 351a178968..983b8002f7 100755
--- a/libraries/render-utils/src/DeferredGlobalLight.slh
+++ b/libraries/render-utils/src/DeferredGlobalLight.slh
@@ -41,7 +41,7 @@ struct SphericalHarmonics {
 
 vec4 evalSphericalLight(SphericalHarmonics sh, vec3 direction ) {
 
-    vec3 dir = direction.xyz; // we don;t understand why yet but we need to use z as vertical axis?
+    vec3 dir = direction.xzy; // we don;t understand why yet but we need to use z as vertical axis?
 
     const float C1 = 0.429043;
     const float C2 = 0.511664;
@@ -125,10 +125,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi
     vec4 fragEyeVector = invViewMat * vec4(-position, 0.0);
     vec3 fragEyeDir = normalize(fragEyeVector.xyz);
     
-    vec3 mapVal = evalSkyboxLight(fragNormal, 0).xyz;
-    vec3 shVal = evalSphericalLight(ambientSphere, fragNormal).xyz;
-    vec3 ambientLight = (normal.x > 0 ? mapVal : shVal) * getLightAmbientIntensity(light);
-    vec3 color = diffuse.rgb * ambientLight;
+    vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, fragNormal).xyz * getLightAmbientIntensity(light);
 
     vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss);
 

From c2da6600f54d07ebc712e73a50c727ce3d8e2cae Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 9 Oct 2015 17:49:24 -0700
Subject: [PATCH 010/301] Fixing includes

---
 libraries/controllers/src/controllers/Mapping.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h
index f7e0899c15..6f843a7b23 100644
--- a/libraries/controllers/src/controllers/Mapping.h
+++ b/libraries/controllers/src/controllers/Mapping.h
@@ -1,11 +1,11 @@
 #include <map>
 
+#include <QtCore/QString>
+
 #include "Endpoint.h"
 #include "Filter.h"
 #include "Route.h"
 
-class QString;
-
 namespace Controllers {
 
     using ValueMap = std::map<Endpoint::Pointer, float>;

From 9e4a7a622637a8417776832a50305ab4b48b02b4 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sat, 10 Oct 2015 03:05:42 -0700
Subject: [PATCH 011/301] Working on controller refactoring

---
 .../controllers/src/controllers/Endpoint.h    |   7 +-
 .../controllers/src/controllers/Filter.cpp    |  24 ---
 .../controllers/src/controllers/Filter.h      | 147 +++++++++++++++++-
 .../controllers/src/controllers/Mapping.cpp   |  59 +++++++
 .../controllers/src/controllers/Mapping.h     |  74 ++-------
 .../NewControllerScriptingInterface.cpp       | 125 +++++++++++++++
 .../NewControllerScriptingInterface.h         |  31 ++++
 .../controllers/impl/MappingBuilderProxy.cpp  |  33 ++++
 .../controllers/impl/MappingBuilderProxy.h    |  35 +++++
 .../controllers/impl/RouteBuilderProxy.cpp    |  80 ++++++++++
 .../src/controllers/impl/RouteBuilderProxy.h  |  42 +++++
 libraries/shared/src/SharedUtil.cpp           |  31 ++--
 libraries/shared/src/SharedUtil.h             |   5 +
 tests/controllers/qml/main.qml                |  43 +++++
 tests/controllers/src/main.cpp                |  63 +++++++-
 15 files changed, 701 insertions(+), 98 deletions(-)
 create mode 100644 libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
 create mode 100644 libraries/controllers/src/controllers/NewControllerScriptingInterface.h
 create mode 100644 libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
 create mode 100644 libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
 create mode 100644 tests/controllers/qml/main.qml

diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index 7361c15706..48cdf015fa 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -13,6 +13,8 @@
 #include <list>
 #include <memory>
 
+class QScriptValue;
+
 namespace Controllers {
     /*
     * Encapsulates a particular input / output,
@@ -20,13 +22,14 @@ namespace Controllers {
     */
     class Endpoint {
     public:
-        virtual float value() = 0;
-        virtual void apply(float newValue, float oldValue, const Endpoint& source) = 0;
+        virtual float value() { return 0;  } // = 0;
+        virtual void apply(float newValue, float oldValue, const Endpoint& source) {} // = 0;
 
         using Pointer = std::shared_ptr<Endpoint>;
         using List = std::list<Pointer>;
 
         static const List& getHardwareEndpoints();
+        static Pointer getEndpoint(const QScriptValue& value);
     };
 
 }
diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
index 6733ddc3e9..e0c6adfcac 100644
--- a/libraries/controllers/src/controllers/Filter.cpp
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -13,30 +13,6 @@
 
 namespace Controllers {
 
-    class ScaleFilter : public Filter {
-    public:
-        virtual float apply(float newValue, float oldValue) {
-            return newValue * _scale;
-        }
-
-    private:
-        float _scale{ 1.0 };
-    };
-
-    class PulseFilter : public Filter {
-    public:
-        virtual float apply(float newValue, float oldValue) {
-            // ???
-        }
-
-    private:
-
-        float _lastEmitValue{ 0 };
-        float _lastEmitTime{ 0 };
-        float _interval{ -1.0f };
-    };
-
-
     Filter::Pointer Filter::parse(const QJsonObject& json) {
         // FIXME parse the json object and determine the instance type to create
         return Filter::Pointer();
diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h
index a2921ee47d..de58dc3647 100644
--- a/libraries/controllers/src/controllers/Filter.h
+++ b/libraries/controllers/src/controllers/Filter.h
@@ -12,6 +12,10 @@
 
 #include <list>
 #include <memory>
+#include <numeric>
+#include <functional>
+
+#include <QtCore/QEasingCurve>
 
 class QJsonObject;
 
@@ -20,14 +24,155 @@ namespace Controllers {
     // Encapsulates part of a filter chain
     class Filter {
     public:
-        virtual float apply(float newValue, float oldValue) = 0;
+        virtual float apply(float value) const = 0;
 
         using Pointer = std::shared_ptr<Filter>;
         using List = std::list<Pointer>;
+        using Lambda = std::function<float(float)>;
 
         static Filter::Pointer parse(const QJsonObject& json);
     };
 
+
+    class LambdaFilter : public Filter {
+    public:
+        LambdaFilter(Lambda f) : _function(f) {};
+
+        virtual float apply(float value) const {
+            return _function(value);
+        }
+
+    private:
+        Lambda _function;
+    };
+
+    class ScriptFilter : public Filter {
+    public:
+
+    };
+
+    //class ScaleFilter : public Filter {
+    //public:
+    //    ScaleFilter(float scale);
+    //    virtual float apply(float scale) const override {
+    //        return value * _scale;
+    //    }
+
+    //private:
+    //    const float _scale;
+    //};
+
+    //class AbstractRangeFilter : public Filter {
+    //public:
+    //    RangeFilter(float min, float max) : _min(min), _max(max) {}
+
+    //protected:
+    //    const float _min;
+    //    const float _max;
+    //};
+
+    ///*
+    //* Constrains will emit the input value on the first call, and every *interval* seconds, otherwise returns 0
+    //*/
+    //class PulseFilter : public Filter {
+    //public:
+    //    PulseFilter(float interval);
+    //    virtual float apply(float value) const override;
+
+    //private:
+    //    float _lastEmitTime{ -std::numeric_limits<float>::max() };
+    //    const float _interval;
+    //};
+
+    ////class DeadzoneFilter : public AbstractRangeFilter {
+    ////public:
+    ////    DeadzoneFilter(float min, float max = 1.0f);
+    ////    virtual float apply(float newValue, float oldValue) override;
+    ////};
+
+    //class EasingFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override;
+
+    //private:
+    //    QEasingCurve _curve;
+    //};
+
+    //// GLSL style filters
+    //class StepFilter : public Filter {
+    //public:
+    //    StepFilter(float edge) : _edge(edge) {};
+    //    virtual float apply(float value) const override;
+
+    //private:
+    //    const float _edge;
+    //};
+
+    //class PowFilter : public Filter {
+    //public:
+    //    PowFilter(float exponent) : _exponent(exponent) {};
+    //    virtual float apply(float value) const override;
+
+    //private:
+    //    const float _exponent;
+    //};
+
+    //class ClampFilter : public RangeFilter {
+    //public:
+    //    ClampFilter(float min = 0.0, float max = 1.0) : RangeFilter(min, max) {};
+    //    virtual float apply(float value) const override;
+    //};
+
+    //class AbsFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override;
+    //};
+
+    //class SignFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override;
+    //};
+
+    //class FloorFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override {
+    //        return floor(newValue);
+    //    }
+    //};
+
+    //class CeilFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override {
+    //        return ceil(newValue);
+    //    }
+    //};
+
+    //class FractFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override {
+    //        return fract(newValue);
+    //    }
+    //};
+
+    //class MinFilter : public Filter {
+    //public:
+    //    MinFilter(float mine) : _min(min) {};
+
+    //    virtual float apply(float value) const override {
+    //        return glm::min(_min, newValue);
+    //    }
+
+    //private:
+    //    const float _min;
+    //};
+
+    //class MaxFilter : public Filter {
+    //public:
+    //    MaxFilter(float max) : _max(max) {};
+    //    virtual float apply(float newValue, float oldValue) override;
+    //private:
+    //    const float _max;
+    //};
 }
 
 #endif
diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/Mapping.cpp
index 3fdbd71d1c..dd1ec14d1e 100644
--- a/libraries/controllers/src/controllers/Mapping.cpp
+++ b/libraries/controllers/src/controllers/Mapping.cpp
@@ -2,3 +2,62 @@
 
 namespace Controllers {
 }
+
+//    class MappingsStack {
+//        std::list<Mapping> _stack;
+//        ValueMap _lastValues;
+//
+//        void update() {
+//            EndpointList hardwareInputs = getHardwareEndpoints();
+//            ValueMap currentValues;
+//
+//            for (auto input : hardwareInputs) {
+//                currentValues[input] = input->value();
+//            }
+//
+//            // Now process the current values for each level of the stack
+//            for (auto& mapping : _stack) {
+//                update(mapping, currentValues);
+//            }
+//
+//            _lastValues = currentValues;
+//        }
+//
+//        void update(Mapping& mapping, ValueMap& values) {
+//            ValueMap updates;
+//            EndpointList consumedEndpoints;
+//            for (const auto& entry : values) {
+//                Endpoint* endpoint = entry.first;
+//                if (!mapping._channelMappings.count(endpoint)) {
+//                    continue;
+//                }
+//
+//                const Mapping::List& routes = mapping._channelMappings[endpoint];
+//                consumedEndpoints.push_back(endpoint);
+//                for (const auto& route : routes) {
+//                    float lastValue = 0;
+//                    if (mapping._lastValues.count(endpoint)) {
+//                        lastValue = mapping._lastValues[endpoint];
+//                    }
+//                    float value = entry.second;
+//                    for (const auto& filter : route._filters) {
+//                        value = filter->apply(value, lastValue);
+//                    }
+//                    updates[route._destination] = value;
+//                }
+//            }
+//
+//            // Update the last seen values
+//            mapping._lastValues = values;
+//
+//            // Remove all the consumed inputs
+//            for (auto endpoint : consumedEndpoints) {
+//                values.erase(endpoint);
+//            }
+//
+//            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
+//            for (const auto& entry : updates) {
+//                values[entry.first] = entry.second;
+//            }
+//        }
+//    };
diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h
index 6f843a7b23..4154701478 100644
--- a/libraries/controllers/src/controllers/Mapping.h
+++ b/libraries/controllers/src/controllers/Mapping.h
@@ -1,3 +1,15 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Mapping_h
+#define hifi_Controllers_Mapping_h
+
 #include <map>
 
 #include <QtCore/QString>
@@ -14,6 +26,8 @@ namespace Controllers {
     public:
         // Map of source channels to route lists
         using Map = std::map<Endpoint::Pointer, Route::List>;
+        using Pointer = std::shared_ptr<Mapping>;
+        using List = std::list<Pointer>;
 
         Map _channelMappings;
         ValueMap _lastValues;
@@ -22,62 +36,6 @@ namespace Controllers {
         QString serialize();
     };
 
-//    class MappingsStack {
-//        std::list<Mapping> _stack;
-//        ValueMap _lastValues;
-//
-//        void update() {
-//            EndpointList hardwareInputs = getHardwareEndpoints();
-//            ValueMap currentValues;
-//
-//            for (auto input : hardwareInputs) {
-//                currentValues[input] = input->value();
-//            }
-//
-//            // Now process the current values for each level of the stack
-//            for (auto& mapping : _stack) {
-//                update(mapping, currentValues);
-//            }
-//
-//            _lastValues = currentValues;
-//        }
-//
-//        void update(Mapping& mapping, ValueMap& values) {
-//            ValueMap updates;
-//            EndpointList consumedEndpoints;
-//            for (const auto& entry : values) {
-//                Endpoint* endpoint = entry.first;
-//                if (!mapping._channelMappings.count(endpoint)) {
-//                    continue;
-//                }
-//
-//                const Mapping::List& routes = mapping._channelMappings[endpoint];
-//                consumedEndpoints.push_back(endpoint);
-//                for (const auto& route : routes) {
-//                    float lastValue = 0;
-//                    if (mapping._lastValues.count(endpoint)) {
-//                        lastValue = mapping._lastValues[endpoint];
-//                    }
-//                    float value = entry.second;
-//                    for (const auto& filter : route._filters) {
-//                        value = filter->apply(value, lastValue);
-//                    }
-//                    updates[route._destination] = value;
-//                }
-//            }
-//
-//            // Update the last seen values
-//            mapping._lastValues = values;
-//
-//            // Remove all the consumed inputs
-//            for (auto endpoint : consumedEndpoints) {
-//                values.erase(endpoint);
-//            }
-//
-//            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
-//            for (const auto& entry : updates) {
-//                values[entry.first] = entry.second;
-//            }
-//        }
-//    };
 }
+
+#endif
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
new file mode 100644
index 0000000000..b8d5c851f5
--- /dev/null
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
@@ -0,0 +1,125 @@
+#include "NewControllerScriptingInterface.h"
+
+#include <mutex>
+
+#include <QtScript/QScriptValue>
+
+#include "GLMHelpers.h"
+
+#include "impl/MappingBuilderProxy.h"
+
+namespace Controllers {
+
+QObject* NewControllerScriptingInterface::newMapping() {
+    qDebug() << "Creating new Mapping proxy";
+    return new MappingBuilderProxy(std::make_shared<Mapping>());
+}
+
+float NewControllerScriptingInterface::getValue(const QScriptValue& source) {
+    return 0;
+}
+
+} // namespace controllers
+
+
+
+
+//    class MappingsStack {
+//        std::list<Mapping> _stack;
+//        ValueMap _lastValues;
+//
+//        void update() {
+//            EndpointList hardwareInputs = getHardwareEndpoints();
+//            ValueMap currentValues;
+//
+//            for (auto input : hardwareInputs) {
+//                currentValues[input] = input->value();
+//            }
+//
+//            // Now process the current values for each level of the stack
+//            for (auto& mapping : _stack) {
+//                update(mapping, currentValues);
+//            }
+//
+//            _lastValues = currentValues;
+//        }
+//
+//        void update(Mapping& mapping, ValueMap& values) {
+//            ValueMap updates;
+//            EndpointList consumedEndpoints;
+//            for (const auto& entry : values) {
+//                Endpoint* endpoint = entry.first;
+//                if (!mapping._channelMappings.count(endpoint)) {
+//                    continue;
+//                }
+//
+//                const Mapping::List& routes = mapping._channelMappings[endpoint];
+//                consumedEndpoints.push_back(endpoint);
+//                for (const auto& route : routes) {
+//                    float lastValue = 0;
+//                    if (mapping._lastValues.count(endpoint)) {
+//                        lastValue = mapping._lastValues[endpoint];
+//                    }
+//                    float value = entry.second;
+//                    for (const auto& filter : route._filters) {
+//                        value = filter->apply(value, lastValue);
+//                    }
+//                    updates[route._destination] = value;
+//                }
+//            }
+//
+//            // Update the last seen values
+//            mapping._lastValues = values;
+//
+//            // Remove all the consumed inputs
+//            for (auto endpoint : consumedEndpoints) {
+//                values.erase(endpoint);
+//            }
+//
+//            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
+//            for (const auto& entry : updates) {
+//                values[entry.first] = entry.second;
+//            }
+//        }
+//    };
+//var mapping = Controller.newMapping();
+//mapping.map(hydra.LeftButton0, actions.ContextMenu);
+//mapping.map(hydra.LeftButton0).to(xbox.RT);
+//mapping.from(xbox.RT).constrainToBoolean().invert().to(actions.Foo)
+//    mapping.from(xbox.RY).invert().deadZone(0.2).to(actions.Pitch)
+//    mapping.from(xbox.RY).filter(function(newValue, oldValue) {
+//    return newValue * 2.0
+//}).to(actions.Pitch)
+
+//mapping.from(function(time) {
+//        return Math.cos(time);
+//    }).to(actions.Pitch);
+
+//    mapping.mapFromFunction(function() {
+//        return x;
+//    }, actions.ContextMenu);
+
+//    mapping.from(xbox.LY).clamp(0, 1).to(actions.Forward);
+//    mapping.from(xbox.LY).clamp(-1, 0).to(actions.Backward);
+//    mapping.from(xbox.RY).clamp(0, 1).to(actions.Forward);
+//    mapping.from(xbox.RS).to();
+//    mapping.from(xbox.ALL).to();
+
+//    mapping.from(xbox.RY).to(function(...) { ... });
+//    mapping.from(xbox.RY).pass();
+
+//    mapping.suppress() ≅ mapping.to(null)
+//        mapping.pass() ≅ mapping.to(fromControl)
+
+//        mapping.from(keyboard.RightParen).invert().to(actions.Yaw)
+//        mapping.from(keyboard.LeftParen).to(actions.Yaw)
+
+//        mapping.from(hydra.LX).pulse(MIN_SNAP_TIME, 3.0).to(Actions.Yaw)
+
+//        mapping.from(keyboard.LeftParen).pulse(MIN_SNAP_TIME).to(Actions.Yaw)
+//        // Enable and disable as above
+
+//        mappingSnap.from(hydra.LX).to(function(newValue, oldValue) {
+//        timeSinceLastYaw += deltaTime
+
+#include "NewControllerScriptingInterface.moc"
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
new file mode 100644
index 0000000000..8730c2da89
--- /dev/null
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
@@ -0,0 +1,31 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_NewControllerScriptingInterface_h
+#define hifi_Controllers_NewControllerScriptingInterface_h
+
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+
+#include "Mapping.h"
+
+class QScriptValue;
+
+namespace Controllers {
+    class NewControllerScriptingInterface : public QObject {
+        Q_OBJECT
+    
+    public:
+        Q_INVOKABLE QObject* newMapping();
+        Q_INVOKABLE float getValue(const QScriptValue& source);
+    };
+}
+
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
new file mode 100644
index 0000000000..e16fa511db
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -0,0 +1,33 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "MappingBuilderProxy.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QDebug>
+
+#include "RouteBuilderProxy.h"
+
+namespace Controllers {
+
+QObject* MappingBuilderProxy::from(const QString& source) {
+    qDebug() << "Creating new Route builder proxy from " << source;
+    auto route = Route::Pointer(new Route());
+    route->_source = endpointFor(source);
+    return new RouteBuilderProxy(this, route);
+}
+
+Endpoint::Pointer MappingBuilderProxy::endpointFor(const QString& endpoint) {
+    static QHash<QString, Endpoint::Pointer> ENDPOINTS;
+    if (!ENDPOINTS.contains(endpoint)) {
+        ENDPOINTS[endpoint] = std::make_shared<Endpoint>();
+    }
+    return ENDPOINTS[endpoint];
+}
+
+}
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
new file mode 100644
index 0000000000..6dac38b21e
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -0,0 +1,35 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#pragma once
+#ifndef hifi_Controllers_Impl_MappingBuilderProxy_h
+#define hifi_Controllers_Impl_MappingBuilderProxy_h
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+#include "../Mapping.h"
+
+namespace Controllers {
+
+class MappingBuilderProxy : public QObject {
+    Q_OBJECT
+public:
+    MappingBuilderProxy(Mapping::Pointer mapping)
+        : _mapping(mapping) { }
+
+    Q_INVOKABLE QObject* from(const QString& fromEndpoint);
+
+protected:
+    friend class RouteBuilderProxy;
+    Endpoint::Pointer endpointFor(const QString& endpoint);
+    Mapping::Pointer _mapping;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
new file mode 100644
index 0000000000..d1659573e4
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -0,0 +1,80 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#include "RouteBuilderProxy.h"
+
+#include <QtCore/QDebug>
+
+#include <GLMHelpers.h>
+
+#include "MappingBuilderProxy.h"
+
+namespace Controllers {
+
+void RouteBuilderProxy::to(const QString& destination) {
+    qDebug() << "Completed route: " << destination;
+    auto sourceEndpoint = _route->_source;
+    auto& mapping = _parent->_mapping;
+    mapping->_channelMappings[sourceEndpoint].push_back(_route);
+    deleteLater();
+}
+
+QObject* RouteBuilderProxy::clamp(float min, float max) {
+    addFilter([=](float value) {
+        return glm::clamp(value, min, max);
+    });
+    return this;
+}
+
+QObject* RouteBuilderProxy::scale(float multiplier) {
+    addFilter([=](float value) {
+        return value * multiplier;
+    });
+    return this;
+}
+
+QObject* RouteBuilderProxy::invert() {
+    return scale(-1.0f);
+}
+
+QObject* RouteBuilderProxy::deadZone(float min) {
+    assert(min < 1.0f);
+    float scale = 1.0f / (1.0f - min);
+    addFilter([=](float value) {
+        if (value < min) {
+            return 0.0f;
+        }
+        return (value - min) * scale;
+    });
+
+    return this;
+}
+
+QObject* RouteBuilderProxy::constrainToInteger() {
+    addFilter([=](float value) {
+        return glm::sign(value);
+    });
+    return this;
+}
+
+QObject* RouteBuilderProxy::constrainToPositiveInteger() {
+    addFilter([=](float value) {
+        return (value <= 0.0f) ? 0.0f : 1.0f;
+    });
+    return this;
+}
+
+void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
+    Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda);
+    addFilter(filterPointer);
+}
+
+void RouteBuilderProxy::addFilter(Filter::Pointer filter) {
+    _route->_filters.push_back(filter);
+}
+
+}
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
new file mode 100644
index 0000000000..516712b969
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -0,0 +1,42 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#pragma once
+#ifndef hifi_Controllers_Impl_RouteBuilderProxy_h
+#define hifi_Controllers_Impl_RouteBuilderProxy_h
+
+#include <QtCore/QObject>
+#include "../Filter.h"
+#include "../Route.h"
+
+namespace Controllers {
+
+class MappingBuilderProxy;
+
+class RouteBuilderProxy : public QObject {
+        Q_OBJECT
+    public:
+        RouteBuilderProxy(MappingBuilderProxy* parent, Route::Pointer route)
+            : _parent(parent), _route(route) { }
+
+        Q_INVOKABLE void to(const QString& destination);
+        Q_INVOKABLE QObject* clamp(float min, float max);
+        Q_INVOKABLE QObject* scale(float multiplier);
+        Q_INVOKABLE QObject* invert();
+        Q_INVOKABLE QObject* deadZone(float min);
+        Q_INVOKABLE QObject* constrainToInteger();
+        Q_INVOKABLE QObject* constrainToPositiveInteger();
+
+    private:
+        void addFilter(Filter::Lambda lambda);
+        void addFilter(Filter::Pointer filter);
+        Route::Pointer _route;
+        MappingBuilderProxy* _parent;
+    };
+
+}
+#endif
diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp
index f78c8c47e0..ccb6533dd7 100644
--- a/libraries/shared/src/SharedUtil.cpp
+++ b/libraries/shared/src/SharedUtil.cpp
@@ -15,6 +15,7 @@
 #include <cstring>
 #include <cctype>
 #include <time.h>
+#include <mutex>
 
 #ifdef _WIN32
 #include <windows.h>
@@ -39,30 +40,29 @@ void usecTimestampNowForceClockSkew(int clockSkew) {
     ::usecTimestampNowAdjust = clockSkew;
 }
 
+static qint64 TIME_REFERENCE = 0; // in usec
+static std::once_flag usecTimestampNowIsInitialized;
+static QElapsedTimer timestampTimer;
+
 quint64 usecTimestampNow(bool wantDebug) {
-    static bool usecTimestampNowIsInitialized = false;
-    static qint64 TIME_REFERENCE = 0; // in usec
-    static QElapsedTimer timestampTimer;
-    
-    if (!usecTimestampNowIsInitialized) {
-        TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * 1000; // ms to usec
+    std::call_once(usecTimestampNowIsInitialized, [&] {
+        TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * USECS_PER_MSEC; // ms to usec
         timestampTimer.start();
-        usecTimestampNowIsInitialized = true;
-    }
+    });
     
     quint64 now;
     quint64 nsecsElapsed = timestampTimer.nsecsElapsed();
-    quint64 usecsElapsed = nsecsElapsed / 1000;  // nsec to usec
+    quint64 usecsElapsed = nsecsElapsed / NSECS_PER_USEC;  // nsec to usec
     
     // QElapsedTimer may not advance if the CPU has gone to sleep. In which case it
     // will begin to deviate from real time. We detect that here, and reset if necessary
     quint64 msecsCurrentTime = QDateTime::currentMSecsSinceEpoch();
-    quint64 msecsEstimate = (TIME_REFERENCE + usecsElapsed) / 1000; // usecs to msecs
+    quint64 msecsEstimate = (TIME_REFERENCE + usecsElapsed) / USECS_PER_MSEC; // usecs to msecs
     int possibleSkew = msecsEstimate - msecsCurrentTime;
-    const int TOLERANCE = 10000; // up to 10 seconds of skew is tolerated
+    const int TOLERANCE = 10 * MSECS_PER_SECOND; // up to 10 seconds of skew is tolerated
     if (abs(possibleSkew) > TOLERANCE) {
         // reset our TIME_REFERENCE and timer
-        TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * 1000; // ms to usec
+        TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * USECS_PER_MSEC; // ms to usec
         timestampTimer.restart();
         now = TIME_REFERENCE + ::usecTimestampNowAdjust;
 
@@ -118,6 +118,13 @@ quint64 usecTimestampNow(bool wantDebug) {
     return now;
 }
 
+float secTimestampNow() {
+    static const auto START_TIME = usecTimestampNow();
+    const auto nowUsecs = usecTimestampNow();
+    const auto nowMsecs = nowUsecs / USECS_PER_MSEC;
+    return (float)nowMsecs / MSECS_PER_SECOND;
+}
+
 float randFloat() {
     return (rand() % 10000)/10000.0f;
 }
diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h
index 4967778cb4..98bc95cf6f 100644
--- a/libraries/shared/src/SharedUtil.h
+++ b/libraries/shared/src/SharedUtil.h
@@ -65,9 +65,14 @@ inline bool operator!=(const xColor& lhs, const xColor& rhs)
 // Use a custom User-Agent to avoid ModSecurity filtering, e.g. by hosting providers.
 const QByteArray HIGH_FIDELITY_USER_AGENT = "Mozilla/5.0 (HighFidelityInterface)";
 
+// Equivalent to time_t but in usecs instead of secs
 quint64 usecTimestampNow(bool wantDebug = false);
 void usecTimestampNowForceClockSkew(int clockSkew);
 
+// Number of seconds expressed since the first call to this function, expressed as a float
+// Maximum accuracy in msecs
+float ssecTimestampNow();
+
 float randFloat();
 int randIntInRange (int min, int max);
 float randFloatInRange (float min,float max);
diff --git a/tests/controllers/qml/main.qml b/tests/controllers/qml/main.qml
new file mode 100644
index 0000000000..9f660e5d35
--- /dev/null
+++ b/tests/controllers/qml/main.qml
@@ -0,0 +1,43 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+import com.highfidelity.test 1.0
+
+ApplicationWindow {
+    id: window
+    visible: true
+
+    AppHook {
+        
+    }
+    
+//    NewControllers {
+//        id: newControllers
+//    }
+    
+    Rectangle {
+        id: page
+        width: 320; height: 480
+        color: "lightgray"
+        Text {
+            id: helloText
+            text: "Hello world!"
+            y: 30
+            anchors.horizontalCenter: page.horizontalCenter
+            font.pointSize: 24; font.bold: true
+        }
+
+        MouseArea {
+            anchors.fill: parent
+            onClicked: {
+                var newMapping = NewControllers.newMapping();
+                console.log("Mapping Object " + newMapping);
+                var routeBuilder = newMapping.from("Hello");
+                console.log("Route Builder " + routeBuilder);
+                routeBuilder.clamp(0, 1).clamp(0, 1).to("Goodbye");
+            }
+        }
+    }
+
+}
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index 88d29214d3..8311b26dab 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -27,12 +27,73 @@
 #include <QtGui/QGuiApplication>
 #include <QtGui/QImage>
 
+#include <QtQuick/QQuickItem>
+#include <QtQml/QQmlApplicationEngine>
+#include <QtQml/QQmlContext>
+
+#include <controllers/NewControllerScriptingInterface.h>
+
+const QString& getQmlDir() {
+    static QString dir;
+    if (dir.isEmpty()) {
+        QDir path(__FILE__);
+        path.cdUp();
+        dir = path.cleanPath(path.absoluteFilePath("../qml/")) + "/";
+        qDebug() << "Qml Path: " << dir;
+    }
+    return dir;
+}
+
+class AppHook : public QQuickItem {
+    Q_OBJECT
+
+public:
+    AppHook() {
+        qDebug() << "Hook Created";
+    }
+};
+
+using namespace Controllers;
+
 int main(int argc, char** argv) {    
+    // Register our component type with QML.
+    qmlRegisterType<AppHook>("com.highfidelity.test", 1, 0, "AppHook");
+    //qmlRegisterType<NewControllerScriptingInterface>("com.highfidelity.test", 1, 0, "NewControllers");
     QGuiApplication app(argc, argv);
-    QWindow window;
+    QQmlApplicationEngine engine(getQmlDir() + "main.qml");
+    engine.rootContext()->setContextProperty("NewControllers", new NewControllerScriptingInterface());
     app.exec();
     return 0;
 }
 
+
+
+//QQmlEngine engine;
+//QQmlComponent *component = new QQmlComponent(&engine);
+//
+//QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
+//
+//component->loadUrl(QUrl("main.qml"));
+//
+//if (!component->isReady()) {
+//    qWarning("%s", qPrintable(component->errorString()));
+//    return -1;
+//}
+//
+//QObject *topLevel = component->create();
+//QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
+//
+//QSurfaceFormat surfaceFormat = window->requestedFormat();
+//window->setFormat(surfaceFormat);
+//window->show();
+//
+//rc = app.exec();
+//
+//delete component;
+//return rc;
+//}
+
+
+
 #include "main.moc"
 

From 80c95cd8eb79a5dacd32e2730ed7ac251d49f117 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sat, 10 Oct 2015 16:07:26 -0700
Subject: [PATCH 012/301] Fixing access to second based timestamp

---
 libraries/shared/src/SharedUtil.cpp | 2 +-
 libraries/shared/src/SharedUtil.h   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp
index ccb6533dd7..145ec4ec37 100644
--- a/libraries/shared/src/SharedUtil.cpp
+++ b/libraries/shared/src/SharedUtil.cpp
@@ -120,7 +120,7 @@ quint64 usecTimestampNow(bool wantDebug) {
 
 float secTimestampNow() {
     static const auto START_TIME = usecTimestampNow();
-    const auto nowUsecs = usecTimestampNow();
+    const auto nowUsecs = usecTimestampNow() - START_TIME;
     const auto nowMsecs = nowUsecs / USECS_PER_MSEC;
     return (float)nowMsecs / MSECS_PER_SECOND;
 }
diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h
index 98bc95cf6f..cd4f734d40 100644
--- a/libraries/shared/src/SharedUtil.h
+++ b/libraries/shared/src/SharedUtil.h
@@ -71,7 +71,7 @@ void usecTimestampNowForceClockSkew(int clockSkew);
 
 // Number of seconds expressed since the first call to this function, expressed as a float
 // Maximum accuracy in msecs
-float ssecTimestampNow();
+float secTimestampNow();
 
 float randFloat();
 int randIntInRange (int min, int max);

From 14f33258aecf22a82ac2fb673d52c0d6152da5de Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sat, 10 Oct 2015 16:08:44 -0700
Subject: [PATCH 013/301] Working on test code, new controller interface

---
 .../NewControllerScriptingInterface.cpp       |  33 +++--
 .../NewControllerScriptingInterface.h         |   3 +-
 tests/controllers/CMakeLists.txt              |  12 +-
 tests/controllers/qml/content.qml             | 137 ++++++++++++++++++
 tests/controllers/qml/main.qml                |  35 +----
 tests/controllers/src/main.cpp                |  71 ++++++++-
 6 files changed, 243 insertions(+), 48 deletions(-)
 create mode 100644 tests/controllers/qml/content.qml

diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
index b8d5c851f5..bc915ba1a6 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
@@ -1,23 +1,36 @@
 #include "NewControllerScriptingInterface.h"
 
 #include <mutex>
+#include <set>
 
-#include <QtScript/QScriptValue>
-
-#include "GLMHelpers.h"
+#include <GLMHelpers.h>
+#include <DependencyManager.h>
+#include <input-plugins/UserInputMapper.h>
 
 #include "impl/MappingBuilderProxy.h"
 
 namespace Controllers {
+    void NewControllerScriptingInterface::update() {
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        static float last = secTimestampNow();
+        float now = secTimestampNow();
+        userInputMapper->update(now - last);
+        last = now;
+    }
 
-QObject* NewControllerScriptingInterface::newMapping() {
-    qDebug() << "Creating new Mapping proxy";
-    return new MappingBuilderProxy(std::make_shared<Mapping>());
-}
+    QObject* NewControllerScriptingInterface::newMapping() {
+        qDebug() << "Creating new Mapping proxy";
+        return new MappingBuilderProxy(std::make_shared<Mapping>());
+    }
 
-float NewControllerScriptingInterface::getValue(const QScriptValue& source) {
-    return 0;
-}
+    float NewControllerScriptingInterface::getValue(const int& source) {
+        //UserInputMapper::Input input; input._id = source;
+        //auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        //auto deviceProxy = userInputMapper->getDeviceProxy(input);
+        //return deviceProxy->getButton(input, 0) ? 1.0 : 0.0;
+
+        return (sin(secTimestampNow()) + 1.0f) / 2.0f;
+    }
 
 } // namespace controllers
 
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
index 8730c2da89..c4c42a2245 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
@@ -22,8 +22,9 @@ namespace Controllers {
         Q_OBJECT
     
     public:
+        Q_INVOKABLE void update();
         Q_INVOKABLE QObject* newMapping();
-        Q_INVOKABLE float getValue(const QScriptValue& source);
+        Q_INVOKABLE float getValue(const int& source);
     };
 }
 
diff --git a/tests/controllers/CMakeLists.txt b/tests/controllers/CMakeLists.txt
index 4e31881141..34ab4c2eba 100644
--- a/tests/controllers/CMakeLists.txt
+++ b/tests/controllers/CMakeLists.txt
@@ -1,13 +1,19 @@
 
 set(TARGET_NAME controllers-test)
  
-AUTOSCRIBE_SHADER_LIB(gpu model render-utils )
-
 # This is not a testcase -- just set it up as a regular hifi project
 setup_hifi_project(Script)
 set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
 
 # link in the shared libraries
-link_hifi_libraries(shared script-engine input-plugins controllers)
+link_hifi_libraries(shared script-engine plugins input-plugins display-plugins controllers)
+
+
+if (WIN32)
+    add_dependency_external_projects(OpenVR)
+    find_package(OpenVR REQUIRED)
+    target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
+    target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
+endif()
 
 copy_dlls_beside_windows_executable()
\ No newline at end of file
diff --git a/tests/controllers/qml/content.qml b/tests/controllers/qml/content.qml
new file mode 100644
index 0000000000..ac171ac42c
--- /dev/null
+++ b/tests/controllers/qml/content.qml
@@ -0,0 +1,137 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+Rectangle {
+    id: root
+    implicitHeight: column1.height + 24
+    implicitWidth: column1.width + 24
+    color: "lightgray"
+
+    property real itemSize: 128
+
+    Component {
+        id: graphTemplate
+        Item {
+            implicitHeight: canvas.height + 2 + text.height
+            implicitWidth: canvas.width
+            property string text: loadText
+
+            Canvas {
+               id: canvas
+               width: root.itemSize; height: root.itemSize;
+               antialiasing: false
+               property int controlId: control
+               property real value: 0.0
+               property int drawWidth: 1
+
+               Timer {
+                   interval: 50; running: true; repeat: true
+                   onTriggered: {
+                       parent.value = NewControllers.getValue(canvas.controlId)
+                       parent.requestPaint();
+                   }
+               }
+
+               onPaint: {
+                   var ctx = canvas.getContext('2d');
+                   ctx.save();
+
+                   var image = ctx.getImageData(0, 0, canvas.width, canvas.height);
+                   ctx.clearRect(0, 0, canvas.width, canvas.height);
+                   ctx.drawImage(image, -drawWidth, 0, canvas.width, canvas.height)
+                   ctx.fillStyle = 'green'
+                   // draw a filles rectangle
+                   var height = canvas.height * canvas.value
+                   ctx.fillRect(canvas.width - drawWidth, canvas.height - height,
+                                drawWidth, height)
+                   ctx.restore()
+               }
+            }
+
+            Text {
+                id: text
+                text: parent.text
+                anchors.topMargin: 2
+                anchors.horizontalCenter: canvas.horizontalCenter
+                anchors.top: canvas.bottom
+                font.pointSize: 12;
+            }
+
+        }
+    }
+
+    Column {
+        id: column1
+        x: 12; y: 12
+        spacing: 24
+        Row {
+            spacing: 16
+            Loader {
+                sourceComponent: graphTemplate;
+                property string loadText: "Key Left"
+                property int control: ControllerIds.Hardware.Keyboard2.Left
+            }
+            Loader {
+                sourceComponent: graphTemplate;
+                property string loadText: "DPad Up"
+                property int control: ControllerIds.Hardware.X360Controller1.DPadUp
+            }
+            /*
+            Loader {
+                sourceComponent: graphTemplate;
+                property string loadText: "Yaw Left"
+                property int control: ControllerIds.Actions.YAW_LEFT
+            }
+            Loader {
+                sourceComponent: graphTemplate;
+                property string loadText: "Yaw Left"
+                property int control: ControllerIds.Actions.YAW_LEFT
+            }
+*/
+
+//            Loader { sourceComponent: graphTemplate; }
+//            Loader { sourceComponent: graphTemplate; }
+//            Loader { sourceComponent: graphTemplate; }
+        }
+        /*
+        Row {
+            spacing: 16
+            Loader { sourceComponent: graphTemplate; }
+            Loader { sourceComponent: graphTemplate; }
+            Loader { sourceComponent: graphTemplate; }
+            Loader { sourceComponent: graphTemplate; }
+        }
+        Row {
+            spacing: 16
+            Loader { sourceComponent: graphTemplate; }
+            Loader { sourceComponent: graphTemplate; }
+            Loader { sourceComponent: graphTemplate; }
+            Loader { sourceComponent: graphTemplate; }
+        }
+        */
+
+
+        Button {
+            text: "Go!"
+            onClicked: {
+                //
+
+//                var newMapping = NewControllers.newMapping();
+//                console.log("Mapping Object " + newMapping);
+//                var routeBuilder = newMapping.from("Hello");
+//                console.log("Route Builder " + routeBuilder);
+//                routeBuilder.clamp(0, 1).clamp(0, 1).to("Goodbye");
+            }
+        }
+
+        Timer {
+            interval: 50; running: true; repeat: true
+            onTriggered: {
+                NewControllers.update();
+            }
+        }
+
+    }
+}
diff --git a/tests/controllers/qml/main.qml b/tests/controllers/qml/main.qml
index 9f660e5d35..5ed68cc1fb 100644
--- a/tests/controllers/qml/main.qml
+++ b/tests/controllers/qml/main.qml
@@ -2,42 +2,13 @@ import QtQuick 2.1
 import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
-import com.highfidelity.test 1.0
 
 ApplicationWindow {
     id: window
     visible: true
 
-    AppHook {
-        
+    Loader {
+        id: pageLoader
+        source: "content.qml"
     }
-    
-//    NewControllers {
-//        id: newControllers
-//    }
-    
-    Rectangle {
-        id: page
-        width: 320; height: 480
-        color: "lightgray"
-        Text {
-            id: helloText
-            text: "Hello world!"
-            y: 30
-            anchors.horizontalCenter: page.horizontalCenter
-            font.pointSize: 24; font.bold: true
-        }
-
-        MouseArea {
-            anchors.fill: parent
-            onClicked: {
-                var newMapping = NewControllers.newMapping();
-                console.log("Mapping Object " + newMapping);
-                var routeBuilder = newMapping.from("Hello");
-                console.log("Route Builder " + routeBuilder);
-                routeBuilder.clamp(0, 1).clamp(0, 1).to("Goodbye");
-            }
-        }
-    }
-
 }
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index 8311b26dab..9840038521 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -11,6 +11,8 @@
 #include <unordered_map>
 #include <memory>
 #include <cstdio>
+#include <mutex>
+#include <set>
 
 #include <glm/glm.hpp>
 #include <glm/gtc/matrix_transform.hpp>
@@ -21,6 +23,7 @@
 #include <QtCore/QElapsedTimer>
 #include <QtCore/QFile>
 #include <QtCore/QLoggingCategory>
+#include <QtCore/QRegularExpression>
 
 #include <QtGui/QResizeEvent>
 #include <QtGui/QWindow>
@@ -32,6 +35,11 @@
 #include <QtQml/QQmlContext>
 
 #include <controllers/NewControllerScriptingInterface.h>
+#include <DependencyManager.h>
+#include <plugins/PluginManager.h>
+#include <input-plugins/InputPlugin.h>
+#include <input-plugins/KeyboardMouseDevice.h>
+#include <input-plugins/UserInputMapper.h>
 
 const QString& getQmlDir() {
     static QString dir;
@@ -55,13 +63,72 @@ public:
 
 using namespace Controllers;
 
-int main(int argc, char** argv) {    
+
+QString sanatizeName(const QString& name) {
+    QString cleanName{ name };
+    cleanName.remove(QRegularExpression{ "[\\(\\)\\.\\s]" });
+    return cleanName;
+}
+
+const QVariantMap& getInputMap() {
+    static std::once_flag once;
+    static QVariantMap map;
+    std::call_once(once, [&] {
+        {
+            QVariantMap hardwareMap;
+            // Controller.Hardware.*
+            auto devices = DependencyManager::get<UserInputMapper>()->getDevices();
+            for (const auto& deviceMapping : devices) {
+                auto device = deviceMapping.second.get();
+                auto deviceName = sanatizeName(device->getName());
+                auto deviceInputs = device->getAvailabeInputs();
+                QVariantMap deviceMap;
+                for (const auto& inputMapping : deviceInputs) {
+                    auto input = inputMapping.first;
+                    auto inputName = sanatizeName(inputMapping.second);
+                    deviceMap.insert(inputName, input.getID());
+                }
+                hardwareMap.insert(deviceName, deviceMap);
+            }
+            map.insert("Hardware", hardwareMap);
+        }
+
+        // Controller.Actions.*
+        {
+            QVariantMap actionMap;
+            auto actionNames = DependencyManager::get<UserInputMapper>()->getActionNames();
+            int actionNumber = 0;
+            for (const auto& actionName : actionNames) {
+                actionMap.insert(sanatizeName(actionName), actionNumber++);
+            }
+            map.insert("Actions", actionMap);
+        }
+    });
+    return map;
+}
+
+int main(int argc, char** argv) {
+    DependencyManager::set<UserInputMapper>();
+    PluginManager::getInstance()->getInputPlugins();
+
+    foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
+        QString name = inputPlugin->getName();
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        if (name == KeyboardMouseDevice::NAME) {
+            auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
+            keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
+            keyboardMouseDevice->assignDefaultInputMapping(*userInputMapper);
+        }
+    }
+
     // Register our component type with QML.
     qmlRegisterType<AppHook>("com.highfidelity.test", 1, 0, "AppHook");
     //qmlRegisterType<NewControllerScriptingInterface>("com.highfidelity.test", 1, 0, "NewControllers");
     QGuiApplication app(argc, argv);
-    QQmlApplicationEngine engine(getQmlDir() + "main.qml");
+    QQmlApplicationEngine engine;
     engine.rootContext()->setContextProperty("NewControllers", new NewControllerScriptingInterface());
+    engine.rootContext()->setContextProperty("ControllerIds", getInputMap());
+    engine.load(getQmlDir() + "main.qml");
     app.exec();
     return 0;
 }

From 14f511350d5c3b88408cd48f710188ab2842a8a7 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sat, 10 Oct 2015 22:34:11 -0700
Subject: [PATCH 014/301] Working on refactoring the xbox hardware access and
 wiring up test code

---
 .../controllers/src/controllers/Endpoint.cpp  |  80 +-
 .../controllers/src/controllers/Endpoint.h    |  31 +-
 .../controllers/src/controllers/Filter.cpp    |   2 +-
 .../controllers/src/controllers/Filter.h      |   2 +-
 .../controllers/src/controllers/Logging.cpp   |  11 +
 .../controllers/src/controllers/Logging.h     |  16 +
 .../controllers/src/controllers/Mapping.cpp   |  60 +-
 .../controllers/src/controllers/Mapping.h     |   9 +-
 .../NewControllerScriptingInterface.cpp       | 386 ++++++++--
 .../NewControllerScriptingInterface.h         |  65 +-
 .../controllers/src/controllers/Route.cpp     |   3 +-
 libraries/controllers/src/controllers/Route.h |   2 +-
 .../controllers/impl/MappingBuilderProxy.cpp  |  33 +-
 .../controllers/impl/MappingBuilderProxy.h    |  20 +-
 .../controllers/impl/RouteBuilderProxy.cpp    |  76 +-
 .../src/controllers/impl/RouteBuilderProxy.h  |  24 +-
 .../src/input-plugins/InputPlugin.cpp         |   4 +-
 .../src/input-plugins/Joystick.cpp            | 176 ++---
 .../src/input-plugins/Joystick.h              |  19 +-
 .../src/input-plugins/KeyboardMouseDevice.cpp |   7 +-
 .../src/input-plugins/KeyboardMouseDevice.h   |   7 +-
 .../src/input-plugins/StandardController.cpp  | 157 ++--
 .../src/input-plugins/StandardController.h    |  39 +-
 .../src/input-plugins/StandardControls.h      |  55 ++
 .../src/input-plugins/UserInputMapper.cpp     | 703 +++++++++---------
 .../src/input-plugins/UserInputMapper.h       |  20 +-
 tests/controllers/qml/Xbox.qml                |  99 +++
 tests/controllers/qml/content.qml             | 234 +++---
 .../controllers/qml/controls/AnalogButton.qml |  45 ++
 .../controllers/qml/controls/AnalogStick.qml  |  50 ++
 .../qml/controls/ScrollingGraph.qml           | 104 +++
 .../controllers/qml/controls/ToggleButton.qml |  43 ++
 tests/controllers/qml/xbox/DPad.qml           |  43 ++
 .../controllers/qml/xbox/LeftAnalogStick.qml  |  21 +
 .../controllers/qml/xbox/RightAnalogStick.qml |  21 +
 tests/controllers/qml/xbox/XboxButtons.qml    |  46 ++
 .../qml/xbox/xbox360-controller-md.png        | Bin 0 -> 29588 bytes
 tests/controllers/src/main.cpp                | 274 +++----
 38 files changed, 1815 insertions(+), 1172 deletions(-)
 create mode 100644 libraries/controllers/src/controllers/Logging.cpp
 create mode 100644 libraries/controllers/src/controllers/Logging.h
 create mode 100644 libraries/input-plugins/src/input-plugins/StandardControls.h
 create mode 100644 tests/controllers/qml/Xbox.qml
 create mode 100644 tests/controllers/qml/controls/AnalogButton.qml
 create mode 100644 tests/controllers/qml/controls/AnalogStick.qml
 create mode 100644 tests/controllers/qml/controls/ScrollingGraph.qml
 create mode 100644 tests/controllers/qml/controls/ToggleButton.qml
 create mode 100644 tests/controllers/qml/xbox/DPad.qml
 create mode 100644 tests/controllers/qml/xbox/LeftAnalogStick.qml
 create mode 100644 tests/controllers/qml/xbox/RightAnalogStick.qml
 create mode 100644 tests/controllers/qml/xbox/XboxButtons.qml
 create mode 100644 tests/controllers/qml/xbox/xbox360-controller-md.png

diff --git a/libraries/controllers/src/controllers/Endpoint.cpp b/libraries/controllers/src/controllers/Endpoint.cpp
index dddacc5ae5..3f1d12b9de 100644
--- a/libraries/controllers/src/controllers/Endpoint.cpp
+++ b/libraries/controllers/src/controllers/Endpoint.cpp
@@ -8,84 +8,6 @@
 
 #include "Endpoint.h"
 
-#include <mutex>
-#include <input-plugins/UserInputMapper.h>
+namespace controller {
 
-namespace Controllers {
-
-    // Ex: xbox.RY, xbox.A ....
-    class HardwareEndpoint : public Endpoint {
-    public:
-        virtual float value() override {
-            // ...
-        }
-
-        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
-            // Default does nothing, but in theory this could be something like vibration
-            // mapping.from(xbox.X).to(xbox.Vibrate)
-        }
-    };
-
-    // Ex: Standard.RY, Action.Yaw
-    class VirtualEndpoint : public Endpoint {
-    public:
-        virtual void apply(float newValue) {
-            if (newValue != _lastValue) {
-                _lastValue = newValue;
-            }
-        }
-
-        virtual float value() {
-            return _lastValue;
-        }
-
-        float _lastValue;
-    };
-
-    float currentTime() {
-        return 0;
-    }
-    /*
-    * A function which provides input
-    */
-    class FunctionEndpoint : public Endpoint {
-    public:
-
-        virtual float value() override {
-            float now = currentTime();
-            float delta = now - _lastCalled;
-            float result = _inputFunction.call(_object, QScriptValue(delta)).toNumber();
-            _lastCalled = now;
-            return result;
-        }
-
-        virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
-            if (newValue != oldValue) {
-                //_outputFunction.call(newValue, oldValue, source);
-            }
-        }
-
-        float _lastValue{ NAN };
-        float _lastCalled{ 0 };
-        QScriptValue _outputFunction;
-        QScriptValue _inputFunction;
-        QScriptValue _object;
-    };
-
-
-
-    // FIXME how do we handle dynamic changes in connected hardware?
-    const Endpoint::List& Endpoint::getHardwareEndpoints() {
-        static Endpoint::List ACTIVE_HARDWARE_ENDPOINTS;
-        static std::once_flag once;
-        std::call_once(once, [&] {
-            auto userInputMapper = DependencyManager::get<UserInputMapper>();
-            // TODO populate ACTIVE_HARDWARE with all the connected devices
-            // For each connected device
-            // for each input channel
-            // build a HardwareEndpoint instance around the input channel and add it to the list
-        });
-
-        return ACTIVE_HARDWARE_ENDPOINTS;
-    }
 }
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index 48cdf015fa..bea33517f5 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -12,26 +12,45 @@
 
 #include <list>
 #include <memory>
+#include <functional>
+
+#include <input-plugins/UserInputMapper.h>
 
 class QScriptValue;
 
-namespace Controllers {
+namespace controller {
     /*
     * Encapsulates a particular input / output,
     * i.e. Hydra.Button0, Standard.X, Action.Yaw
     */
     class Endpoint {
     public:
-        virtual float value() { return 0;  } // = 0;
-        virtual void apply(float newValue, float oldValue, const Endpoint& source) {} // = 0;
-
         using Pointer = std::shared_ptr<Endpoint>;
         using List = std::list<Pointer>;
+        using Pair = std::pair<Pointer, Pointer>;
+        using ReadLambda = std::function<float()>;
+        using WriteLambda = std::function<void(float)>;
 
-        static const List& getHardwareEndpoints();
-        static Pointer getEndpoint(const QScriptValue& value);
+        Endpoint(const UserInputMapper::Input& id) : _id(id) {}
+        virtual float value() = 0;
+        virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
+        const UserInputMapper::Input& getId() { return _id;  }
+    protected:
+        UserInputMapper::Input _id;
     };
 
+    class LambdaEndpoint : public Endpoint {
+    public:
+        LambdaEndpoint(ReadLambda readLambda, WriteLambda writeLambda = [](float) {})
+            : Endpoint(UserInputMapper::Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
+
+        virtual float value() override { return _readLambda(); }
+        virtual void apply(float newValue, float oldValue, const Pointer& source) override { _writeLambda(newValue); }
+
+    private:
+        ReadLambda _readLambda;
+        WriteLambda _writeLambda;
+    };
 }
 
 #endif
diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
index e0c6adfcac..17715eceff 100644
--- a/libraries/controllers/src/controllers/Filter.cpp
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -11,7 +11,7 @@
 #include <QtCore/QObject>
 #include <QtScript/QScriptValue>
 
-namespace Controllers {
+namespace controller {
 
     Filter::Pointer Filter::parse(const QJsonObject& json) {
         // FIXME parse the json object and determine the instance type to create
diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h
index de58dc3647..f3978e2c0a 100644
--- a/libraries/controllers/src/controllers/Filter.h
+++ b/libraries/controllers/src/controllers/Filter.h
@@ -19,7 +19,7 @@
 
 class QJsonObject;
 
-namespace Controllers {
+namespace controller {
 
     // Encapsulates part of a filter chain
     class Filter {
diff --git a/libraries/controllers/src/controllers/Logging.cpp b/libraries/controllers/src/controllers/Logging.cpp
new file mode 100644
index 0000000000..ae6b523a45
--- /dev/null
+++ b/libraries/controllers/src/controllers/Logging.cpp
@@ -0,0 +1,11 @@
+//
+//  Created by Bradley Austin Davis 2015/10/11
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Logging.h"
+
+Q_LOGGING_CATEGORY(controllers, "hifi.controllers")
diff --git a/libraries/controllers/src/controllers/Logging.h b/libraries/controllers/src/controllers/Logging.h
new file mode 100644
index 0000000000..d74ddae59f
--- /dev/null
+++ b/libraries/controllers/src/controllers/Logging.h
@@ -0,0 +1,16 @@
+//
+//  Created by Bradley Austin Davis 2015/10/11
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_Controllers_Logging_h
+#define hifi_Controllers_Logging_h
+
+#include <QLoggingCategory>
+
+Q_DECLARE_LOGGING_CATEGORY(controllers)
+
+#endif
diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/Mapping.cpp
index dd1ec14d1e..0063a1d24a 100644
--- a/libraries/controllers/src/controllers/Mapping.cpp
+++ b/libraries/controllers/src/controllers/Mapping.cpp
@@ -1,63 +1,5 @@
 #include "Mapping.h"
 
-namespace Controllers {
+namespace controller {
 }
 
-//    class MappingsStack {
-//        std::list<Mapping> _stack;
-//        ValueMap _lastValues;
-//
-//        void update() {
-//            EndpointList hardwareInputs = getHardwareEndpoints();
-//            ValueMap currentValues;
-//
-//            for (auto input : hardwareInputs) {
-//                currentValues[input] = input->value();
-//            }
-//
-//            // Now process the current values for each level of the stack
-//            for (auto& mapping : _stack) {
-//                update(mapping, currentValues);
-//            }
-//
-//            _lastValues = currentValues;
-//        }
-//
-//        void update(Mapping& mapping, ValueMap& values) {
-//            ValueMap updates;
-//            EndpointList consumedEndpoints;
-//            for (const auto& entry : values) {
-//                Endpoint* endpoint = entry.first;
-//                if (!mapping._channelMappings.count(endpoint)) {
-//                    continue;
-//                }
-//
-//                const Mapping::List& routes = mapping._channelMappings[endpoint];
-//                consumedEndpoints.push_back(endpoint);
-//                for (const auto& route : routes) {
-//                    float lastValue = 0;
-//                    if (mapping._lastValues.count(endpoint)) {
-//                        lastValue = mapping._lastValues[endpoint];
-//                    }
-//                    float value = entry.second;
-//                    for (const auto& filter : route._filters) {
-//                        value = filter->apply(value, lastValue);
-//                    }
-//                    updates[route._destination] = value;
-//                }
-//            }
-//
-//            // Update the last seen values
-//            mapping._lastValues = values;
-//
-//            // Remove all the consumed inputs
-//            for (auto endpoint : consumedEndpoints) {
-//                values.erase(endpoint);
-//            }
-//
-//            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
-//            for (const auto& entry : updates) {
-//                values[entry.first] = entry.second;
-//            }
-//        }
-//    };
diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h
index 4154701478..5b54a1745b 100644
--- a/libraries/controllers/src/controllers/Mapping.h
+++ b/libraries/controllers/src/controllers/Mapping.h
@@ -11,6 +11,7 @@
 #define hifi_Controllers_Mapping_h
 
 #include <map>
+#include <unordered_map>
 
 #include <QtCore/QString>
 
@@ -18,19 +19,15 @@
 #include "Filter.h"
 #include "Route.h"
 
-namespace Controllers {
-
-    using ValueMap = std::map<Endpoint::Pointer, float>;
+namespace controller {
 
     class Mapping {
     public:
         // Map of source channels to route lists
         using Map = std::map<Endpoint::Pointer, Route::List>;
         using Pointer = std::shared_ptr<Mapping>;
-        using List = std::list<Pointer>;
 
         Map _channelMappings;
-        ValueMap _lastValues;
 
         void parse(const QString& json);
         QString serialize();
@@ -38,4 +35,4 @@ namespace Controllers {
 
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
index bc915ba1a6..f5d6276b91 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
@@ -1,100 +1,330 @@
-#include "NewControllerScriptingInterface.h"
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#include "NewControllerScriptingInterface.h"
 
 #include <mutex>
 #include <set>
 
+#include <QtCore/QRegularExpression>
+
 #include <GLMHelpers.h>
 #include <DependencyManager.h>
 #include <input-plugins/UserInputMapper.h>
+#include <input-plugins/InputPlugin.h>
+#include <input-plugins/KeyboardMouseDevice.h>
+#include <plugins/PluginManager.h>
 
 #include "impl/MappingBuilderProxy.h"
+#include "Logging.h"
 
-namespace Controllers {
-    void NewControllerScriptingInterface::update() {
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        static float last = secTimestampNow();
-        float now = secTimestampNow();
-        userInputMapper->update(now - last);
-        last = now;
+static const uint16_t ACTIONS_DEVICE = UserInputMapper::Input::INVALID_DEVICE - (uint16_t)1;
+
+namespace controller {
+
+
+    class VirtualEndpoint : public Endpoint {
+    public:
+        VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input(-1))
+            : Endpoint(id) {
+        }
+
+        virtual float value() override { return _currentValue; }
+        virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; }
+
+    private:
+        float _currentValue{ 0.0f };
+    };
+
+
+    class JSEndpoint : public Endpoint {
+    public:
+        JSEndpoint(const QJSValue& callable) 
+            : Endpoint(UserInputMapper::Input(-1)), _callable(callable) {}
+
+        virtual float value() {
+            float result = (float)_callable.call().toNumber();;
+            return result;
+        }
+
+        virtual void apply(float newValue, float oldValue, const Pointer& source) {
+            _callable.call(QJSValueList({ QJSValue(newValue) }));
+        }
+
+    private:
+        QJSValue _callable;
+    };
+
+    class CompositeEndpoint : public Endpoint, Endpoint::Pair {
+    public:
+        CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
+            : Endpoint(UserInputMapper::Input(-1)), Pair(first, second) { }
+
+        virtual float value() {
+            float result = first->value() * -1.0 + second->value();
+            return result;
+        }
+
+        virtual void apply(float newValue, float oldValue, const Pointer& source) {
+            // Composites are read only
+        }
+
+    private:
+        Endpoint::Pointer _first;
+        Endpoint::Pointer _second;
+    };
+
+    QString sanatizeName(const QString& name) {
+        QString cleanName{ name };
+        cleanName.remove(QRegularExpression{ "[\\(\\)\\.\\s]" });
+        return cleanName;
     }
 
-    QObject* NewControllerScriptingInterface::newMapping() {
-        qDebug() << "Creating new Mapping proxy";
-        return new MappingBuilderProxy(std::make_shared<Mapping>());
+    QVariantMap createDeviceMap(const UserInputMapper::DeviceProxy* device) {
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        QVariantMap deviceMap;
+        for (const auto& inputMapping : device->getAvailabeInputs()) {
+            const auto& input = inputMapping.first;
+            const auto inputName = sanatizeName(inputMapping.second);
+            qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType()
+                << QString::number(input.getID(), 16) << ": " << inputName;
+            deviceMap.insert(inputName, input.getID());
+        }
+        return deviceMap;
+    }
+
+    NewControllerScriptingInterface::NewControllerScriptingInterface() {
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        auto devices = userInputMapper->getDevices();
+        for (const auto& deviceMapping : devices) {
+            auto device = deviceMapping.second.get();
+            auto deviceName = sanatizeName(device->getName());
+            qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
+            // Expose the IDs to JS
+            _hardware.insert(deviceName, createDeviceMap(device));
+
+            // Create the endpoints
+            for (const auto& inputMapping : device->getAvailabeInputs()) {
+                const auto& input = inputMapping.first;
+                // Ignore aliases
+                if (_endpoints.count(input)) {
+                    continue;
+                }
+                _endpoints[input] = std::make_shared<LambdaEndpoint>([=] {
+                    auto deviceProxy = userInputMapper->getDeviceProxy(input);
+                    if (!deviceProxy) {
+                        return 0.0f;
+                    }
+                    return deviceProxy->getValue(input, 0);
+                });
+            }
+        }
+
+        qCDebug(controllers) << "Setting up standard controller abstraction";
+        auto standardDevice = userInputMapper->getStandardDevice();
+        // Expose the IDs to JS
+        _standard = createDeviceMap(standardDevice.get());
+        // Create the endpoints
+        for (const auto& inputMapping : standardDevice->getAvailabeInputs()) {
+            const auto& standardInput = inputMapping.first;
+            // Ignore aliases
+            if (_endpoints.count(standardInput)) {
+                continue;
+            }
+            _endpoints[standardInput] = std::make_shared<VirtualEndpoint>(standardInput);
+        }
+
+        auto actionNames = userInputMapper->getActionNames();
+        int actionNumber = 0;
+        qCDebug(controllers) << "Setting up standard actions";
+        for (const auto& actionName : actionNames) {
+            UserInputMapper::Input actionInput(ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
+            qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16);
+            // Expose the IDs to JS
+            _actions.insert(sanatizeName(actionName), actionInput.getID());
+
+            // Create the endpoints
+            // FIXME action endpoints need to accumulate values, and have them cleared at each frame
+            _endpoints[actionInput] = std::make_shared<VirtualEndpoint>();
+        }
+    }
+
+    QObject* NewControllerScriptingInterface::newMapping(const QString& mappingName) {
+        if (_mappingsByName.count(mappingName)) {
+            qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
+        }
+        qDebug() << "Creating new Mapping " << mappingName;
+        Mapping::Pointer mapping = std::make_shared<Mapping>();
+        _mappingsByName[mappingName] = mapping;
+        return new MappingBuilderProxy(*this, mapping);
+    }
+
+    void NewControllerScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
+        auto iterator = _mappingsByName.find(mappingName);
+        if (_mappingsByName.end() == iterator) {
+            qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName;
+            return;
+        }
+
+        auto mapping = iterator->second;
+        if (enable) {
+            _activeMappings.push_front(mapping);
+        } else {
+            auto activeIterator = std::find(_activeMappings.begin(), _activeMappings.end(), mapping);
+            if (_activeMappings.end() == activeIterator) {
+                qCWarning(controllers) << "Attempted to disable inactive mapping " << mappingName;
+                return;
+            }
+            _activeMappings.erase(activeIterator);
+        }
     }
 
     float NewControllerScriptingInterface::getValue(const int& source) {
-        //UserInputMapper::Input input; input._id = source;
-        //auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        //auto deviceProxy = userInputMapper->getDeviceProxy(input);
-        //return deviceProxy->getButton(input, 0) ? 1.0 : 0.0;
+        // return (sin(secTimestampNow()) + 1.0f) / 2.0f;
+        UserInputMapper::Input input(source);
+        auto iterator = _endpoints.find(input);
+        if (_endpoints.end() == iterator) {
+            return 0.0;
+        }
 
-        return (sin(secTimestampNow()) + 1.0f) / 2.0f;
+        const auto& endpoint = iterator->second;
+        return getValue(endpoint);
+    }
+
+    float NewControllerScriptingInterface::getValue(const Endpoint::Pointer& endpoint) {
+        auto valuesIterator = _overrideValues.find(endpoint);
+        if (_overrideValues.end() != valuesIterator) {
+            return valuesIterator->second;
+        }
+
+        return endpoint->value();
+    }
+
+        
+    void NewControllerScriptingInterface::update() {
+        static float last = secTimestampNow();
+        float now = secTimestampNow();
+        float delta = now - last;
+        last = now;
+
+        foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
+            inputPlugin->pluginUpdate(delta, false);
+        }
+
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        userInputMapper->update(delta);
+
+        _overrideValues.clear();
+        EndpointSet readEndpoints;
+        EndpointSet writtenEndpoints;
+        // Now process the current values for each level of the stack
+        for (auto& mapping : _activeMappings) {
+            for (const auto& mappingEntry : mapping->_channelMappings) {
+                const auto& source = mappingEntry.first;
+
+                // Endpoints can only be read once (though a given mapping can route them to 
+                // multiple places).  Consider... If the default is to wire the A button to JUMP
+                // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
+                // I press the button.  The exception is if I'm wiring a control back to itself
+                // in order to adjust my interface, like inverting the Y axis on an analog stick
+                if (readEndpoints.count(source)) {
+                    continue;
+                }
+
+                // Apply the value to all the routes
+                const auto& routes = mappingEntry.second;
+
+                for (const auto& route : routes) {
+                    const auto& destination = route->_destination;
+
+                    if (writtenEndpoints.count(destination)) {
+                        continue;
+                    }
+
+                    // Standard controller destinations can only be can only be used once.
+                    if (userInputMapper->getStandardDeviceID() == destination->getId().getDevice()) {
+                        writtenEndpoints.insert(destination);
+                    }
+
+                    // Only consume the input if the route isn't a loopback.
+                    // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
+                    bool loopback = source == destination;
+                    if (!loopback) {
+                        readEndpoints.insert(source);
+                    }
+
+                    // Fetch the value, may have been overriden by previous loopback routes
+                    float value = getValue(source);
+
+                    // Apply each of the filters.
+                    const auto& filters = route->_filters;
+                    for (const auto& filter : route->_filters) {
+                        value = filter->apply(value);
+                    }
+
+                    if (loopback) {
+                        _overrideValues[source] = value;
+                    } else {
+                        destination->apply(value, 0, source);
+                    }
+                }
+            }
+        }
+    }
+
+
+
+    Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const QJSValue& endpoint) {
+        if (endpoint.isNumber()) {
+            return endpointFor(UserInputMapper::Input(endpoint.toInt()));
+        }
+
+        if (endpoint.isCallable()) {
+            auto result = std::make_shared<JSEndpoint>(endpoint);
+            return result;
+        }
+
+        qWarning() << "Unsupported input type " << endpoint.toString();
+        return Endpoint::Pointer();
+    }
+
+    Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const QScriptValue& endpoint) {
+        if (endpoint.isNumber()) {
+            return endpointFor(UserInputMapper::Input(endpoint.toInt32()));
+        }
+
+        qWarning() << "Unsupported input type " << endpoint.toString();
+        return Endpoint::Pointer();
+    }
+
+    Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) {
+        auto iterator = _endpoints.find(inputId);
+        if (_endpoints.end() == iterator) {
+            qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
+            return Endpoint::Pointer();
+        }
+        return iterator->second;
+    }
+
+    Endpoint::Pointer NewControllerScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) {
+        EndpointPair pair(first, second);
+        Endpoint::Pointer result;
+        auto iterator = _compositeEndpoints.find(pair);
+        if (_compositeEndpoints.end() == iterator) {
+            result = std::make_shared<CompositeEndpoint>(first, second);
+            _compositeEndpoints[pair] = result;
+        } else {
+            result = iterator->second;
+        }
+        return result;
     }
 
 } // namespace controllers
 
-
-
-
-//    class MappingsStack {
-//        std::list<Mapping> _stack;
-//        ValueMap _lastValues;
-//
-//        void update() {
-//            EndpointList hardwareInputs = getHardwareEndpoints();
-//            ValueMap currentValues;
-//
-//            for (auto input : hardwareInputs) {
-//                currentValues[input] = input->value();
-//            }
-//
-//            // Now process the current values for each level of the stack
-//            for (auto& mapping : _stack) {
-//                update(mapping, currentValues);
-//            }
-//
-//            _lastValues = currentValues;
-//        }
-//
-//        void update(Mapping& mapping, ValueMap& values) {
-//            ValueMap updates;
-//            EndpointList consumedEndpoints;
-//            for (const auto& entry : values) {
-//                Endpoint* endpoint = entry.first;
-//                if (!mapping._channelMappings.count(endpoint)) {
-//                    continue;
-//                }
-//
-//                const Mapping::List& routes = mapping._channelMappings[endpoint];
-//                consumedEndpoints.push_back(endpoint);
-//                for (const auto& route : routes) {
-//                    float lastValue = 0;
-//                    if (mapping._lastValues.count(endpoint)) {
-//                        lastValue = mapping._lastValues[endpoint];
-//                    }
-//                    float value = entry.second;
-//                    for (const auto& filter : route._filters) {
-//                        value = filter->apply(value, lastValue);
-//                    }
-//                    updates[route._destination] = value;
-//                }
-//            }
-//
-//            // Update the last seen values
-//            mapping._lastValues = values;
-//
-//            // Remove all the consumed inputs
-//            for (auto endpoint : consumedEndpoints) {
-//                values.erase(endpoint);
-//            }
-//
-//            // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
-//            for (const auto& entry : updates) {
-//                values[entry.first] = entry.second;
-//            }
-//        }
-//    };
 //var mapping = Controller.newMapping();
 //mapping.map(hydra.LeftButton0, actions.ContextMenu);
 //mapping.map(hydra.LeftButton0).to(xbox.RT);
@@ -134,5 +364,3 @@ namespace Controllers {
 
 //        mappingSnap.from(hydra.LX).to(function(newValue, oldValue) {
 //        timeSinceLastYaw += deltaTime
-
-#include "NewControllerScriptingInterface.moc"
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
index c4c42a2245..6bf0bda40d 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
@@ -10,21 +10,78 @@
 #ifndef hifi_Controllers_NewControllerScriptingInterface_h
 #define hifi_Controllers_NewControllerScriptingInterface_h
 
+#include <unordered_map>
+#include <unordered_set>
+#include <map>
+#include <set>
+
 #include <QtCore/QObject>
 #include <QtCore/QVariant>
 
+#include <QtQml/QJSValue>
+#include <QtScript/QScriptValue>
+
+#include <input-plugins/UserInputMapper.h>
+
 #include "Mapping.h"
 
 class QScriptValue;
 
-namespace Controllers {
+namespace controller {
     class NewControllerScriptingInterface : public QObject {
         Q_OBJECT
-    
+        Q_PROPERTY(QVariantMap Hardware READ getHardware CONSTANT FINAL)
+        Q_PROPERTY(QVariantMap Actions READ getActions CONSTANT FINAL)
+        Q_PROPERTY(QVariantMap Standard READ getStandard CONSTANT FINAL)
+
     public:
-        Q_INVOKABLE void update();
-        Q_INVOKABLE QObject* newMapping();
+        NewControllerScriptingInterface();
         Q_INVOKABLE float getValue(const int& source);
+
+        Q_INVOKABLE void update();
+        Q_INVOKABLE QObject* newMapping(const QString& mappingName);
+        Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
+        Q_INVOKABLE void disableMapping(const QString& mappingName) {
+            enableMapping(mappingName, false);
+        }
+
+
+        const QVariantMap& getHardware() { return _hardware; }
+        const QVariantMap& getActions() { return _actions; }
+        const QVariantMap& getStandard() { return _standard; }
+
+    private:
+
+        // FIXME move to unordered set / map
+        using MappingMap = std::map<QString, Mapping::Pointer>;
+        using MappingStack = std::list<Mapping::Pointer>;
+        using InputToEndpointMap = std::map<UserInputMapper::Input, Endpoint::Pointer>;
+        using EndpointSet = std::unordered_set<Endpoint::Pointer>;
+        using ValueMap = std::map<Endpoint::Pointer, float>;
+        using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
+        using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
+
+        void update(Mapping::Pointer& mapping, EndpointSet& consumed);
+        float getValue(const Endpoint::Pointer& endpoint);
+        Endpoint::Pointer endpointFor(const QJSValue& endpoint);
+        Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
+        Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint);
+        Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
+
+        friend class MappingBuilderProxy;
+        friend class RouteBuilderProxy;
+    private:
+        uint16_t _nextFunctionId;
+        InputToEndpointMap _endpoints;
+        EndpointPairMap _compositeEndpoints;
+
+        ValueMap _overrideValues;
+        MappingMap _mappingsByName;
+        MappingStack _activeMappings;
+
+        QVariantMap _hardware;
+        QVariantMap _actions;
+        QVariantMap _standard;
     };
 }
 
diff --git a/libraries/controllers/src/controllers/Route.cpp b/libraries/controllers/src/controllers/Route.cpp
index 29fb9b04eb..b9116d2813 100644
--- a/libraries/controllers/src/controllers/Route.cpp
+++ b/libraries/controllers/src/controllers/Route.cpp
@@ -12,10 +12,11 @@
 
 #include "Endpoint.h"
 #include "Filter.h"
+#include "Logging.h"
 
 class QJsonObject;
 
-namespace Controllers {
+namespace controller {
 
     /*
     * encapsulates a source, destination and filters to apply
diff --git a/libraries/controllers/src/controllers/Route.h b/libraries/controllers/src/controllers/Route.h
index 9459369d18..01770a87d1 100644
--- a/libraries/controllers/src/controllers/Route.h
+++ b/libraries/controllers/src/controllers/Route.h
@@ -15,7 +15,7 @@
 
 class QJsonObject;
 
-namespace Controllers {
+namespace controller {
 
     /*
     * encapsulates a source, destination and filters to apply
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index e16fa511db..4e2c6a4d8c 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -12,22 +12,33 @@
 #include <QtCore/QDebug>
 
 #include "RouteBuilderProxy.h"
+#include "../NewControllerScriptingInterface.h"
+#include "../Logging.h"
 
-namespace Controllers {
+namespace controller {
 
-QObject* MappingBuilderProxy::from(const QString& source) {
-    qDebug() << "Creating new Route builder proxy from " << source;
+QObject* MappingBuilderProxy::from(const QJSValue& source) {
+    qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString();
+    auto sourceEndpoint = _parent.endpointFor(source);
+    return from(sourceEndpoint);
+}
+
+QObject* MappingBuilderProxy::from(const QScriptValue& source) {
+    qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString();
+    auto sourceEndpoint = _parent.endpointFor(source);
+    return from(sourceEndpoint);
+}
+
+QObject* MappingBuilderProxy::from(const Endpoint::Pointer& source) {
     auto route = Route::Pointer(new Route());
-    route->_source = endpointFor(source);
-    return new RouteBuilderProxy(this, route);
+    route->_source = source;
+    return new RouteBuilderProxy(_parent, _mapping, route);
 }
 
-Endpoint::Pointer MappingBuilderProxy::endpointFor(const QString& endpoint) {
-    static QHash<QString, Endpoint::Pointer> ENDPOINTS;
-    if (!ENDPOINTS.contains(endpoint)) {
-        ENDPOINTS[endpoint] = std::make_shared<Endpoint>();
-    }
-    return ENDPOINTS[endpoint];
+QObject* MappingBuilderProxy::join(const QJSValue& source1, const QJSValue& source2) {
+    auto source1Endpoint = _parent.endpointFor(source1);
+    auto source2Endpoint = _parent.endpointFor(source2);
+    return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint));
 }
 
 }
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index 6dac38b21e..b5e02bbfdf 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -13,20 +13,30 @@
 #include <QtCore/QString>
 
 #include "../Mapping.h"
+#include "../Endpoint.h"
 
-namespace Controllers {
+class QJSValue;
+class QScriptValue;
+
+namespace controller {
+
+class NewControllerScriptingInterface;
 
 class MappingBuilderProxy : public QObject {
     Q_OBJECT
 public:
-    MappingBuilderProxy(Mapping::Pointer mapping)
-        : _mapping(mapping) { }
+    MappingBuilderProxy(NewControllerScriptingInterface& parent, Mapping::Pointer mapping)
+        : _parent(parent), _mapping(mapping) { }
 
-    Q_INVOKABLE QObject* from(const QString& fromEndpoint);
+    Q_INVOKABLE QObject* from(const QJSValue& source);
+    Q_INVOKABLE QObject* from(const QScriptValue& source);
 
+    Q_INVOKABLE QObject* join(const QJSValue& source1, const QJSValue& source2);
 protected:
+    QObject* from(const Endpoint::Pointer& source);
+
     friend class RouteBuilderProxy;
-    Endpoint::Pointer endpointFor(const QString& endpoint);
+    NewControllerScriptingInterface& _parent;
     Mapping::Pointer _mapping;
 };
 
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index d1659573e4..e6b67e9ca6 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -12,17 +12,47 @@
 #include <GLMHelpers.h>
 
 #include "MappingBuilderProxy.h"
+#include "../NewControllerScriptingInterface.h"
+#include "../Logging.h"
 
-namespace Controllers {
+namespace controller {
 
-void RouteBuilderProxy::to(const QString& destination) {
-    qDebug() << "Completed route: " << destination;
+void RouteBuilderProxy::to(const QJSValue& destination) {
+    qCDebug(controllers) << "Completing route " << destination.toString();
+    auto destinationEndpoint = _parent.endpointFor(destination);
+    return to(destinationEndpoint);
+}
+
+void RouteBuilderProxy::to(const QScriptValue& destination) {
+    qCDebug(controllers) << "Completing route " << destination.toString();
+    auto destinationEndpoint = _parent.endpointFor(destination);
+    return to(destinationEndpoint);
+}
+
+void RouteBuilderProxy::to(const Endpoint::Pointer& destination) {
     auto sourceEndpoint = _route->_source;
-    auto& mapping = _parent->_mapping;
-    mapping->_channelMappings[sourceEndpoint].push_back(_route);
+    _route->_destination = destination;
+    _mapping->_channelMappings[sourceEndpoint].push_back(_route);
     deleteLater();
 }
 
+QObject* RouteBuilderProxy::filter(const QJSValue& expression) {
+    if (expression.isCallable()) {
+        addFilter([=](float value) {
+            QJSValue originalExpression = expression;
+            QJSValueList params({ QJSValue(value) });
+            auto result = originalExpression.call(params);
+            return (float)(result.toNumber());
+        });
+    }
+    return this;
+}
+
+QObject* RouteBuilderProxy::filter(const QScriptValue& expression) {
+    return this;
+}
+
+
 QObject* RouteBuilderProxy::clamp(float min, float max) {
     addFilter([=](float value) {
         return glm::clamp(value, min, max);
@@ -45,7 +75,7 @@ QObject* RouteBuilderProxy::deadZone(float min) {
     assert(min < 1.0f);
     float scale = 1.0f / (1.0f - min);
     addFilter([=](float value) {
-        if (value < min) {
+        if (abs(value) < min) {
             return 0.0f;
         }
         return (value - min) * scale;
@@ -68,6 +98,40 @@ QObject* RouteBuilderProxy::constrainToPositiveInteger() {
     return this;
 }
 
+
+class PulseFilter : public Filter {
+public:
+    PulseFilter(float interval) : _interval(interval) {}
+    
+    virtual float apply(float value) const override {
+        float result = 0.0;
+
+        if (0.0 != value) {
+            float now = secTimestampNow();
+            float delta = now - _lastEmitTime;
+            if (delta >= _interval) {
+                _lastEmitTime = now;
+                result = value;
+            }
+        }
+
+        return result;
+    }
+
+private:
+    mutable float _lastEmitTime{ -std::numeric_limits<float>::max() };
+    const float _interval;
+};
+
+
+QObject* RouteBuilderProxy::pulse(float interval) {
+    Filter::Pointer filter = std::make_shared<PulseFilter>(interval);
+    addFilter(filter);
+    return this;
+}
+
+
+
 void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
     Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda);
     addFilter(filterPointer);
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 516712b969..63cd106edb 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -12,19 +12,28 @@
 #include <QtCore/QObject>
 #include "../Filter.h"
 #include "../Route.h"
+#include "../Mapping.h"
 
-namespace Controllers {
+class QJSValue;
+class QScriptValue;
 
-class MappingBuilderProxy;
+namespace controller {
+
+class NewControllerScriptingInterface;
 
 class RouteBuilderProxy : public QObject {
         Q_OBJECT
     public:
-        RouteBuilderProxy(MappingBuilderProxy* parent, Route::Pointer route)
-            : _parent(parent), _route(route) { }
+        RouteBuilderProxy(NewControllerScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route)
+            : _parent(parent), _mapping(mapping), _route(route) { }
 
-        Q_INVOKABLE void to(const QString& destination);
+        Q_INVOKABLE void to(const QJSValue& destination);
+        Q_INVOKABLE void to(const QScriptValue& destination);
+
+        Q_INVOKABLE QObject* filter(const QJSValue& expression);
+        Q_INVOKABLE QObject* filter(const QScriptValue& expression);
         Q_INVOKABLE QObject* clamp(float min, float max);
+        Q_INVOKABLE QObject* pulse(float interval);
         Q_INVOKABLE QObject* scale(float multiplier);
         Q_INVOKABLE QObject* invert();
         Q_INVOKABLE QObject* deadZone(float min);
@@ -32,10 +41,13 @@ class RouteBuilderProxy : public QObject {
         Q_INVOKABLE QObject* constrainToPositiveInteger();
 
     private:
+        void to(const Endpoint::Pointer& destination);
         void addFilter(Filter::Lambda lambda);
         void addFilter(Filter::Pointer filter);
+        Mapping::Pointer _mapping;
         Route::Pointer _route;
-        MappingBuilderProxy* _parent;
+
+        NewControllerScriptingInterface& _parent;
     };
 
 }
diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
index 227bd12e1b..b52dd3f658 100644
--- a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
+++ b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
@@ -22,8 +22,8 @@ InputPluginList getInputPlugins() {
     InputPlugin* PLUGIN_POOL[] = {
         new KeyboardMouseDevice(),
         new SDL2Manager(),
-        new SixenseManager(),
-        new ViveControllerManager(),
+        //new SixenseManager(),
+        //new ViveControllerManager(),
         nullptr
     };
 
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index d0e2705e98..5c6f43c604 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -15,6 +15,8 @@
 
 #include "Joystick.h"
 
+#include "StandardControls.h"
+
 const float CONTROLLER_THRESHOLD = 0.3f;
 
 #ifdef HAVE_SDL2
@@ -55,39 +57,14 @@ void Joystick::focusOutEvent() {
 };
 
 #ifdef HAVE_SDL2
+
 void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
     SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
-    
-    switch (axis) {
-        case SDL_CONTROLLER_AXIS_LEFTX:
-            _axisStateMap[makeInput(LEFT_AXIS_X_POS).getChannel()] = (event.value > 0.0f) ? event.value / MAX_AXIS : 0.0f;
-            _axisStateMap[makeInput(LEFT_AXIS_X_NEG).getChannel()] = (event.value < 0.0f) ? -event.value / MAX_AXIS : 0.0f;
-            break;
-        case SDL_CONTROLLER_AXIS_LEFTY:
-            _axisStateMap[makeInput(LEFT_AXIS_Y_POS).getChannel()] = (event.value > 0.0f) ? event.value / MAX_AXIS : 0.0f;
-            _axisStateMap[makeInput(LEFT_AXIS_Y_NEG).getChannel()] = (event.value < 0.0f) ? -event.value / MAX_AXIS : 0.0f;
-            break;
-        case SDL_CONTROLLER_AXIS_RIGHTX:
-            _axisStateMap[makeInput(RIGHT_AXIS_X_POS).getChannel()] = (event.value > 0.0f) ? event.value / MAX_AXIS : 0.0f;
-            _axisStateMap[makeInput(RIGHT_AXIS_X_NEG).getChannel()] = (event.value < 0.0f) ? -event.value / MAX_AXIS : 0.0f;
-            break;
-        case SDL_CONTROLLER_AXIS_RIGHTY:
-            _axisStateMap[makeInput(RIGHT_AXIS_Y_POS).getChannel()] = (event.value > 0.0f) ? event.value / MAX_AXIS : 0.0f;
-            _axisStateMap[makeInput(RIGHT_AXIS_Y_NEG).getChannel()] = (event.value < 0.0f) ? -event.value / MAX_AXIS : 0.0f;
-            break;
-        case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
-            _axisStateMap[makeInput(RIGHT_SHOULDER).getChannel()] = event.value / MAX_AXIS;
-            break;
-        case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
-            _axisStateMap[makeInput(LEFT_SHOULDER).getChannel()] = event.value / MAX_AXIS;
-            break;
-        default:
-            break;
-    }
+    _axisStateMap[makeInput((Controllers::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
 }
 
 void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
-    auto input = makeInput((SDL_GameControllerButton) event.button);
+    auto input = makeInput((Controllers::StandardButtonChannel)event.button);
     bool newValue = event.state == SDL_PRESSED;
     if (newValue) {
         _buttonPressedMap.insert(input.getChannel());
@@ -95,6 +72,7 @@ void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
         _buttonPressedMap.erase(input.getChannel());
     }
 }
+
 #endif
 
 
@@ -107,32 +85,57 @@ void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
     proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
     proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
         QVector<UserInputMapper::InputPair> availableInputs;
-#ifdef HAVE_SDL2
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_A), "Bottom Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_B), "Right Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_X), "Left Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_Y), "Top Button"));
-        
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_DPAD_UP), "DPad Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_DPAD_DOWN), "DPad Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_DPAD_LEFT), "DPad Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_DPAD_RIGHT), "DPad Right"));
-        
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_LEFTSHOULDER), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_SHOULDER), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_SHOULDER), "R2"));
-        
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_Y_NEG), "Left Stick Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_Y_POS), "Left Stick Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_X_POS), "Left Stick Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_X_NEG), "Left Stick Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_Y_NEG), "Right Stick Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_Y_POS), "Right Stick Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_X_POS), "Right Stick Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_X_NEG), "Right Stick Left"));
+        // Buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "A"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "B"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "X"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Y"));
+
+        // DPad
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "DU"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "DD"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "DL"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "DR"));
+
+        // Bumpers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "LB"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "RB"));
+
+        // Stick press
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "LS"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "RS"));
+
+        // Center buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::START), "Start"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Back"));
+
+        // Analog sticks
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LY), "LY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LX), "LX"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RY), "RY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RX), "RX"));
+
+        // Triggers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "LT"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "RT"));
+
+        // Aliases, PlayStation style names
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "L1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "R1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "L2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "R2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "L3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "R3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Select"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "Cross"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "Circle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "Square"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Triangle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "Up"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "Down"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "Left"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "Right"));
 
-#endif
         return availableInputs;
     };
     proxy->resetDeviceBindings = [this, &mapper] () -> bool {
@@ -150,76 +153,15 @@ void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
     const float JOYSTICK_YAW_SPEED = 0.5f;
     const float JOYSTICK_PITCH_SPEED = 0.25f;
     const float BOOM_SPEED = 0.1f;
-    
-    // Y axes are flipped (up is negative)
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(LEFT_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(LEFT_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(LEFT_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(LEFT_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
-    
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(RIGHT_AXIS_X_POS), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(RIGHT_AXIS_X_NEG), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(RIGHT_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(RIGHT_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
-    
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(SDL_CONTROLLER_BUTTON_DPAD_UP), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(SDL_CONTROLLER_BUTTON_DPAD_DOWN), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(SDL_CONTROLLER_BUTTON_DPAD_RIGHT), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(SDL_CONTROLLER_BUTTON_DPAD_LEFT), DPAD_MOVE_SPEED);
-    
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(SDL_CONTROLLER_BUTTON_Y), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(SDL_CONTROLLER_BUTTON_X), DPAD_MOVE_SPEED);
-    
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(RIGHT_SHOULDER), BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(LEFT_SHOULDER), BOOM_SPEED);
-    
-    
-    // Hold front right shoulder button for precision controls
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(LEFT_AXIS_Y_NEG), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(LEFT_AXIS_Y_POS), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(LEFT_AXIS_X_POS), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(LEFT_AXIS_X_NEG), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
-    
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(RIGHT_AXIS_X_POS), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_YAW_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(RIGHT_AXIS_X_NEG), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_YAW_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(RIGHT_AXIS_Y_NEG), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_PITCH_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(RIGHT_AXIS_Y_POS), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_PITCH_SPEED/2.0f);
-    
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(SDL_CONTROLLER_BUTTON_DPAD_UP), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(SDL_CONTROLLER_BUTTON_DPAD_DOWN), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(SDL_CONTROLLER_BUTTON_DPAD_RIGHT), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(SDL_CONTROLLER_BUTTON_DPAD_LEFT), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(SDL_CONTROLLER_BUTTON_Y), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(SDL_CONTROLLER_BUTTON_X), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(RIGHT_SHOULDER), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), BOOM_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(LEFT_SHOULDER), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), BOOM_SPEED/2.0f);
-    
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(SDL_CONTROLLER_BUTTON_LEFTSHOULDER));
-    
-    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(SDL_CONTROLLER_BUTTON_B));
-    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(SDL_CONTROLLER_BUTTON_A));
+
 #endif
 }
 
-#ifdef HAVE_SDL2
-UserInputMapper::Input Joystick::makeInput(SDL_GameControllerButton button) {
+UserInputMapper::Input Joystick::makeInput(Controllers::StandardButtonChannel button) {
     return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
 }
-#endif
 
-UserInputMapper::Input Joystick::makeInput(Joystick::JoystickAxisChannel axis) {
+UserInputMapper::Input Joystick::makeInput(Controllers::StandardAxisChannel axis) {
     return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
 }
 
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h
index 2ba89da052..70949a8b83 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.h
+++ b/libraries/input-plugins/src/input-plugins/Joystick.h
@@ -21,6 +21,7 @@
 #endif
 
 #include "InputDevice.h"
+#include "StandardControls.h"
 
 class Joystick : public QObject, public InputDevice {
     Q_OBJECT
@@ -31,18 +32,6 @@ class Joystick : public QObject, public InputDevice {
 #endif
     
 public:
-    enum JoystickAxisChannel {
-        LEFT_AXIS_X_POS = 0,
-        LEFT_AXIS_X_NEG,
-        LEFT_AXIS_Y_POS,
-        LEFT_AXIS_Y_NEG,
-        RIGHT_AXIS_X_POS,
-        RIGHT_AXIS_X_NEG,
-        RIGHT_AXIS_Y_POS,
-        RIGHT_AXIS_Y_NEG,
-        RIGHT_SHOULDER,
-        LEFT_SHOULDER,
-    };
 
     const QString& getName() const { return _name; }
 
@@ -55,10 +44,8 @@ public:
     Joystick() : InputDevice("Joystick") {}
     ~Joystick();
     
-#ifdef HAVE_SDL2
-    UserInputMapper::Input makeInput(SDL_GameControllerButton button);
-#endif
-    UserInputMapper::Input makeInput(Joystick::JoystickAxisChannel axis);
+    UserInputMapper::Input makeInput(Controllers::StandardButtonChannel button);
+    UserInputMapper::Input makeInput(Controllers::StandardAxisChannel axis);
     
 #ifdef HAVE_SDL2
     Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
index 36ae643a8e..202a767244 100755
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
@@ -10,6 +10,11 @@
 //
 #include "KeyboardMouseDevice.h"
 
+#include <QtGUI/QKeyEvent>
+#include <QtGUI/QMouseEvent>
+#include <QtGUI/QTouchEvent>
+
+
 const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse";
 
 void KeyboardMouseDevice::update(float deltaTime, bool jointsCaptured) {
@@ -81,7 +86,7 @@ void KeyboardMouseDevice::wheelEvent(QWheelEvent* event) {
     _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_Y_NEG).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f);
 }
 
-glm::vec2 KeyboardMouseDevice::evalAverageTouchPoints(const QList<QTouchEvent::TouchPoint>& points) const {
+glm::vec2 evalAverageTouchPoints(const QList<QTouchEvent::TouchPoint>& points) {
     glm::vec2 averagePoint(0.0f);
     if (points.count() > 0) {
         for (auto& point : points) {
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
index 6f703bc6f9..d96566e9d1 100644
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
@@ -12,11 +12,15 @@
 #ifndef hifi_KeyboardMouseDevice_h
 #define hifi_KeyboardMouseDevice_h
 
-#include <QTouchEvent>
 #include <chrono>
 #include "InputDevice.h"
 #include "InputPlugin.h"
 
+class QTouchEvent;
+class QKeyEvent;
+class QMouseEvent;
+class QWheelEvent;
+
 class KeyboardMouseDevice : public InputPlugin, public InputDevice {
     Q_OBJECT
 public:
@@ -100,7 +104,6 @@ protected:
     glm::vec2 _lastTouch;
     bool _isTouching = false;
     
-    glm::vec2 evalAverageTouchPoints(const QList<QTouchEvent::TouchPoint>& points) const;
     std::chrono::high_resolution_clock _clock;
     std::chrono::high_resolution_clock::time_point _lastTouchTime;
 };
diff --git a/libraries/input-plugins/src/input-plugins/StandardController.cpp b/libraries/input-plugins/src/input-plugins/StandardController.cpp
index 4fb4a23654..040efca794 100644
--- a/libraries/input-plugins/src/input-plugins/StandardController.cpp
+++ b/libraries/input-plugins/src/input-plugins/StandardController.cpp
@@ -23,11 +23,6 @@ StandardController::~StandardController() {
 }
 
 void StandardController::update(float deltaTime, bool jointsCaptured) {
-    for (auto axisState : _axisStateMap) {
-        if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
-            _axisStateMap[axisState.first] = 0.0f;
-        }
-    }
 }
 
 void StandardController::focusOutEvent() {
@@ -44,119 +39,85 @@ void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
     proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
     proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
         QVector<UserInputMapper::InputPair> availableInputs;
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_A), "Bottom Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_B), "Right Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_X), "Left Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_Y), "Top Button"));
-        
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_UP), "DPad Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_DOWN), "DPad Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_LEFT), "DPad Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_RIGHT), "DPad Right"));
-        
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_LEFTSHOULDER), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_SHOULDER), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_SHOULDER), "R2"));
-        
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_Y_NEG), "Left Stick Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_Y_POS), "Left Stick Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_X_POS), "Left Stick Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_X_NEG), "Left Stick Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_Y_NEG), "Right Stick Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_Y_POS), "Right Stick Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_X_POS), "Right Stick Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_X_NEG), "Right Stick Left"));
+        // Buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "A"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "B"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "X"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Y"));
+
+        // DPad
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "DU"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "DD"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "DL"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "DR"));
+
+        // Bumpers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "LB"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "RB"));
+
+        // Stick press
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "LS"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "RS"));
+
+        // Center buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::START), "Start"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Back"));
+
+        // Analog sticks
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LY), "LY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LX), "LX"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RY), "RY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RX), "RX"));
+
+        // Triggers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "LT"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "RT"));
+
+        // Poses
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LeftPose), "LeftPose"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RightPose), "RightPose"));
+
+        // Aliases, PlayStation style names
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "L1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "R1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "L2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "R2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "L3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "R3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Select"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "Cross"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "Circle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "Square"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Triangle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "Up"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "Down"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "Left"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "Right"));
 
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_HAND), "Left Hand"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_HAND), "Right Hand"));
 
         return availableInputs;
     };
+
     proxy->resetDeviceBindings = [this, &mapper] () -> bool {
         mapper.removeAllInputChannelsForDevice(_deviceID);
         this->assignDefaultInputMapping(mapper);
         return true;
     };
+
     mapper.registerStandardDevice(proxy);
 }
 
 void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    const float DPAD_MOVE_SPEED = 0.5f;
-    const float JOYSTICK_YAW_SPEED = 0.5f;
-    const float JOYSTICK_PITCH_SPEED = 0.25f;
-    const float BOOM_SPEED = 0.1f;
-    
-    // Y axes are flipped (up is negative)
-    // Left StandardController: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(LEFT_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(LEFT_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(LEFT_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(LEFT_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
-    
-    // Right StandardController: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(RIGHT_AXIS_X_POS), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(RIGHT_AXIS_X_NEG), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(RIGHT_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(RIGHT_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
-    
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_UP), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_DOWN), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_RIGHT), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_LEFT), DPAD_MOVE_SPEED);
-    
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(STANDARD_CONTROLLER_BUTTON_Y), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(STANDARD_CONTROLLER_BUTTON_X), DPAD_MOVE_SPEED);
-    
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(RIGHT_SHOULDER), BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(LEFT_SHOULDER), BOOM_SPEED);
-    
-    
-    // Hold front right shoulder button for precision controls
-    // Left StandardController: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(LEFT_AXIS_Y_NEG), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(LEFT_AXIS_Y_POS), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(LEFT_AXIS_X_POS), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(LEFT_AXIS_X_NEG), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
-    
-    // Right StandardController: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(RIGHT_AXIS_X_POS), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_YAW_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(RIGHT_AXIS_X_NEG), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_YAW_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(RIGHT_AXIS_Y_NEG), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_PITCH_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(RIGHT_AXIS_Y_POS), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_PITCH_SPEED/2.0f);
-    
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_UP), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_DOWN), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_RIGHT), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_LEFT), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(STANDARD_CONTROLLER_BUTTON_Y), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(STANDARD_CONTROLLER_BUTTON_X), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
-    
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(RIGHT_SHOULDER), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), BOOM_SPEED/2.0f);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(LEFT_SHOULDER), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), BOOM_SPEED/2.0f);
-    
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(STANDARD_CONTROLLER_BUTTON_LEFTSHOULDER));
-    
-    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(STANDARD_CONTROLLER_BUTTON_B));
-    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(STANDARD_CONTROLLER_BUTTON_A));
 }
 
-UserInputMapper::Input StandardController::makeInput(StandardController::StandardControllerButtonChannel button) {
+UserInputMapper::Input StandardController::makeInput(Controllers::StandardButtonChannel button) {
     return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
 }
 
-UserInputMapper::Input StandardController::makeInput(StandardController::StandardControllerAxisChannel axis) {
+UserInputMapper::Input StandardController::makeInput(Controllers::StandardAxisChannel axis) {
     return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
 }
 
-UserInputMapper::Input StandardController::makeInput(StandardController::StandardControllerPoseChannel pose) {
+UserInputMapper::Input StandardController::makeInput(Controllers::StandardPoseChannel pose) {
     return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
 }
diff --git a/libraries/input-plugins/src/input-plugins/StandardController.h b/libraries/input-plugins/src/input-plugins/StandardController.h
index f7a4215242..fa660e15b8 100644
--- a/libraries/input-plugins/src/input-plugins/StandardController.h
+++ b/libraries/input-plugins/src/input-plugins/StandardController.h
@@ -17,6 +17,8 @@
 
 #include "InputDevice.h"
 
+#include "StandardControls.h"
+
 typedef std::shared_ptr<StandardController> StandardControllerPointer;
 
 class StandardController : public QObject, public InputDevice {
@@ -24,37 +26,6 @@ class StandardController : public QObject, public InputDevice {
     Q_PROPERTY(QString name READ getName)
 
 public:
-    enum StandardControllerAxisChannel {
-        LEFT_AXIS_X_POS = 0,
-        LEFT_AXIS_X_NEG,
-        LEFT_AXIS_Y_POS,
-        LEFT_AXIS_Y_NEG,
-        RIGHT_AXIS_X_POS,
-        RIGHT_AXIS_X_NEG,
-        RIGHT_AXIS_Y_POS,
-        RIGHT_AXIS_Y_NEG,
-        RIGHT_SHOULDER,
-        LEFT_SHOULDER,
-    };
-    enum StandardControllerButtonChannel {
-        STANDARD_CONTROLLER_BUTTON_A = 0,
-        STANDARD_CONTROLLER_BUTTON_B,
-        STANDARD_CONTROLLER_BUTTON_X,
-        STANDARD_CONTROLLER_BUTTON_Y,
-
-        STANDARD_CONTROLLER_BUTTON_DPAD_UP,
-        STANDARD_CONTROLLER_BUTTON_DPAD_DOWN,
-        STANDARD_CONTROLLER_BUTTON_DPAD_LEFT,
-        STANDARD_CONTROLLER_BUTTON_DPAD_RIGHT,
-
-        STANDARD_CONTROLLER_BUTTON_LEFTSHOULDER,
-        STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER,
-    };
-
-    enum StandardControllerPoseChannel {
-        LEFT_HAND = 0,
-        RIGHT_HAND,
-    };
 
     const QString& getName() const { return _name; }
 
@@ -67,9 +38,9 @@ public:
     StandardController() : InputDevice("Standard") {}
     ~StandardController();
     
-    UserInputMapper::Input makeInput(StandardController::StandardControllerButtonChannel button);
-    UserInputMapper::Input makeInput(StandardController::StandardControllerAxisChannel axis);
-    UserInputMapper::Input makeInput(StandardController::StandardControllerPoseChannel pose);
+    UserInputMapper::Input makeInput(Controllers::StandardButtonChannel button);
+    UserInputMapper::Input makeInput(Controllers::StandardAxisChannel axis);
+    UserInputMapper::Input makeInput(Controllers::StandardPoseChannel pose);
 
 private:
 };
diff --git a/libraries/input-plugins/src/input-plugins/StandardControls.h b/libraries/input-plugins/src/input-plugins/StandardControls.h
new file mode 100644
index 0000000000..9b79bbdae1
--- /dev/null
+++ b/libraries/input-plugins/src/input-plugins/StandardControls.h
@@ -0,0 +1,55 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#pragma once
+
+namespace Controllers {
+
+    // Needs to match order and values of SDL_GameControllerButton
+    enum StandardButtonChannel {
+        // Button quad
+        A = 0,
+        B,
+        X,
+        Y,
+        // Center buttons
+        BACK,
+        GUIDE,
+        START,
+        // Stick press
+        LS,
+        RS,
+        // Bumper press
+        LB,
+        RB,
+        // DPad
+        DU,
+        DD,
+        DL,
+        DR
+    };
+
+    // Needs to match order and values of SDL_GameControllerAxis
+    enum StandardAxisChannel {
+        // Left Analog stick
+        LX = 0,
+        LY,
+        // Right Analog stick
+        RX,
+        RY,
+        // Triggers
+        LT,
+        RT
+    };
+
+    // No correlation to SDL
+    enum StandardPoseChannel {
+        LeftPose = 0,
+        RightPose
+    };
+
+}
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
index fad962345c..c29acc09af 100755
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
+++ b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
@@ -1,335 +1,368 @@
-//
-//  UserInputMapper.cpp
-//  input-plugins/src/input-plugins
-//
-//  Created by Sam Gateau on 4/27/15.
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include "UserInputMapper.h"
-#include "StandardController.h"
-
-// Default contruct allocate the poutput size with the current hardcoded action channels
-UserInputMapper::UserInputMapper() {
-    registerStandardDevice();
-    assignDefaulActionScales();
-    createActionNames();
-}
-
-UserInputMapper::~UserInputMapper() {
-}
-
-
-bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
-    proxy->_name += " (" + QString::number(deviceID) + ")";
-    _registeredDevices[deviceID] = proxy;
-    return true;
-}
-
-UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
-    auto device = _registeredDevices.find(input.getDevice());
-    if (device != _registeredDevices.end()) {
-        return (device->second);
-    } else {
-        return DeviceProxy::Pointer();
-    }
-}
-
-QString UserInputMapper::getDeviceName(uint16 deviceID) { 
-    if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
-        return _registeredDevices[deviceID]->_name;
-    }
-    return QString("unknown");
-}
-
-
-void UserInputMapper::resetAllDeviceBindings() {
-    for (auto device : _registeredDevices) {
-        device.second->resetDeviceBindings();
-    }
-}
-
-void UserInputMapper::resetDevice(uint16 deviceID) {
-    auto device = _registeredDevices.find(deviceID);
-    if (device != _registeredDevices.end()) {
-        device->second->resetDeviceBindings();
-    }
-}
-
-int UserInputMapper::findDevice(QString name) {
-    for (auto device : _registeredDevices) {
-        if (device.second->_name.split(" (")[0] == name) {
-            return device.first;
-        }
-    }
-    return 0;
-}
-
-QVector<QString> UserInputMapper::getDeviceNames() {
-    QVector<QString> result;
-    for (auto device : _registeredDevices) {
-        QString deviceName = device.second->_name.split(" (")[0];
-        result << deviceName;
-    }
-    return result;
-}
-
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
-    return addInputChannel(action, input, Input(), scale);
-}
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
-    // Check that the device is registered
-    if (!getDeviceProxy(input)) {
-        qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
-        return false;
-    }
-    
-    auto inputChannel = InputChannel(input, modifier, action, scale);
-
-    // Insert or replace the input to modifiers
-    if (inputChannel.hasModifier()) {
-        auto& modifiers = _inputToModifiersMap[input.getID()];
-        modifiers.push_back(inputChannel._modifier);
-        std::sort(modifiers.begin(), modifiers.end());
-    }
-
-    // Now update the action To Inputs side of things
-    _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
-
-    return true;
-}
-
-int UserInputMapper::addInputChannels(const InputChannels& channels) {
-    int nbAdded = 0;
-    for (auto& channel : channels) {
-        nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
-    }
-    return nbAdded;
-}
-
-bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
-    // Remove from Input to Modifiers map
-    if (inputChannel.hasModifier()) {
-        _inputToModifiersMap.erase(inputChannel._input.getID());
-    }
-    
-    // Remove from Action to Inputs map
-    std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
-    ret = _actionToInputsMap.equal_range(inputChannel._action);
-    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
-        if (it->second == inputChannel) {
-            _actionToInputsMap.erase(it);
-            return true;
-        }
-    }
-    
-    return false;
-}
-
-void UserInputMapper::removeAllInputChannels() {
-    _inputToModifiersMap.clear();
-    _actionToInputsMap.clear();
-}
-
-void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
-    QVector<InputChannel> channels = getAllInputsForDevice(device);
-    for (auto& channel : channels) {
-        removeInputChannel(channel);
-    }
-}
-
-void UserInputMapper::removeDevice(int device) {
-    removeAllInputChannelsForDevice((uint16) device);
-    _registeredDevices.erase(device);
-}
-
-int UserInputMapper::getInputChannels(InputChannels& channels) const {
-    for (auto& channel : _actionToInputsMap) {
-        channels.push_back(channel.second);
-    }
-
-    return _actionToInputsMap.size();
-}
-
-QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
-    InputChannels allChannels;
-    getInputChannels(allChannels);
-    
-    QVector<InputChannel> channels;
-    for (InputChannel inputChannel : allChannels) {
-        if (inputChannel._input._device == device) {
-            channels.push_back(inputChannel);
-        }
-    }
-    
-    return channels;
-}
-
-void UserInputMapper::update(float deltaTime) {
-
-    // Reset the axis state for next loop
-    for (auto& channel : _actionStates) {
-        channel = 0.0f;
-    }
-    
-    for (auto& channel : _poseStates) {
-        channel = PoseValue();
-    }
-
-    int currentTimestamp = 0;
-
-    for (auto& channelInput : _actionToInputsMap) {
-        auto& inputMapping = channelInput.second;
-        auto& inputID = inputMapping._input;
-        bool enabled = true;
-        
-        // Check if this input channel has modifiers and collect the possibilities
-        auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
-        if (modifiersIt != _inputToModifiersMap.end()) {
-            Modifiers validModifiers;
-            bool isActiveModifier = false;
-            for (auto& modifier : modifiersIt->second) {
-                auto deviceProxy = getDeviceProxy(modifier);
-                if (deviceProxy->getButton(modifier, currentTimestamp)) {
-                    validModifiers.push_back(modifier);
-                    isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
-                }
-            }
-            enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
-        }
-
-        // if enabled: default input or all modifiers on
-        if (enabled) {
-            auto deviceProxy = getDeviceProxy(inputID);
-            switch (inputMapping._input.getType()) {
-                case ChannelType::BUTTON: {
-                    _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
-                    break;
-                }
-                case ChannelType::AXIS: {
-                    _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
-                    break;
-                }
-                case ChannelType::POSE: {
-                    if (!_poseStates[channelInput.first].isValid()) {
-                        _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
-                    }
-                    break;
-                }
-                default: {
-                    break; //silence please
-                }
-            }
-        } else{
-            // Channel input not enabled
-            enabled = false;
-        }
-    }
-
-    // Scale all the channel step with the scale
-    static const float EPSILON =  0.01f;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        _actionStates[i] *= _actionScales[i];
-        // Emit only on change, and emit when moving back to 0
-        if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
-            _lastActionStates[i] = _actionStates[i];
-            emit actionEvent(i, _actionStates[i]);
-        }
-        // TODO: emit signal for pose changes
-    }
-}
-
-QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
-    QVector<Action> actions;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        actions.append(Action(i));
-    }
-    return actions;
-}
-
-QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
-    QVector<InputChannel> inputChannels;
-    std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
-    ret = _actionToInputsMap.equal_range(action);
-    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
-        inputChannels.append(it->second);
-    }
-    return inputChannels;
-}
-
-int UserInputMapper::findAction(const QString& actionName) const {
-    auto actions = getAllActions();
-    for (auto action : actions) {
-        if (getActionName(action) == actionName) {
-            return action;
-        }
-    }
-    // If the action isn't found, return -1
-    return -1;
-}
-
-QVector<QString> UserInputMapper::getActionNames() const {
-    QVector<QString> result;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        result << _actionNames[i];
-    }
-    return result;
-}
-
-void UserInputMapper::assignDefaulActionScales() {
-    _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit
-    _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit
-    _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit
-    _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit
-    _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit
-    _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit
-    _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit
-    _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit
-    _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit
-    _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
-    _actionScales[BOOM_IN] = 0.5f; // .5m per unit
-    _actionScales[BOOM_OUT] = 0.5f; // .5m per unit
-    _actionScales[LEFT_HAND] = 1.0f; // default
-    _actionScales[RIGHT_HAND] = 1.0f; // default
-    _actionScales[LEFT_HAND_CLICK] = 1.0f; // on
-    _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
-    _actionStates[SHIFT] = 1.0f; // on
-    _actionStates[ACTION1] = 1.0f; // default
-    _actionStates[ACTION2] = 1.0f; // default
-}
-
-// This is only necessary as long as the actions are hardcoded
-// Eventually you can just add the string when you add the action
-void UserInputMapper::createActionNames() {
-    _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
-    _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
-    _actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
-    _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
-    _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
-    _actionNames[VERTICAL_UP] = "VERTICAL_UP";
-    _actionNames[YAW_LEFT] = "YAW_LEFT";
-    _actionNames[YAW_RIGHT] = "YAW_RIGHT";
-    _actionNames[PITCH_DOWN] = "PITCH_DOWN";
-    _actionNames[PITCH_UP] = "PITCH_UP";
-    _actionNames[BOOM_IN] = "BOOM_IN";
-    _actionNames[BOOM_OUT] = "BOOM_OUT";
-    _actionNames[LEFT_HAND] = "LEFT_HAND";
-    _actionNames[RIGHT_HAND] = "RIGHT_HAND";
-    _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
-    _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
-    _actionNames[SHIFT] = "SHIFT";
-    _actionNames[ACTION1] = "ACTION1";
-    _actionNames[ACTION2] = "ACTION2";
-    _actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
-    _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
-}
-
-void UserInputMapper::registerStandardDevice() {
-    _standardController = std::make_shared<StandardController>();
-    _standardController->registerToUserInputMapper(*this);
-}
\ No newline at end of file
+//
+//  UserInputMapper.cpp
+//  input-plugins/src/input-plugins
+//
+//  Created by Sam Gateau on 4/27/15.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "UserInputMapper.h"
+#include "StandardController.h"
+
+const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX);
+const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
+const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
+const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
+
+// Default contruct allocate the poutput size with the current hardcoded action channels
+UserInputMapper::UserInputMapper() {
+    registerStandardDevice();
+    assignDefaulActionScales();
+    createActionNames();
+}
+
+UserInputMapper::~UserInputMapper() {
+}
+
+
+bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
+    proxy->_name += " (" + QString::number(deviceID) + ")";
+    _registeredDevices[deviceID] = proxy;
+    return true;
+}
+
+UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
+    auto device = _registeredDevices.find(input.getDevice());
+    if (device != _registeredDevices.end()) {
+        return (device->second);
+    } else {
+        return DeviceProxy::Pointer();
+    }
+}
+
+QString UserInputMapper::getDeviceName(uint16 deviceID) { 
+    if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
+        return _registeredDevices[deviceID]->_name;
+    }
+    return QString("unknown");
+}
+
+
+void UserInputMapper::resetAllDeviceBindings() {
+    for (auto device : _registeredDevices) {
+        device.second->resetDeviceBindings();
+    }
+}
+
+void UserInputMapper::resetDevice(uint16 deviceID) {
+    auto device = _registeredDevices.find(deviceID);
+    if (device != _registeredDevices.end()) {
+        device->second->resetDeviceBindings();
+    }
+}
+
+int UserInputMapper::findDevice(QString name) {
+    for (auto device : _registeredDevices) {
+        if (device.second->_name.split(" (")[0] == name) {
+            return device.first;
+        }
+    }
+    return 0;
+}
+
+QVector<QString> UserInputMapper::getDeviceNames() {
+    QVector<QString> result;
+    for (auto device : _registeredDevices) {
+        QString deviceName = device.second->_name.split(" (")[0];
+        result << deviceName;
+    }
+    return result;
+}
+
+
+bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
+    return addInputChannel(action, input, Input(), scale);
+}
+
+bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
+    // Check that the device is registered
+    if (!getDeviceProxy(input)) {
+        qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
+        return false;
+    }
+    
+    auto inputChannel = InputChannel(input, modifier, action, scale);
+
+    // Insert or replace the input to modifiers
+    if (inputChannel.hasModifier()) {
+        auto& modifiers = _inputToModifiersMap[input.getID()];
+        modifiers.push_back(inputChannel._modifier);
+        std::sort(modifiers.begin(), modifiers.end());
+    }
+
+    // Now update the action To Inputs side of things
+    _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
+
+    return true;
+}
+
+int UserInputMapper::addInputChannels(const InputChannels& channels) {
+    int nbAdded = 0;
+    for (auto& channel : channels) {
+        nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
+    }
+    return nbAdded;
+}
+
+bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
+    // Remove from Input to Modifiers map
+    if (inputChannel.hasModifier()) {
+        _inputToModifiersMap.erase(inputChannel._input.getID());
+    }
+    
+    // Remove from Action to Inputs map
+    std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
+    ret = _actionToInputsMap.equal_range(inputChannel._action);
+    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
+        if (it->second == inputChannel) {
+            _actionToInputsMap.erase(it);
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+void UserInputMapper::removeAllInputChannels() {
+    _inputToModifiersMap.clear();
+    _actionToInputsMap.clear();
+}
+
+void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
+    QVector<InputChannel> channels = getAllInputsForDevice(device);
+    for (auto& channel : channels) {
+        removeInputChannel(channel);
+    }
+}
+
+void UserInputMapper::removeDevice(int device) {
+    removeAllInputChannelsForDevice((uint16) device);
+    _registeredDevices.erase(device);
+}
+
+int UserInputMapper::getInputChannels(InputChannels& channels) const {
+    for (auto& channel : _actionToInputsMap) {
+        channels.push_back(channel.second);
+    }
+
+    return _actionToInputsMap.size();
+}
+
+QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
+    InputChannels allChannels;
+    getInputChannels(allChannels);
+    
+    QVector<InputChannel> channels;
+    for (InputChannel inputChannel : allChannels) {
+        if (inputChannel._input._device == device) {
+            channels.push_back(inputChannel);
+        }
+    }
+    
+    return channels;
+}
+
+void UserInputMapper::update(float deltaTime) {
+
+    // Reset the axis state for next loop
+    for (auto& channel : _actionStates) {
+        channel = 0.0f;
+    }
+    
+    for (auto& channel : _poseStates) {
+        channel = PoseValue();
+    }
+
+    int currentTimestamp = 0;
+
+    for (auto& channelInput : _actionToInputsMap) {
+        auto& inputMapping = channelInput.second;
+        auto& inputID = inputMapping._input;
+        bool enabled = true;
+        
+        // Check if this input channel has modifiers and collect the possibilities
+        auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
+        if (modifiersIt != _inputToModifiersMap.end()) {
+            Modifiers validModifiers;
+            bool isActiveModifier = false;
+            for (auto& modifier : modifiersIt->second) {
+                auto deviceProxy = getDeviceProxy(modifier);
+                if (deviceProxy->getButton(modifier, currentTimestamp)) {
+                    validModifiers.push_back(modifier);
+                    isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
+                }
+            }
+            enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
+        }
+
+        // if enabled: default input or all modifiers on
+        if (enabled) {
+            auto deviceProxy = getDeviceProxy(inputID);
+            switch (inputMapping._input.getType()) {
+                case ChannelType::BUTTON: {
+                    _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
+                    break;
+                }
+                case ChannelType::AXIS: {
+                    _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
+                    break;
+                }
+                case ChannelType::POSE: {
+                    if (!_poseStates[channelInput.first].isValid()) {
+                        _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
+                    }
+                    break;
+                }
+                default: {
+                    break; //silence please
+                }
+            }
+        } else{
+            // Channel input not enabled
+            enabled = false;
+        }
+    }
+
+    // Scale all the channel step with the scale
+    static const float EPSILON =  0.01f;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        _actionStates[i] *= _actionScales[i];
+        // Emit only on change, and emit when moving back to 0
+        if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
+            _lastActionStates[i] = _actionStates[i];
+            emit actionEvent(i, _actionStates[i]);
+        }
+        // TODO: emit signal for pose changes
+    }
+}
+
+QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
+    QVector<Action> actions;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        actions.append(Action(i));
+    }
+    return actions;
+}
+
+QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
+    QVector<InputChannel> inputChannels;
+    std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
+    ret = _actionToInputsMap.equal_range(action);
+    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
+        inputChannels.append(it->second);
+    }
+    return inputChannels;
+}
+
+int UserInputMapper::findAction(const QString& actionName) const {
+    auto actions = getAllActions();
+    for (auto action : actions) {
+        if (getActionName(action) == actionName) {
+            return action;
+        }
+    }
+    // If the action isn't found, return -1
+    return -1;
+}
+
+QVector<QString> UserInputMapper::getActionNames() const {
+    QVector<QString> result;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        result << _actionNames[i];
+    }
+    return result;
+}
+
+void UserInputMapper::assignDefaulActionScales() {
+    _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit
+    _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit
+    _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit
+    _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit
+    _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit
+    _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit
+    _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit
+    _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit
+    _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit
+    _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
+    _actionScales[BOOM_IN] = 0.5f; // .5m per unit
+    _actionScales[BOOM_OUT] = 0.5f; // .5m per unit
+    _actionScales[LEFT_HAND] = 1.0f; // default
+    _actionScales[RIGHT_HAND] = 1.0f; // default
+    _actionScales[LEFT_HAND_CLICK] = 1.0f; // on
+    _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
+    _actionStates[SHIFT] = 1.0f; // on
+    _actionStates[ACTION1] = 1.0f; // default
+    _actionStates[ACTION2] = 1.0f; // default
+    _actionStates[TranslateX] = 1.0f; // default
+    _actionStates[TranslateY] = 1.0f; // default
+    _actionStates[TranslateZ] = 1.0f; // default
+    _actionStates[Roll] = 1.0f; // default
+    _actionStates[Pitch] = 1.0f; // default
+    _actionStates[Yaw] = 1.0f; // default
+}
+
+// This is only necessary as long as the actions are hardcoded
+// Eventually you can just add the string when you add the action
+void UserInputMapper::createActionNames() {
+    _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
+    _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
+    _actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
+    _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
+    _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
+    _actionNames[VERTICAL_UP] = "VERTICAL_UP";
+    _actionNames[YAW_LEFT] = "YAW_LEFT";
+    _actionNames[YAW_RIGHT] = "YAW_RIGHT";
+    _actionNames[PITCH_DOWN] = "PITCH_DOWN";
+    _actionNames[PITCH_UP] = "PITCH_UP";
+    _actionNames[BOOM_IN] = "BOOM_IN";
+    _actionNames[BOOM_OUT] = "BOOM_OUT";
+    _actionNames[LEFT_HAND] = "LEFT_HAND";
+    _actionNames[RIGHT_HAND] = "RIGHT_HAND";
+    _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
+    _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
+    _actionNames[SHIFT] = "SHIFT";
+    _actionNames[ACTION1] = "ACTION1";
+    _actionNames[ACTION2] = "ACTION2";
+    _actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
+    _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
+    _actionNames[TranslateX] = "TranslateX";
+    _actionNames[TranslateY] = "TranslateY";
+    _actionNames[TranslateZ] = "TranslateZ";
+    _actionNames[Roll] = "Roll";
+    _actionNames[Pitch] = "Pitch";
+    _actionNames[Yaw] = "Yaw";
+}
+
+void UserInputMapper::registerStandardDevice() {
+    _standardController = std::make_shared<StandardController>();
+    _standardController->registerToUserInputMapper(*this);
+}
+
+float UserInputMapper::DeviceProxy::getValue(const Input& input, int timestamp) const {
+    switch (input.getType()) {
+        case UserInputMapper::ChannelType::BUTTON:
+            return getButton(input, timestamp) ? 1.0f : 0.0f;
+
+        case UserInputMapper::ChannelType::AXIS:
+            return getAxis(input, timestamp);
+
+        case UserInputMapper::ChannelType::POSE:
+            return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
+
+        default:
+            return 0.0f;
+    }
+}
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.h b/libraries/input-plugins/src/input-plugins/UserInputMapper.h
index 1d64638ee1..304e74e8cc 100755
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.h
+++ b/libraries/input-plugins/src/input-plugins/UserInputMapper.h
@@ -48,8 +48,9 @@ public:
         union {
             struct {
                 uint16 _device; // Up to 64K possible devices
-                uint16 _channel : 14; // 2^14 possible channel per Device
+                uint16 _channel : 13; // 2^13 possible channel per Device
                 uint16 _type : 2; // 2 bits to store the Type directly in the ID
+                uint16 _padding : 1; // 2 bits to store the Type directly in the ID
             };
             uint32 _id = 0; // by default Input is 0 meaning invalid
         };
@@ -74,13 +75,19 @@ public:
         // where the default initializer (a C++-11ism) for the union data above is not applied.
         explicit Input() : _id(0) {}
         explicit Input(uint32 id) : _id(id) {}
-        explicit Input(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)) {}
+        explicit Input(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)), _padding(0) {}
         Input(const Input& src) : _id(src._id) {}
         Input& operator = (const Input& src) { _id = src._id; return (*this); }
         bool operator ==(const Input& right) const { return _id == right._id; }
         bool operator < (const Input& src) const { return _id < src._id; }
+
+        static const Input INVALID_INPUT;
+        static const uint16 INVALID_DEVICE;
+        static const uint16 INVALID_CHANNEL;
+        static const uint16 INVALID_TYPE;
     };
 
+
     // Modifiers are just button inputID
     typedef std::vector< Input > Modifiers;
 
@@ -121,7 +128,7 @@ public:
        PoseGetter getPose = [] (const Input& input, int timestamp) -> PoseValue { return PoseValue(); };
        AvailableInputGetter getAvailabeInputs = [] () -> AvailableInput { return QVector<InputPair>(); };
        ResetBindings resetDeviceBindings = [] () -> bool { return true; };
-       
+       float getValue(const Input& input, int timestamp = 0) const;
        typedef std::shared_ptr<DeviceProxy> Pointer;
     };
     // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
@@ -171,6 +178,13 @@ public:
         CONTEXT_MENU,
         TOGGLE_MUTE,
 
+        TranslateX,
+        TranslateY,
+        TranslateZ,
+        Roll,
+        Pitch,
+        Yaw,
+
         NUM_ACTIONS,
     };
     
diff --git a/tests/controllers/qml/Xbox.qml b/tests/controllers/qml/Xbox.qml
new file mode 100644
index 0000000000..ae66081162
--- /dev/null
+++ b/tests/controllers/qml/Xbox.qml
@@ -0,0 +1,99 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "./xbox"
+import "./controls"
+
+Item {
+    id: root
+
+    property var device
+
+    property real scale: 1.0
+    width: 300 * scale
+    height: 215 * scale
+    
+    Image {
+        anchors.fill: parent
+        source: "xbox/xbox360-controller-md.png"
+
+        LeftAnalogStick {
+            device: root.device
+            x: (65 * root.scale) - width / 2; y: (42 * root.scale) - height / 2
+        }
+
+        // Left stick press
+        ToggleButton {
+            controlId: root.device.LS
+            width: 16 * root.scale; height: 16 * root.scale
+            x: (65 * root.scale) - width / 2; y: (42 * root.scale) - height / 2
+        }
+
+
+        RightAnalogStick {
+            device: root.device
+            x: (193 * root.scale) - width / 2; y: (96 * root.scale) - height / 2
+        }
+
+        // Right stick press
+        ToggleButton {
+            controlId: root.device.RS
+            width: 16 * root.scale; height: 16 * root.scale
+            x: (193 * root.scale) - width / 2; y: (96 * root.scale) - height / 2
+        }
+
+        // Left trigger
+        AnalogButton {
+            controlId: root.device.LT
+            width: 8; height: 64
+            x: (20 * root.scale); y: (7 * root.scale)
+        }
+
+        // Right trigger
+        AnalogButton {
+            controlId: root.device.RT
+            width: 8; height: 64
+            x: (272 * root.scale); y: (7 * root.scale)
+        }
+
+        // Left bumper
+        ToggleButton {
+            controlId: root.device.LB
+            width: 32 * root.scale; height: 16 * root.scale
+            x: (40 * root.scale); y: (7 * root.scale)
+        }
+
+        // Right bumper
+        ToggleButton {
+            controlId: root.device.RB
+            width: 32 * root.scale; height: 16 * root.scale
+            x: (root.width - width) - (40 * root.scale); y: (7 * root.scale)
+        }
+
+        DPad {
+            device: root.device
+            size: 48 * root.scale
+            x: (80 * root.scale); y: (71 * root.scale)
+        }
+
+        XboxButtons {
+            device: root.device
+            size: 65 * root.scale
+            x: (206 * root.scale); y: (19 * root.scale)
+        }
+
+        ToggleButton {
+            controlId: root.device.Back
+            width: 16 * root.scale; height: 12 * root.scale
+            x: (112 * root.scale); y: (45 * root.scale)
+        }
+
+        ToggleButton {
+            controlId: root.device.Start
+            width: 16 * root.scale; height: 12 * root.scale
+            x: (177 * root.scale); y: (45 * root.scale)
+        }
+    }
+}
diff --git a/tests/controllers/qml/content.qml b/tests/controllers/qml/content.qml
index ac171ac42c..ce8a491419 100644
--- a/tests/controllers/qml/content.qml
+++ b/tests/controllers/qml/content.qml
@@ -1,137 +1,97 @@
-import QtQuick 2.1
-import QtQuick.Controls 1.0
-import QtQuick.Layouts 1.0
-import QtQuick.Dialogs 1.0
-
-Rectangle {
-    id: root
-    implicitHeight: column1.height + 24
-    implicitWidth: column1.width + 24
-    color: "lightgray"
-
-    property real itemSize: 128
-
-    Component {
-        id: graphTemplate
-        Item {
-            implicitHeight: canvas.height + 2 + text.height
-            implicitWidth: canvas.width
-            property string text: loadText
-
-            Canvas {
-               id: canvas
-               width: root.itemSize; height: root.itemSize;
-               antialiasing: false
-               property int controlId: control
-               property real value: 0.0
-               property int drawWidth: 1
-
-               Timer {
-                   interval: 50; running: true; repeat: true
-                   onTriggered: {
-                       parent.value = NewControllers.getValue(canvas.controlId)
-                       parent.requestPaint();
-                   }
-               }
-
-               onPaint: {
-                   var ctx = canvas.getContext('2d');
-                   ctx.save();
-
-                   var image = ctx.getImageData(0, 0, canvas.width, canvas.height);
-                   ctx.clearRect(0, 0, canvas.width, canvas.height);
-                   ctx.drawImage(image, -drawWidth, 0, canvas.width, canvas.height)
-                   ctx.fillStyle = 'green'
-                   // draw a filles rectangle
-                   var height = canvas.height * canvas.value
-                   ctx.fillRect(canvas.width - drawWidth, canvas.height - height,
-                                drawWidth, height)
-                   ctx.restore()
-               }
-            }
-
-            Text {
-                id: text
-                text: parent.text
-                anchors.topMargin: 2
-                anchors.horizontalCenter: canvas.horizontalCenter
-                anchors.top: canvas.bottom
-                font.pointSize: 12;
-            }
-
-        }
-    }
-
-    Column {
-        id: column1
-        x: 12; y: 12
-        spacing: 24
-        Row {
-            spacing: 16
-            Loader {
-                sourceComponent: graphTemplate;
-                property string loadText: "Key Left"
-                property int control: ControllerIds.Hardware.Keyboard2.Left
-            }
-            Loader {
-                sourceComponent: graphTemplate;
-                property string loadText: "DPad Up"
-                property int control: ControllerIds.Hardware.X360Controller1.DPadUp
-            }
-            /*
-            Loader {
-                sourceComponent: graphTemplate;
-                property string loadText: "Yaw Left"
-                property int control: ControllerIds.Actions.YAW_LEFT
-            }
-            Loader {
-                sourceComponent: graphTemplate;
-                property string loadText: "Yaw Left"
-                property int control: ControllerIds.Actions.YAW_LEFT
-            }
-*/
-
-//            Loader { sourceComponent: graphTemplate; }
-//            Loader { sourceComponent: graphTemplate; }
-//            Loader { sourceComponent: graphTemplate; }
-        }
-        /*
-        Row {
-            spacing: 16
-            Loader { sourceComponent: graphTemplate; }
-            Loader { sourceComponent: graphTemplate; }
-            Loader { sourceComponent: graphTemplate; }
-            Loader { sourceComponent: graphTemplate; }
-        }
-        Row {
-            spacing: 16
-            Loader { sourceComponent: graphTemplate; }
-            Loader { sourceComponent: graphTemplate; }
-            Loader { sourceComponent: graphTemplate; }
-            Loader { sourceComponent: graphTemplate; }
-        }
-        */
-
-
-        Button {
-            text: "Go!"
-            onClicked: {
-                //
-
-//                var newMapping = NewControllers.newMapping();
-//                console.log("Mapping Object " + newMapping);
-//                var routeBuilder = newMapping.from("Hello");
-//                console.log("Route Builder " + routeBuilder);
-//                routeBuilder.clamp(0, 1).clamp(0, 1).to("Goodbye");
-            }
-        }
-
-        Timer {
-            interval: 50; running: true; repeat: true
-            onTriggered: {
-                NewControllers.update();
-            }
-        }
-
-    }
-}
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "./xbox"
+import "./controls"
+
+Column {
+    id: root
+    property var xbox: NewControllers.Hardware.X360Controller1
+    property var actions: NewControllers.Actions
+    property var standard: NewControllers.Standard
+    property string mappingName: "TestMapping"
+
+    spacing: 12
+
+    Timer {
+        interval: 50; running: true; repeat: true
+        onTriggered: {
+            NewControllers.update();
+        }
+    }
+
+    Row {
+        spacing: 8
+        Button {
+            text: "Default Mapping"
+            onClicked: {
+                var mapping = NewControllers.newMapping("Default");
+                mapping.from(xbox.A).to(standard.A);
+                mapping.from(xbox.B).to(standard.B);
+                mapping.from(xbox.X).to(standard.X);
+                mapping.from(xbox.Y).to(standard.Y);
+                mapping.from(xbox.Up).to(standard.DU);
+                mapping.from(xbox.Down).to(standard.DD);
+                mapping.from(xbox.Left).to(standard.DL);
+                mapping.from(xbox.Right).to(standard.Right);
+                mapping.from(xbox.LB).to(standard.LB);
+                mapping.from(xbox.RB).to(standard.RB);
+                mapping.from(xbox.LS).to(standard.LS);
+                mapping.from(xbox.RS).to(standard.RS);
+                mapping.from(xbox.Start).to(standard.Start);
+                mapping.from(xbox.Back).to(standard.Back);
+                mapping.from(xbox.LY).to(standard.LY);
+                mapping.from(xbox.LX).to(standard.LX);
+                mapping.from(xbox.RY).to(standard.RY);
+                mapping.from(xbox.RX).to(standard.RX);
+                mapping.from(xbox.LT).to(standard.LT);
+                mapping.from(xbox.RT).to(standard.RT);
+                NewControllers.enableMapping("Default");
+            }
+        }
+
+        Button {
+            text: "Build Mapping"
+            onClicked: {
+                var mapping = NewControllers.newMapping(root.mappingName);
+                // Inverting a value
+                mapping.from(xbox.RY).invert().to(standard.RY);
+                // Assigning a value from a function
+                mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
+                // Constrainting a value to -1, 0, or 1, with a deadzone
+                mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
+                mapping.join(standard.LB, standard.RB).pulse(0.5).to(actions.Yaw);
+            }
+        }
+
+        Button {
+            text: "Enable Mapping"
+            onClicked: NewControllers.enableMapping(root.mappingName)
+        }
+
+        Button {
+            text: "Disable Mapping"
+            onClicked: NewControllers.disableMapping(root.mappingName)
+        }
+    }
+
+    Row {
+        spacing: 8
+        Xbox { device: root.xbox }
+        Xbox { device: root.standard }
+    }
+
+
+    Row {
+        ScrollingGraph {
+            controlId: NewControllers.Actions.Yaw
+            label: "Yaw"
+            min: -3.0
+            max: 3.0
+            size: 128
+        }
+    }
+}
+
diff --git a/tests/controllers/qml/controls/AnalogButton.qml b/tests/controllers/qml/controls/AnalogButton.qml
new file mode 100644
index 0000000000..26f91458ac
--- /dev/null
+++ b/tests/controllers/qml/controls/AnalogButton.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+Item {
+    id: root
+    property int size: 64
+    width: size
+    height: size
+    property int controlId: 0
+    property real value: 0
+    property color color: 'black'
+
+    function update() {
+        value = NewControllers.getValue(controlId);
+        canvas.requestPaint();
+    }
+
+    Timer {
+        interval: 50; running: true; repeat: true
+        onTriggered: root.update();
+    }
+
+    Canvas {
+       id: canvas
+       anchors.fill: parent
+       antialiasing: false
+
+       onPaint: {
+           var ctx = canvas.getContext('2d');
+           ctx.save();
+           ctx.beginPath();
+           ctx.clearRect(0, 0, canvas.width, canvas.height);
+           var fillHeight = root.value * canvas.height;
+
+           ctx.fillStyle = 'red'
+           ctx.fillRect(0, canvas.height - fillHeight, canvas.width, fillHeight);
+           ctx.fill();
+           ctx.restore()
+       }
+    }
+}
+
+
diff --git a/tests/controllers/qml/controls/AnalogStick.qml b/tests/controllers/qml/controls/AnalogStick.qml
new file mode 100644
index 0000000000..8860aea49c
--- /dev/null
+++ b/tests/controllers/qml/controls/AnalogStick.qml
@@ -0,0 +1,50 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+Item {
+    id: root
+    property int size: 64
+    width: size
+    height: size
+
+    property int halfSize: size / 2
+    property var controlIds: [ 0, 0 ]
+    property vector2d value: Qt.vector2d(0, 0)
+
+    function update() {
+        value = Qt.vector2d(
+            NewControllers.getValue(controlIds[0]),
+            NewControllers.getValue(controlIds[1])
+        );
+        canvas.requestPaint();
+    }
+
+    Timer {
+        interval: 50; running: true; repeat: true
+        onTriggered: root.update()
+    }
+
+    Canvas {
+       id: canvas
+       anchors.fill: parent
+       antialiasing: false
+
+       onPaint: {
+           var ctx = canvas.getContext('2d');
+           ctx.save();
+           ctx.beginPath();
+           ctx.clearRect(0, 0, width, height);
+           ctx.fill();
+           ctx.translate(root.halfSize, root.halfSize)
+           ctx.lineWidth = 4
+           ctx.strokeStyle = Qt.rgba(Math.max(Math.abs(value.x), Math.abs(value.y)), 0, 0, 1)
+           ctx.moveTo(0, 0).lineTo(root.value.x * root.halfSize, root.value.y * root.halfSize)
+           ctx.stroke()
+           ctx.restore()
+       }
+    }
+}
+
+
diff --git a/tests/controllers/qml/controls/ScrollingGraph.qml b/tests/controllers/qml/controls/ScrollingGraph.qml
new file mode 100644
index 0000000000..69f919aaf1
--- /dev/null
+++ b/tests/controllers/qml/controls/ScrollingGraph.qml
@@ -0,0 +1,104 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+Item {
+    id: root
+    property int size: 64
+    width: size
+    height: size
+
+    property int controlId: 0
+    property real value: 0.5
+    property int scrollWidth: 1
+    property real min: 0.0
+    property real max: 1.0
+    property bool log: false
+    property real range: max - min
+    property color color: 'blue'
+    property bool bar: false
+    property real lastHeight: -1
+    property string label: ""
+
+    function update() {
+        value = NewControllers.getValue(controlId);
+        canvas.requestPaint();
+    }
+
+    function drawHeight() {
+        if (value < min) {
+            return 0;
+        }
+        if (value > max) {
+            return height;
+        }
+        return ((value - min) / range) * height;
+    }
+
+    Timer {
+        interval: 50; running: true; repeat: true
+        onTriggered: root.update()
+    }
+
+    Canvas {
+       id: canvas
+       anchors.fill: parent
+       antialiasing: false
+
+       Text {
+           anchors.top: parent.top
+           text: root.label
+
+       }
+
+       Text {
+           anchors.right: parent.right
+           anchors.top: parent.top
+           text: root.max
+       }
+
+       Text {
+           anchors.right: parent.right
+           anchors.bottom: parent.bottom
+           text: root.min
+       }
+
+       function scroll() {
+           var ctx = canvas.getContext('2d');
+           var image = ctx.getImageData(0, 0, canvas.width, canvas.height);
+           ctx.beginPath();
+           ctx.clearRect(0, 0, canvas.width, canvas.height);
+           ctx.drawImage(image, -root.scrollWidth, 0, canvas.width, canvas.height)
+           ctx.restore()
+       }
+
+       onPaint: {
+           scroll();
+           var ctx = canvas.getContext('2d');
+           ctx.save();
+           var currentHeight = root.drawHeight();
+           if (root.lastHeight == -1) {
+               root.lastHeight = currentHeight
+           }
+
+//           var x = canvas.width - root.drawWidth;
+//           var y = canvas.height - drawHeight;
+//           ctx.fillStyle = root.color
+//           ctx.fillRect(x, y, root.drawWidth, root.bar ? drawHeight : 1)
+//           ctx.fill();
+//           ctx.restore()
+
+
+           ctx.beginPath();
+           ctx.lineWidth = 1
+           ctx.strokeStyle = root.color
+           ctx.moveTo(canvas.width - root.scrollWidth, root.lastHeight).lineTo(canvas.width, currentHeight)
+           ctx.stroke()
+           ctx.restore()
+           root.lastHeight = currentHeight
+       }
+    }
+}
+
+
diff --git a/tests/controllers/qml/controls/ToggleButton.qml b/tests/controllers/qml/controls/ToggleButton.qml
new file mode 100644
index 0000000000..9ef54f5971
--- /dev/null
+++ b/tests/controllers/qml/controls/ToggleButton.qml
@@ -0,0 +1,43 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+Item {
+    id: root
+    width: size
+    height: size
+    property int size: 64
+    property int controlId: 0
+    property real value: 0
+    property color color: 'black'
+
+    Timer {
+        interval: 50; running: true; repeat: true
+        onTriggered: {
+            root.value = NewControllers.getValue(root.controlId);
+            canvas.requestPaint();
+        }
+    }
+
+    Canvas {
+       id: canvas
+       anchors.fill: parent
+       antialiasing: false
+
+       onPaint: {
+           var ctx = canvas.getContext('2d');
+           ctx.save();
+           ctx.beginPath();
+           ctx.clearRect(0, 0, width, height);
+           if (root.value > 0.0) {
+               ctx.fillStyle = root.color
+               ctx.fillRect(0, 0, canvas.width, canvas.height);
+           }
+           ctx.fill();
+           ctx.restore()
+       }
+    }
+}
+
+
diff --git a/tests/controllers/qml/xbox/DPad.qml b/tests/controllers/qml/xbox/DPad.qml
new file mode 100644
index 0000000000..8efe6c2b30
--- /dev/null
+++ b/tests/controllers/qml/xbox/DPad.qml
@@ -0,0 +1,43 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "./../controls"
+
+
+Item {
+    id: root
+    property int size: 64
+    width: size
+    height: size
+    property int spacer: size / 3
+    property var device
+    property color color: 'black'
+
+    ToggleButton {
+        controlId: device.Up
+        x: spacer
+        width: spacer; height: spacer
+    }
+
+    ToggleButton {
+        controlId: device.Left
+        y: spacer
+        width: spacer; height: spacer
+    }
+
+    ToggleButton {
+        controlId: device.Right
+        x: spacer * 2; y: spacer
+        width: spacer; height: spacer
+    }
+
+    ToggleButton {
+        controlId: device.Down
+        x: spacer; y: spacer * 2
+        width: spacer; height: spacer
+    }
+}
+
+
diff --git a/tests/controllers/qml/xbox/LeftAnalogStick.qml b/tests/controllers/qml/xbox/LeftAnalogStick.qml
new file mode 100644
index 0000000000..ed2689e7c8
--- /dev/null
+++ b/tests/controllers/qml/xbox/LeftAnalogStick.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "./../controls"
+
+Item {
+    id: root
+    property int size: 64
+    width: size
+    height: size
+    property var device
+
+    AnalogStick {
+        size: size
+        controlIds: [ device.LX, device.LY ]
+    }
+}
+
+
diff --git a/tests/controllers/qml/xbox/RightAnalogStick.qml b/tests/controllers/qml/xbox/RightAnalogStick.qml
new file mode 100644
index 0000000000..611b4d8f92
--- /dev/null
+++ b/tests/controllers/qml/xbox/RightAnalogStick.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "./../controls"
+
+Item {
+    id: root
+    property int size: 64
+    width: size
+    height: size
+    property var device
+
+    AnalogStick {
+        size: size
+        controlIds: [ device.RX, device.RY ]
+    }
+}
+
+
diff --git a/tests/controllers/qml/xbox/XboxButtons.qml b/tests/controllers/qml/xbox/XboxButtons.qml
new file mode 100644
index 0000000000..4a9e87799e
--- /dev/null
+++ b/tests/controllers/qml/xbox/XboxButtons.qml
@@ -0,0 +1,46 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "./../controls"
+
+Item {
+    id: root
+    property int size: 64
+    width: size
+    height: size
+    property int spacer: size / 3
+    property var device
+    property color color: 'black'
+
+    ToggleButton {
+        controlId: device.Y
+        x: spacer
+        width: spacer; height: spacer
+        color: 'yellow'
+    }
+
+    ToggleButton {
+        controlId: device.X
+        y: spacer
+        width: spacer; height: spacer
+        color: 'blue'
+    }
+
+    ToggleButton {
+        controlId: device.B
+        x: spacer * 2; y: spacer
+        width: spacer; height: spacer
+        color: 'red'
+    }
+
+    ToggleButton {
+        controlId: device.A
+        x: spacer; y: spacer * 2
+        width: spacer; height: spacer
+        color: 'green'
+    }
+}
+
+
diff --git a/tests/controllers/qml/xbox/xbox360-controller-md.png b/tests/controllers/qml/xbox/xbox360-controller-md.png
new file mode 100644
index 0000000000000000000000000000000000000000..bdb596455fc3bb066c70cc1f2cf989a8ee05e0e9
GIT binary patch
literal 29588
zcmXt<cQo7Y`~S67Rka&i?Y%cudy5@0YVW;@+M~3n5lW2OHG-H$Nl_H_*4UfaE7Xj=
z$M59xJ-?Hae{zzO`*pw0>waF>^ZB^q^>x*W2xtj#aBzq;HB>-2IFI;naBybu@o;c(
zzFB+F;o#ulIxFfZ;^5S$ytuV}ii3mm$Pc8hgi||Azm0=~!(^`k(!s$A;lRQ9@CgU!
z8V3jG!#^CH_d+;0J2p5t(qD0KsC@ET4P<a|aPaK3)KzdEu&;0J<xm_Poaa6oZ~bs^
zh<mW_M}6KE4%iO^d=#Dk|3Ywx8ko3naC~_*RTRNNbNhFJLG*#G%P%4-{k;62xNOjC
ze83gW&~W8~aPgEIP{(A8_RX}-1crMopB*)}owwguEIKUjhBM5&7j9J-o?IsFKX)EZ
z5)+js5FOVa*N?Zu(fq)qurZ6%I=1*PPkEm)ukz7n1soN&n-iHJu17|TMxB+{(>I}!
z-lQr9fR+Iy+V_v0FiR?aL?>h6h&mU5B?FkM!KT3hEuC;}K=HxB3I5VL0$IwWxB!Bu
zKo~g;6c2<ck>ZNc61g?e<_`VW5q?uqUA?elI0)TJR`_ZDl$RkzR8+L*&mUY-QPDqk
z!sFXwcpo1%qLPpfN_8_O6WgQP{w`v)Vzfj!<6oXfANEB7a8(T0C=*kMoZ|b|FYhA$
z`|m%g;A1v48f_llAAGzQbimUEET8ykA#i<j^G-US3qU|m{EUKv0zg4wD@Lmc1O2fR
zUOSTNviYLVrNT$anyT?-$O(z|#c42tO}PovLQMH6tBrX%pwAmoNn<W5q`1TRZ~9hN
zm_}qT=$#satKyhOI9L)`w*7N_q_o+{nHf@ELe!qe_54|XhjJ@)ui*s{Ou99NS<^t&
z{H0&1m5?=}lC0{~;b5;bxF=2EFPr#c4K6@&XJ=tomtq={ZE9*tOkCWy5%sy(?&qQx
z2M32wi$y7j8w3XcVdU*rDaKW*HO3_%xIP!)q`C^sqbiUEEl)lQqK{FE0>Zj&g!Dlm
zrFZXyvjnZn%F1HZ8N&fFO7&C9Y0e)t%O{c`5Me2)&-42nSp!AJRb$)!4O6vKZe!d2
z3%8e=7e*|pOsN{AiM<*ePzMp31{9xJO=emeIS(%{H!p9Ghs3hc#pEkqQ<Mi~)<Eys
z?o4)G-X9N%iMctTrsnfipRcQ{wrXl>pL^}NGJqZubd-rtOU6DMS7qE82u1E7sK-fx
z-r#Mu7r2i<DKXzh$a^7j)fs|6$%dZmo0%na+5ALrZK8rzN(?%#cX*wgo#AkJQDr4T
zVsCVpjY5ra-L_~Wsya;X>Mo+Jtjs|&cG0W6wl;Zg&P<zQ;#H*H;=AY!AdH%kvAnG<
zSD#De{d@7YK#Uq3EFvYP5g94pWkZ_S8{M<|+pVd1%5BT?UvI1fOfs4);pCG*)<CK@
z$Gf)0AQ=V_9Ke&2kds3jfLYQ}RgKxB8)$4qqJ3}gFFH9X6OU%?Q;No1HdJ#wB(x-Q
zGcY9E>SjN(-Fxdkc}Qq6k=pqCr$<FST04>w7Z?B0+`Q%^bzoYxn@m>iAc8zR6tc9m
zES+#QGc$AX@L*#|nHU@EIy@9|Ysxu3_T3A(kxBg;`ZB)wGgrcf?`z){dX$H;M4xDO
z(ygRT7o^;{YRpBfA<}(G;X(1w__kP){^#v&S0`uZ`uY7mRAXFOS=p}?_c)dWmUxxu
zu`z>)s{!lrxw!-;e3cS|G~`BfhU2!}OWa2pK=vD@CNq9o2;Rr84@ie@w<f!K)6w0t
z;}JV!GY)9ie!xKE^W35TmfAz%m6c|VMhHvP5q5k3VKC*5jW0huc}A>nViGsA3u|xB
zkB@&&@Ztsbi<1t+4kD!!uEk?qM?n_nuNH14(&>xGBYPl{I}6+2*n9|L9=BViARW@Y
zr8IwUn%Tg?1c>>e$w@#l*ZACAe@FPuca%rqFW1fq&GLz$b}J4}P8vqWzO9qhldHc@
zjbLNr;g>Yq>>P{oEf%^F&w+&*Lr$9I6Aiy%Anr6ITfB-AaYm}jkQc%b1d8ri{r3Gk
zX}&J!vS5+^=Ys>U>zf;4S_r+g|G#AN+E=`$+1jzGsbtb`-e|%=d-I5t|Nc{xVIbKW
z&bN1RiY+c?=^q$CQ@k+%ARR>htiMw#B8^h`5F|tVL9L|AMa)i!+Cja|xJnfcuI<la
zzoJ_^l3MloYRZTA0p(Hl{kuNpP|NU*g+Sll9$!gGN$G@ZPEO8jXQX^@Z*O3=Yv)VN
z@`=I0K_MxrzoVn1V=e%Q+Q&t&KBq?Hz25e98HjuBNGerBB^eF<w6htikV6SHZvC-R
z0)pdgj3o4}|FIK}?)tX(DNu@ja(WtMX$hHfQ!UabP3dd#-zK*XJ9^p{u)p>@>dEBf
z<ljPsA?jT;djbm-3jKjVyo^`DE~G7BpM^Z$=V0M=Y+M}L2#~M)j7gAxWO$gIIF3w}
ztlcW5*RIP!#8!x!vi*zutDKhZ%ps?EwUWy)x!VZ&XeNDQV>JT<GM)^#B^}-bmM)tw
zV`BzNMWk(kn9al09smUen!lD`DI}Yam>ByIGLb6O%@~@QB@8*`Ixjki&~&c~MRXRL
z@~Lq^Q~6n4-|L$VX5X-+S^4|r@1|w2Clud`WUM_ArzMJJ8f>d$->oez{Zv-QK}$<J
zx_dS_JS-w1@!wRH2{#YV+P|@q^vukI*&A2&=b6ixt#O!EQcB9i_;`2JlV_tYV*c;n
zADzuu+l$e<dU*VC5o1YU8FK-o^eGEbtH8l_O=k5dj~8}tB|`8wmqw!$a1ir49MGbQ
z3jDa9D6<+X(j;0!JQ^ArW?IPj<YYQktqw=3hLD7WT4120p`oFR810p6$&}lcCmlrX
zUEAVin4B0bk#SW<boAq3N1vJ*J}C0<yQm_4jR1453?Kmk!A6GX_I<nxOOOnMlarG^
zPllL;#Q5|yc0b2l(zUV#gvG>EJU#j2h+h?d`({%W7d*9x-_`HbczSv|y0oP0>dJkw
z6e<|dmao9{J6qJ*M>=0jT-?CIg0Ig~M^~2|qQ=d~_h;3|Mu>U?F=t%R;Gh}PV_Q~M
z_F1hYJu7S7M@pY3BavX{-#@M~m-Ng`N@7O2U##9g@;`7TT;4_0T6Yeg?apYjk*BAp
z>w`cdBQ;ESbObRzEf#<5ga@4(e=UYAJEt*<XAL0lrxlnKr06+vhl*!*>roy60N~q{
zo1@m^wm&&>9K5n}ZL~-k`=1v#SDU%sU$e7U|E99;EwzWL*MPi3yZX_-7Qcd0@9!g$
z8Rd07J^681Sy{u*QO*_M%HWR&M?qf;3d$-fKCi9Wp-?{;b^Q)>F#gg=v@h7$Sb(&o
zrCVG|N`nJhR8s@FySdmhp_qAY05}Sg@%Q%^5)%5LR+8Gt$Y#>DK&2@~?-Ul6=PwQE
zS^ZW~;i5P<ttMjfI}N!Z6Il&}bvrd8MdO2HhG%D~8B*dZD|rrDwix;c254TrLNB!V
z{qvV*2wHgr)Y3v+i&XC|AlhsoDJg!NgES10x9{kQpP@W5c};2$ha{KvEiK!b>ZPE_
zzxDj{x04^_r5D5H813!tXFVh;D=SA`#7>f}$)yTM`bI}dqnUjEjWU~=n+s=an}^fB
z$@GyLygJ$1-rnxAtN)w4+oJpKr|><}fxLV|lM7J%^XJ#`@$uk@zcqFTm3~t6|LvZU
z6T~>gg&7!-!NCb*V+Oyh1c!!(76O;UsUd0tmaQt0k@7V)HG9jQkzM|QZS^%zwE(Je
zmn%<zT3W9|PPyV$qU$=Y6FNHN0x(OEA*cD{T*vmWHww5P72Vw3>*x0q%e*#xUoUt`
zmXwrKfO*dM=hfZac_|awG3#c`Ef&f3^}-PkH_Olgw2O<&Z?~q$iRPMeg(+iW273W-
zC@3h7C*9kGO@2jpG07FCq@|I2NYLS=YN%MP%7mP9JtL<7jk&;X<7tR&ip=rf=H>-N
zlTC~g^HTVQWkJXe_i2bMW8|%{7b3Sk^ukVvx*1L6*M=YcVPwlbEX*QeedK-r$f7{*
zkcg;g&+II9G1vIyq>7f-3m6O*sJ$>00!2D}&C4q-Dfw7mFU-TkQ&Cf6X=Cu{7`X87
zA6LC;Qceyn0Rch4U^r*|3@G#Z_ivo1PoL&Vy^HSdR+76rH3Sem<<u)!XkI0mH~XHa
zTQ2iTCj45g-ZZH_^g`eoXIWF@`FB=URyOkI*zGc_(JCWE`@Vi0g#(2`aX%^&5D>U{
zc$C)GCU<vtze0l-@k@_r7#PYB2&%%7xSrK-4GkbGgAN)+QU`aHx*0=j>rU8&Jknb{
zt3`3Z{py!CN6+D*kU&=A%|RPhqOf;PH(y%y?ORl4-WGpK=$jYQ|Ne0?MqDxnwB@U?
zbQQ>kHph(Eh#rNsC#9qej9qJ8ZI<S~&eraKK>`O8eC$#%GNPcMph(Zmw3Ep7c87;^
zenC2Du#sPe$(5Ct)6mh`J2~OSC@BU9zh-A=_f1*?*>9g*QPa?*_IdLDL`hN*#At9p
zKNo*CtNG7G%&y67Z1*hD>@)8jap$t0wKZcvTfU1}f7Fv_Qel^enRzGtDS>ZZ7)M6R
zM_y$`atn4YAxTgm{AdN1R2v6}Pud*HIyyv@iH@jTL)vl`7DXn~-&-eSgm~x=sN!N4
zf)_99P5EX$B;Nih?M-O$KFK}dfmsZ+EH^F)FYGK(+SmK#-n`kSZb0!N9YD3B?EDv@
z?N+Z9Osl3qrly}4y{x}Deg{lUOla%rO^l9ycQjPsrh4b$L5P^=H~F65MoUA8_dKrW
zt2T$5yZa1%Ij2tevuDp*!mdP8WY4L~b@S&={jA37y-d0iR9J3zOgdTUiTyC`7fTs-
z?98$bUI@DK3C(x!gwbd;Zw{^28mp0F2EohN9^00JEH*WekrBKsE4`l$ZC(cAe*MVe
zdaoB0N15BPkd$tMp!Rz?2z$utFzjER+&!xR^Slo9^Lix$*B%{WxAbB^9tUuzYK+d#
z{&b80835i%=MxeU8JL;%ulB^jtE=;<wD2XXw^69Kt*xy;1NLd3K7EQkR>!2xc@;@<
z1*|)?#c0u(hr7;{F_(o?zfQEUmwFcv2D)8bzI)YW^CkS|d~u3`a*GB3@ljA-eEf5k
zRD5x9@!9=z3cY7u!}00kilsn+U$3hGPX+-*O|(vJ)|mDA(!!t9mgk#(50=QE8ZfgY
zHP)u4Ci6|sA++!5#l`wrNbu>HI(l3K(Y<?ijN~j_ISRs78yrwqoxVb(gNwI!c~euy
zOHN&n++F^9{-;$XB_9PlZ_`2#TDFn{zt?4;P;c{eIcXuW$H%^}OIHK_bA!bYU;w51
zX-K5zZG^m$kr9B3%6nUwh>%d|&6|P1j+0kFAketUTRMO9bbEr3nArF7&=#eKm=k^;
z*W(`$aJ<(z(jPT9ALGesT5p<Ec(>>5TXW_a5HyeHO2GPhcFIjWBO}9<FY{@pTEUfu
z{g!WwPun5@0MLK?wgpyi6wS196olR3x?jfxMn*<BY);b8iSA!TfBQ3j`gpF`IJj_j
z<1I@`IaxYwHGf@E{d5`-7POTgsKEjK(bQCfD#vORPsSQL%X-PUt8~6LK-1cqF<vEl
ze0-d!J$RFHIrpZ~kW`fn2GV@{Hal-+$6p#N0NeiL5VftTlh*mv|Clp?!s6npfq{~%
zKBl!EK7LMJPS7EzZ472>rR!sZ=_4*Nr*36Np_4Q7p!o-WJC1kuH$O>6Bp==sG(Paw
zBOAHIC8K4<X^B!~j`15C8-3q@nPN#`X=-Zvq{Lin+1Bi6-#|UjBhAN<;&*lISXosy
zBip3b>I0g<hs&j&z5>azz$vHg6a(kU3;+gjaC$}t@@z+zf#k`PC%+-m79dGRWRYCp
z&d<dWOu$!jc2)p^u&AiA7;UeIgrSK^9Ll3(-}N-)RrxZ86N>cN_?sFWIRTh7^xt?G
zp5%P^e7JI>l2g#Pa0uwSw<dod5z}v>IVKyK46^3J7@C;@{rp6+3c7zT{t60&6?b$L
zoNSF4T3ZXM_j`-a1HXrahQ{~W?YdcNdK+~vj|>hHMky!^OM<xozQW=#5ci9(y5-O+
z84bhgnhv;kjDybG8slnX-fV3(FT!1aX-y7j#grQ%-V?l!wpQYUEg4{MVpr3hw&pZg
zH6Hh8<4QMD;y5&gfg<U5l*i=s^e}G&Vrq*8dx>w~(oiNkb}bJ=M(k*0b-rzt4+h+-
zgYll-S3NxU<t8|fAW=qtd~xpT=2l!+m*OwoURM3g0KhFE;ACePeSRLGTOiXirHt#r
z+681I_xJbLH#ct+cq|;Ks^hCWGdcMe{g!}$V3Wdn0PU;7LiRWchan~I{yw7Cq9xj_
zrmVR+v!S8k71<Bz8M|~h4o&u8SP(2oCb@5&8H)V7`edAEe!;iH?~R$3?Gryb_CX3n
zZf^h5ZCeKY3FsmGq!T3A*;19~r$xvK)x=d)s4=#0GUMjuRj!*Eai3^jthE=Sc6hkI
zOT5=9k^lu=GQP}}Rv)~gm?*rrPg`Q}hpB(ZJan?)zc3+#+01}>nl`s<nefFVBz*6#
z-=AZaQ+ifscWme6qNkRZ^<)@2J$Hcw(R6fl_I7sBX=&sIVaJ*~J3FJhXIclGP1g-5
zkIAX2cc=dh9!KHG%F1G^I1v#gKR;38IQzcKPn%|>JQ)Ouy)2zwTN3kM)~YsRr8LlC
zP-H0|>A0L<BwLl!K_GC(w%)yQR#+gA9~PN)jcH*fGOM9%MDbnR=H`+h@~h#!pL^{F
zq!I6vpUjfn1`dXuJ#Yw5L@C)99UjUnde)lxheFg?&2!yV0jj8cpZnY3f{-0JzaXle
zAD1^<+ZWxR;b^F59L<D}`%$sAwRLp&Oy*=zR7^~)nmbu5M~VJTK+?x&B>n8376MfK
z{QUD0=8>-{wGNDUGN=h-jUtCZ@_wCLn;3Hem`i;m)yv8Z0Tz$IsMhS3>17b$M~AM<
zilyDKpwLvopM}H8hOJI3!Rfg<GwcnY*e-2t4bkdzHOHS`Sz+q3`I4ELIp2ybD=*(Z
zIN1Ch^+e`!<>P=ExT?!W$Y*a>n3j(2YREgH=jvqZb<iP`Q)95YEI_M%db_)Z;d7Jr
zbIF|`#2d8|vd-nsJqcj@tBkQIu1$UON`s2bj!xww(%+sYmZYj=P^5~10U4E`RcUdt
zoz{~UgiJMazU~AHrD<d|<w;aKvAuD9wwovYJ^{+9SDR}(1S>85G-DMCiH*e*u==GT
zM7<z9(NkmdT5Hd#YR{{@qT+LXy>QFf%)W@QF!K%DjD3>3o7>mCJO?*7H?2O`fu~wK
z+s($y8BF*;7rpTC@Pc;W<+GiU53vcKb<5Y|ISXt?3S_a}EJW?3`0QC`g6BNE-YZvA
zQ}cP3&6lI2BeWzymDEr2-ZI)>dZ@{LhD%V;I;+*Vn9ELxnv0KbV;rWn%TeiWt5yC9
z<&l}3OiWMQmlLKG&Gfg+bNT)p;p*y&N?$jIgJrJ&m3->4t+i<BZogP+^L$ZI^9(`Y
z_k|t<dO2sx$01oVg!VmlE15h1?zABCmYvG~bk#gdV**f7o%B*!V@1S)D;i|-q2DxC
zsm<SLw92Gz?JVSVz}{?YvbBy5QI?>!lbf5HmCvqIaoBDRVreeTdoy-qyF2EEn51MK
zx3NkkW@&D&|7g8W@@&5b%!BpDs;UxISQHHm#+-;3%S2>lb=b(?>PwrLrJjYf|6KIy
zUKPsL#;Y;rMZC?5I1OoE2pPg$3`C`YKxY=@@wk?jmMSc%ZIv&Yd+mxkI}5crSWOi3
zQ$ExNF-|WE+E&XXD>Z)4e3+aBFoqpIf<PbuO3K>3M3c{IC8^4hIXOAa8?7GMZ<!KU
zOzNz9-I{9QNpVd0$1-<a&lnfdx<s?JWzJ{qf8CwW`;IQ>JCS`Z{yRJSbs>x7o(n8j
znBpVFCrLSk_VwMZ(qLnGw#EY>@RxoikxSIJm^|jf21R0p{qJ9V<Eo7AZl%{_mTp4_
z{?hQOsy6q^_tb=V=a}V@-bAWLQW3Y8(NrySAV^NH$&Q+uTF}GY1vfW0O6WyJYika6
zqmP1&^YhvnJhE-B?jqFG)LcA0Ehp~(&mk)aT8lRl9H`?YA|etK6C0hGK`_;<=_<g%
zAR{AHCekmFRQR}Gv$MM#L<|fJqLwjP{5o*?<yy<OO`Ve`Q8)rwiAzgX<J)4Ys;XcU
z6Rhhrv+L;NqkmAw7w-@pe3jXE=fP3TWrvu@K70H7``X&thlf2Rh6V=pds3fzZ0F|Z
zUq{}{OifMEIo)aS#&SU8hlh2sg0LOio%!5YPcMc3AA)k%&CQLVZBf_H@5DGiI*jjP
zIZ|H!c9rCLjFQ&0)iV5ZF_#G^g{nbwL4SY$XBCzo2t>)u?(48iAqWIAyMOM;SQ{iW
zJUIz4sk4H$x4&vz)HO7GNtqY}hhvR1<Eo6Zva+`3@VB<M%omG+jN#$ox0ikLWtEi)
zWn~;ZJUko4A=%oo+1WH|YHHNf)CzF0@5=8eoo!+(OG_O+Jrea~`nP_yYi6jlW05hJ
z^uqhoa^JTzQw&N1S?hbKMtb>(F!RX*O4ZcP+ksA%swv-pqec7}zV_K8{;A(Ku)=KJ
z^6Z=(C4g!|LIO24H4`bm&&uyd=Leo8-+sp$m&8)Y@fPEIT@YG_pRt#e^z1DyvTW6I
zX8<d!st~Gn$7ZIUDi5H-)B!X;-bZa+-L<n2&GLyClp=hTFETPRr0A1%bY8WEU5Q}L
zsjg>?zwSuPpPJj*5)l%9K{`<Gw*~T+W^{Q-XxZDZ8`Iwx_xZ2<eiU(5WnJ$)Qos+1
z#$Ygg>qp;1FTB!_Z1tu|2?+$K;tXl67tspA!B+`#qWQX_GBQb4b$woliLo(7P0i;d
zvi{LkPZ-~oVLDeTz(pqD;si`dgM*-xCz0AmMM@#zXGbdZb>4W2Tg>!+F9~9}Y8nhd
zzVcK8d7PAq2Il686Wb1Uc6K@uUt88A{0>$u9$9$vs$B1>uqetfa6*wdlE&%prC&+s
zd#R4?`Hd*|H-ATY`1Yr#yRkZQYZ%!`ik9h+;-dPceO7*#oeMAcccs~>lm=g!;ROc-
zWUj5Psfx}c5-i&S$RKJojEv<iEx}suQE&2ff0)%QBr%i6f79m@%GM?%Bova6`0u5j
z%sZ_YYL))N5)!dfZoM87eyiP21NP^7;fCe<a4>+fT?u2#%nFrPb$!5v8X-$(lB3#9
z8_T)G7xi>0Y#eszZs7ss35tZOqHOjAfP4GNc`N6U`;y72spCZJ+h`97EoJ483t_9q
zN5LT1O!t{u17l+~o(#LNu)M{#z?b;AT>Sj(l!?L;5?GgP)#s~&2y(S2ZpJZHg_ae*
z6d{tGhtOc6cmb}OO3%tNw6f}`q{{h`uT*5(U^yR>*JJUh(<u7q1_w1Qt(}d{2jw{8
z#p#Q>SRE?9@`?CmOnH6%yP+qq@NqY|djh&VB<zK#e}<g#5D^iX2Y7(e8aLP^v$a)N
z$W#o{P4*KK6W_I10H~-0vrG9BiuWuKC=XLU%GbE)qdvwgWwO0yI|i;xfwP0S7Li-~
zhW{Rt{u5C)yG=*VW=VZSbBU3qvp2eYqNi2qhQ0^GA0Bz$6!y5aAC1GSt2fYD)|>l?
zWwoj)kdaaE$_kTN&3Wdlj*>AhhLmTDq_gdzl29o0-&u&<&7LSN9o?9VSW-#~EB<44
zc6Jq(RPh;^&g|@Lnvl@YF&8nct$lqRvKP?CC$Q~L+qpb)c`22jpP!VRJif4?jr9<g
zI{o;&ZG<$$XxVdz`deTiu6~eO%%n(7RaIhp=!KUVW<ZC6&j8R8u%ENA;KwhS1jcjX
z%>-vDmyGF~n-64JM`&^Z=F-mfqnSp>$CcQ~vA)&&!qUe9X&JCFm(OY?$8vs12N9JL
z11D!^B-%GUE6ZMtc6(>1+Y2#}Idv--J3da%z<-O`rWSC>iHrf#sk;xdQ1_9NDFFVW
z!JpKL8_QR$za!3s2zqZZwUw1?@bZGS#lYoWr$z%y%b`DiaO+Kzii?YbrwBKbJq5Cq
ztER}~RYrHu0000fAs)P{iWQ3dHnCk%TbpU}vvhlM-&lm2hQ>B5Ebj)>S@`i8i9il9
zhfxeaFYo$F*GH^bJY`}{MiArT<+apcr0<%sgt@R6qeY{D61k260h#(-pL*?5bB_c9
z?qM)kQc8-bgoK)*;Y1nzMHxZnWOO)Ysonja5DEHjR+Ah25214WTyyA+w<Cqep9`(1
zue1=g17#^hcLf-zwi7M-<_&MBqG&c@y=fAdCk6yB{r;V_YAOK)cW`owMWNm<g`EsJ
zE|(T_ktg<&O|20vXW+Ad_W4pBW>xZ!Fpb`r@m0pQfPK4%`#X!yi2M@ul=0Eg4>P-t
z4i32ax^caBischSyxk@s5KC5)E(bI{J^dS)$JNs_!#tY?qK2#Z+eHin2K$@aJ(aX8
zun?eHz8VfRUZ_wk8S}Y3wB_O93Bt5r{M+4~KaI#md1Mw9G3V)W^7Hd!C0>d?Ihcqy
z4ap`~m~wF7h5BvE_tU&;YRyOL-_A~PQIW0TpFqQ>Rc&o_HO8Uyn?W2<l<|b(^B5)O
zKwDI`81v=2(x(A*8skRq^*wybtp(qjCxeAD5jpQ7hPCB3e$Z$ViewW$dGdr_E-VQ3
z*sG=b@B6JcxO|aOb6;?dND|mTGx3nBKFWU`&3UF=<{V(K>0)}^nEdLEnzc2fKvrTx
z0zv=405=a03xI%(Am%Wn{e_z>e9A2tE)PWxy8jUltYn4#UKlnFm0|d=uP^whm&&m|
zp;y#m|0oT(Rly}bt{=J{lLOrPcW^>RT>gFD|A*K-H$OkRWvgJ_S^kE`(9jTUZ0yxP
zzz;?G?9Yj(A=&CWu6c}%j1uM4&1#I#5&QFq6cYK{FT5tTJ}bYYf(7{u0Pu>6Z;g#F
z>t@=xpWaL8e7CEo4i68XoSfX7Mek&+1+<~@3h5vl{^ud>07^;`S=phzJw71JS23+p
zsfa0G*Ip#s#nm+%(b{Or&kJ`9mB?*}*`K*#Bu~p9_%|C!?R2BQ{Y_1#LH6!f@IkrK
zS)!E`48oEJ3?JUa`8_0zkN1|JIW=Z0#}SW>jVZdiaudWnZZgv`Fd$P^RXrgf=!S5w
zPEG<04Gn#_b{s@rdnb{{<F5LA9Ulkf>2k)z#JCf{kq#oKXJ_yJjWX}->}*1ow?{ZH
zuh+ze&Ys?$M23BBAZMj|vv3>vPzenZ=^?T5w8b3IO;n|&ku!uHD#|_Fo;;mcgkbY;
zFi&q)T?f$CmbnF-1{T7RB#KfhQFIhxtpKN|ryut7)*V(^-zB)u)YeBn+y@Ijf!lg|
zdt>t1O<7r4OF?k)7?D9$;QW_N2;$|qGC4l3gwA&m9KewBtZh+OPmhE+?qim9M0Q$Q
z+S6sh1eV6e#=JLy$$neI$f(!>OOo;lO+UYr2CW&xT7y{V1A#IUV5b|!wRxCARbRDI
zsPFb>_-wn7wCR?<Y4txhN0ke1XX$%>J-I`9n|i+cme7j>^zGHjCne_K5ZS<9ZE1vs
zK;PN!%=5S&Z0jH<F3vCQ3F%uuJv}|dhERz4qac|IaHY`|?Ni0yyJsx;-O<%}C5l6V
z1zz6*|LS4B6<+A291kMRmVzU{pcJBSh_jCWDWCL+ogXX?pa-(D3ku3=YrT4`)}on&
zL`6ULt*<uCSV6-<T~)76?-(CWe(jJHa}|%e2#FsQAGa;{%mv^;k$)OT<OWhAZ|(DR
zIh&fAPLi97i=&s8tgz9~>SD2E?|Rmd)Asgu(T^Xe%_rS#UB@Bqx$pi}N%y6ulC8vk
z_K1DTEvta{F{-Oeac5^I=n9<$uc-LqUN>@Qz>|S(c1|bs{2uNu{LXfa){ZXI3JZZS
z{1_#yCyDed9;0>+y?^Xz`-}ihRPTG1p`UYED5ZZB&NGm6IlUAa<$2D3Yftgnj@VF<
zSf^*+g5mP{_T*YeX>{~s9v+^r+1YOc2xH^o;#F9F9sNi5qp1mbq$~MA4N*&GknPtJ
zZ2vT}rCg-H63}LHx8~Pk0X8ua<XLIU^^m!9;RnKgb6RU3Vjd=pLZ00LD0YIkv(>6M
zuaqjM++5w<y3xLi&3c}%ODXNtlj&1W6dyH=;g5C67598BbqX(i95Mb#ek_%_Y&kUU
z{^2B&Sy-0cIwg)F<n!3rSnzaJx-MJqj;B~Iiz!3Ov#bGe@9)zIO!%gJlnY)LPW0Ca
zsVrSE`vpP}95ChrE?@}1nP0a09-XDlK|@Ph+}LOsAqDd<E-q#XZh3IRRs6D!$TUl(
zQ2iNn_T*36#hA+@m4@fMLz@qr%dME#;2k<aPKesTk#gO*)7=c4Qx2&rSvxy2=ve+;
z)5VFZyg7mH=~bAP+#u2+?da$oL-?ry%I)wf%%asletUac^`fe}dL!x?!|(N@Z~9!u
zMxP84Wa{AXx2G5a#TBIYjBiEFR|O#?tV$F=`u7B<J8Gsi2>oei$E^i0qQ->(I7;CI
zn5VZR{Ko5^760*^-Lue#k;svv&THYg`yI}``>h92H*@CI-9;6=5cE)PZtj>{lP`Y!
zClI{!*RQ;Sf&!w#D~|-5v(wYR@4rm<9DkqRPl7;FHP|H94^94@o{9-%xljB7lHwMR
zaRFiEbu(JZ$~`iE7UY#$Spum**x^;!$$wff(Ae~J>;T%VVLC*JI=zRL(mu=%KWnW{
zXx8hKMyb6tQ1s#R4au+1K-q_BP$lkpQ&^($L?_FttJ<KVZGK|>LZ|&4+T!%&6>;CM
zilg3Sy{ajYwYA{G()!Vt0W>x*YHxpqm~U73i3LHV^VO=R)-G;LDE`o-^kwBUnDf&X
zNWYD<3S93sF!EZPjCTWQEl_bl<Nc-EizufD2MJ*?m{x7|3m%I9T0^uUZ9?J__7yei
zMWCWlH~pOlQ&VgfZfV*6+w_aETe}s8pMP!MvF9l-WumZ@)X!S9z+S+cD1{H(+uIPi
zTMEDZIq_dsf&?*2R*v&7cJ<Vhi7`G>d?wWz<r9QNMDNi36yw`sHy4<47|d~uni+~z
zVM#STj)L^s0RR9#X^38VBjI&q!t_|25;G}LrM_-tVRJtt-`hcbQX7-I@E^1f?3#Kf
zkY1_*$5xI=4UufC@9m3TS@XgCw|t6}E4fdbe*XN*s-BFcJ|?zH+uQTAvuUnm&O&5c
zEQld$%F_89`MQmuP3apdWq@j|+Q-rfNn9>cZ4qILx96ggtv$h9fZ~P*-=k0vsm9Rt
z&+~_COv^Dz#|Zl2{Ko$wB~q7XrSIt9OVjgVM1N&f6}ooKZ*1HD>yT4ONQlIqh0RM`
zcYl9>%e;N^Vy@zuU14fMi;l415|T(&HmGLD{k8j5R|Co;7u2KamMneIhKGlTWmRCX
zn8mih<;<60H>oyiXhGE<?Z`M?l9oITuWR80_xreiM6HhUhU7Jiu@8_#hgZ_}$=}Xj
zg~WBd{a*89yajxGZn1SU6#0>^`~AOBW`Y+lu6C;G@Z)+;nhmO^xBv+hdiJ=A3UxCt
z<N5d%W<s2=hRRDeRLDLmLgc@0P+^Ej@!6>s<!B+pyJtViG%k>!jWq6P%U73zmP|fq
zmUzwby-y=B&`I-@i&&}Gb-qe)@M~pd<&*z{+fn-1VEpv-RNunlS1rkRrJ`?TWwCx+
z!;1|Qf1R*pMr&*9#%%fc__z*tHs90mVMt45Wo2=7b<)z3)qj0`CXTWTgP`Y4aB%F{
z$~=CEB&u4&;TPmtz};)rUS3{t7X0sR_mA9S9v+!Qa<@Jfl%0@gp--sYxhxH8?2RBH
zjaT^@aVPDC$Zc+Je!A8^S85xh6gB1M=<n}8)*08$eSg0ANM=cje<<Ky(EA6-W@`N1
z&_G;aQrZCjZ9#p#u)p+TY{yDw)43`cWaz(xhoi`n{f85(A9uSC3hVM$k>B{a9j`xH
zuix*7CMNfEr;u@TaWO%WLQ+ycZMPbVqR}T;J}nmMSy^>eC|=mp%ex4<o4rPeOpG~s
zN?-8BVj#L17}8#lkdUBr<(03iF2kT+K7sU>ZA1;;-`${^+^HHH8?j(Pe0;p>a>96S
zAe=4)j%b*V%>RCEpAJm*sQ%1xB45(r|NcD^_bI(sXp-BMypneAw?p1qlKgyxjzCr}
z6+BXuCj)rk#?PF<vg-47ccu=TjZC_UW5EnKT$3`!Us@JZWDYS+&&Uv#lk51MK&pDV
zxV3JveQYD_9)!+TD+nr$g_0Ph4#bBAg(MZ+qk?ZrLELzFcpIjT5QR!A!NtPFqS0;c
zuodP6JsIFp4<|fiU5{JJ=aYqq=1)YZRZpS<)Av$6LpT^@X4YCXd_hFP#~u8>oi`fz
z$X#4q92-iS9YYW_SVnDYp~bJE$<V?gY<{uIBw@^jjWW@|!eVfA^a~#_nn_<@|M&gf
zjjN}pV?cnhZeRABSXo)w0m`t6ZGYU4U03<}exs5Rv<B-OB2_S^W0Kj<n^lULuAD?*
z&B|;Mrr5VLs-M(W?38%yA7c;SZA53@MWARgmtDQ-=UzLh{7C;fDgZ#}&6`BCn$3dH
zgCaQG)oSkf@6pjO^qZ+eP9`2iT1~%wTj;X{EORapQL8wNc?_y58}lT_?}9p?#3-#~
z_wBg2Hmsg-25o(0W*L(=`(<fqiTgO}ePq#c(vXwAhlhtI8S+2-pYr!#wl5-(r=gt=
zr*#jJxB`|6`rKni;6<VMhY#TK5O|I?-G12e_h2pQd?y<lg<+sI<^>D><IwZH)jd?>
zZPvrF_2r5D!--DKz?0FLnLfS9Yr`~T>20istLs|?5NCk->bL>LN0}J2x@y~TwMoYi
z@~<d(G3^Bb!Nycki{x7q6Dn3#)`iH2JFSS0DYp!*G7a6(NE=G)YrmvQzOs#%^cA5`
zV7~hp*?i+ZS)B(-f!3SPvz@l%;rW}_bOvW$2)Y{Mw$g7JO&ju88!xRQ@7@#QJ#ln&
zOvD=kUfxA?T&}%vb9dKdBmZ}HZA8&wST!XkDT%dR+}z#Klk_Euy(Ctiig3W}gopY`
zoY6QaE-Lc&;zCrIA~o`vr162=!>u1JE$y`DSr~UhVj>MSwM|G!$kJLCSHkBOdhWuw
z`^dY_+anlsAnM!iRtyt6XJI;`FhAeX*Ej9%=0fmVHci}FB>Nu*WBsnZY3jSJrC(WD
z*+%JK$k#%xGuWb+r1QwqSK!_}!h3?2@~4Hs{ZQwX<muU25ts*!)7r-v88)%w&z%7r
z-xgc-`P$zP#0CL;lqIF54h1MV#FBvw!`51F;_X3TX9*1Ei1H`M0QO#9N;Ne#HT)ye
zv*;?n8u`RQ`x<oA2{QA&seh06kxbZP<o8B-#iz$RK+K~@!v(U5##NThBI=5YkL>O3
zPtVQ_K%i)(gBiHG0fhzce%&0jxrouy($Qt-<P`t-;Xman40;I}$PzR(Hda$qd_>t8
zJIC`vJj3bq`s%T};HZJQV^L*yl3K~1{eY8Q>j&CKl(xP7dTbq+7V=P3RP;x4bN_Od
z7TaG~+SkCQ;Vaj!xquI8eFdfGomUv4={w=AlSIJ|CIA6{=-_y}gq)nNyZdhIjj!Zj
z_YMY=WgjH5vtKmk@)Of>^KXA2ogcW=Wg~=baXf;oG6&FW^0#ph3eL{ud|#rOd=6I>
z`}_MP`1L?J(aA|kq=~&!L5ECtcXy}f=K`oTB<A8}O5bar6&x50b|U9qe<Yr*eR_Tl
zva}>(xt!Q%TYDUuaQ|F9W7h;!TEEG3e;KKTIefa-1}znpj8-C{m-@aJVOEn_qMm|H
z>mrV!g;>4$=AX)h|7ZPOm>i?HxVV^@*owb28g|(PZqKM(yuaO&-?}_nr<eA3>6$!o
zDqYJc3_qs{Xv@#c%+wi>^z`!DTxjvb)|(~jDUWTIrj&LcPU|QSzUeb9_*=}>S(i69
zLb2(X;J@Cl<_mhj*JgSWf4URYO2UqMslY}?o*Dy}Eguc_^%Z0ooPB)0xX;v*CHA^_
zd3B(N8jY`SZmt3!4wjJ-ygygzv2M_IdEwHbMP+U(%Y$+eX_t+Dvk*%vKGGr0LxQ)D
z*0J$zwK1=ekx|8zn_WHiQBa<T1aIBXA<K8^5t2ee3g+f?D85tedm^V^vShIbZnv}R
zw~f({`C6rGt@4Usu$Y1ZhO+W<D*q4JZ6aJ5g9bbqQuM^APPQ1uL0Lv95=$DZm5^l(
zsB%DyT3bVgC|j8DXZHjArC(t=?5e6ne`yF1me#|rV!)OGTs;ff-rim<Ns(K-KHJ5H
z4zsgA;rjz(v_xh#nSNWtwj$YH4*B?xyBYtuE{*6+8%9RTW7;nm&d$zwb2hm%fZeM?
z@hWzU17E#A$DsYCHDRFKaYeNqEh#xU-N;CJ@6J1kl9H0!?ZSI*et!O4CofK@CYH}S
zDPg?BFQ0ggDH6`s&XWmF>+bI6hbt9<;1zH<bG9})L{0O5==b>ckA*>n1TrYgA6Upr
zwzgU=mB4#viQFO68e=h9BI3A@QBjYirKM*Zok{Mf2!ij>4|wencf8tWe3Vw<SK=xL
z*aC5G&MX+nEPFfVlI|h~<jKg%n&8M_&a4#Ih|U;tLOM16S$`L7^yAw%oZO*+`Dq9f
zJ{SzvH#Pk{vAuD7brN=k&N}Ho`3(tGhk*><zC{+uhDt0rHvuRpC^mdwN8HRWV}Y-F
z`@YP5Z9qz&tGD-7Rb5AMM@K~O`%WC7mKM#cSM0Qq+Fh-%#kS4Q#eYLF?dmM4-{5f9
ziL?)W|NVD~8j0X2&yk`hE(ltC&JcNfG{57WrOmOuzmHxFTt@HKb#kO?48G)rsP(`N
z%P*%99Zmcp|1?Q<hmKSwC9S{C6IeBX(~xYb8lQZmw0Sa=$|nrW%z#4FrFC^FCRX7Y
zE^KOkC;werVx8JrtM>jUBr-S)KIhkW5#;foe(iV&QIEQa`I^Q~ep}syfBVrN)cDo&
z56c&}B#_rPFj!xDb7;@4kzTG)FImIe%d4!YNHIABph{La(sy_$6doR43gQmfpHtP;
zL{`=YOXOlrh&-8KU)08xQOZfk3u7kI6|6zU&(EJb_xvp>?)CNcC0a0&TM!QP{%zlv
zeDwPXiN3XUO0QiD`nR(PO_&_xOs(a5qF~3$F?s;^aa8aGJ2&V$Rh?lqRh{9jA98E|
z&%(RZGLeYR!p%)5={IkLbBBK29uLsb0^Z2T3<^dZy&!%it)i&-=;OzaTp7T<fHzK!
z!HNsBz}6Ly0Q3w*DmK?zOfvGoZNAx2gl54@(%#<QcOya|3;J}?M(D5NU-uToQ^jxP
z<<F|7`X}_{+r0#TzNe~AP9`2MkR6b{SZLffQhciTt+TT*a5+3{d)qZwnoVcEvZ~6}
z)wQU!^ixhwPB5=SwsvfM{PR3rPD4XO|G>cYfHqAS=tX59kohU6Zr;kD_?Lm7O!>tN
zUcP*Z1E8Qd8j@W8?!7F>5PmvFRL`;KB`JS{8sXyShr!|T_4UHIieIW&7vk;1cuPa2
zXd!DSSBE!uY*0;9s~{KGZ!d&>y=mtASiuWaTBPCeohIeBS(}+=;r_)94L$wF*^IR{
z;!DYUifRjizBia(A3^Zaj*bXr(a|ir3M5if?*7s~BqYQku0d=+b<iK8COQK8;?}Fx
zR82Wx2#xJu_3=60&?Kgp`tCV+3t@pGg~Y_z`Xut-1SYepCm;T0O{uP$FeT@$ngW`e
z(?xVLBIb3lR&?oWPZK9+XBt{s7Fvj1BZ`Zc7rK6%hGg?XnCrII)zw)`;Ca5LY&7%E
zvJg-Y4SmC@n`eqhTixX`l`Bl?yvprd{T=mWmtnD^5_+w?osmc-=zG5RR)!(v_NHYa
zY-b?*1f*|aZcev+J&ll%kq&NSf}sEX;}RDacMzeOo1b^}@YtyDV`$qCI4<TIpPA|N
zjyR#)3wRTHzQ;@p5fK(v^z`IcD><sA-pWNfHTr(v>IlEV%3DlKOk#(MauKPltgOXP
zpGPHQ8t(4A()nHkeL6+@ql=4>A*XeCd4XBhh=oa4YtRvkNv#Ena(|t@s((MgZ+o1*
z*0L?OZ#{eF_nPrN9#SRq@oh5wYb8U&mu^iV1KzPi3<EYopC`6UD=P_NloXwvIdMqj
zZ-v?d_RX4Ue}e{xhmX%@tS6?XRPF6qiHL|kDKT?!a8%URE`b^U1+YMoqf=9=0$KlC
z!#l6aWz5!kioBDPQ>=0vv8@nwv;QrwqD??R=IW~LQqVf&{abzuNi4j5yGGUdB{9r1
zi%y4JpmSL;u=2fhzV9;|cuU16AWW%hs(5DiofQ4#%*+5pP@HxsQ`-+g3)i>d$*}YF
zC6DW2R{u&uL}UO4|4C(4uc)i*^N<kSZA*6>wQdi|aG$9yn%Q;r^n`u;_8~i)#>vU4
zqO!8vuKtT|`3&2qH#7!-?Sli3Z0+NI-a37KeV-G`6Jw^QwjI40+8n_TcNa%NGFVL?
zD4#%iWF}Gx9?#mR)M#P4-@oLmn;961y!SiDEO!=l6}!ug$yY~|PPnceNkw!PDlmQj
zMxAY3)oWL8gP0f2*7nsNTI2$QQh%LnjX<?If;UptHDDlZZS8MkE*q{#mzPplS2^7;
zIQZ(<DHA;LbaE2lg~-+C`ZVPRtF28gE@m0u7K1{er6BIg%F2y@A)U)3;TMYtPpgPr
z;iZX*2|_}`!#Vdl{+u+i_1qQ7!UyNIc>K5vnQqw|M(gi7e3bt)=J7s8ZEj8(jhT7_
z2%ehMS!MJjd1bwaE{}~Fh|vx;19&e>7=duGokVWEDWC5^eJ&!m?apn7ebH58-N?#H
z*V&mfUga?qsiLg>L?A2i{yqXb=TcJxD=JbPHrd5s%B!jpwK-S?Z7QbR_$XgcP*Cj6
zBS_k<^msD5(Z0fO-Xsn=m6Vm?!9bcq)Ef&eegFW#!|bAH{{vWPr6Ba+tw`jt+p<Ym
z_;z?h3t_71m-e<~+tDHGC{b!cEP!l%w_^eZgFS#E_n^Uj(pM>c-sX(cs^3e!8i?cU
z)lcbv<*K?gZTP-+a(3qC<%Na^0%2+W{Xl{jFOGs_2#JZYM7}BC<n;9T<m3+*uFpR{
zF~qBUEhykf)%bg_h}7guD9&S~j#oLz*=0NX0OkT{87qHg@3z>#BPTWBo|3YBlB8o*
z4qGjFIzK%%g_Nb95%uwF(lC-IkH=+5*;3Qp@%%0jjlQ@!3X;(x_Akg!R4Z8>EmD55
z1Bx&HtXp2v+M44aqA5iE2Xi4RE*_&)^fe14ibxb&sAyzIivfi_{9-gq#zyDnc%F$Y
z@&8=(s;sQc^w&+%v2yk}mZpThY8)Fb4gFHvQ8#ND>E9*A4Is$L$&re@|8@Hq#Un;b
zq*juenwq-LY>E{U-orLD<mXtm6T4r@+u?V-PlcrEiRp=-WoyTRdDzSQH8fZxB=0?6
zYX#Oz9|VdNbCDC`Q8llnJrtBQUT75`F<rb0OSrC-h&Wp9EOI`4eE*FuRB<~xoQIe9
z>Ucm9=^&CQk+rCe?WO4G+V*48=P9v=`pOCuaom#_rFSOM<ue~!UVF7zB%AW7iP5q%
zq(FhNO&Bg5%!5U6I4t^8=lkKcr|sj3?k)Srf=#`eY~)&ICXI@cGtWj!K(46yQyikH
zo6FO^<+bBvVWEJS&=-`_KZx*pqN)0fnWhrxUcKtYTr3-F-ON)~>vMe?*|HxgkiDXN
zN2I~R2vN(<%X6@^dyJUZVIx<BgYCp<$K0AuRJb#MWQn~RFpx`=89nhcBO@a)7;IB-
z+I-ua+DT$OvY?&R`;X4c*=ai73})-{>t$9TK=Fe%hw9du;Ok#o^A%uocUAs4-E!rU
zF(Em*j;3h#sfiAA*0h;~|AkT5_%kq2a$;h_*RuQ>L(qrVSUe92I*DAOk})aokaTU1
z=eUn?A3su4S8oY9<Dn9?+Ssk@#7=c!$NvlsKkAmxA0ylgGMJl4&8uJg@Z^^^UTBSH
z1G2RfMuzW{melpRsOd2db8moCIuHf&cw8XN*Sxxc2SDH<LC4C<iaof7`uyjk#l^%_
zY;Bo=Fp&qJY8-CE2pgLZiBy8*1TolZRZr#!*U{1OpMNWRRSZzW(Hf|wg=!C#>`Q*d
zN=-<Pk9&E&Tld;;lhCaxrzei2(S4@&m(M;<X;MOcy)ZF@j1<NjdhiIZ@6DL&DZT3(
z&8Xf-#Tp#BYrYrGL3b0Ugn8CXrcfxfVrqw<gds-WxUW6pPI}D6e+W5>c+WBB0zk~`
z*xTDLwVFMOW?J!WxjY^aeAi-u^$@UGD%i-V2+R|&!s70hQu;so!Z%7PYoHes`4Bps
z_gdN6nUh5B@*BNhW~Xj-e|Bf~I@(8ynug{rX`O%51@Gf7nw_e-priW8&%IzSMswZ4
zqcJM^;>L>?$&A6oB}*(1Itfs7Pl`B*!j6B&kkh*s3v*UefviL<k=i;N_!9K#4n2_d
zI`o_mJ3LnSa1yC&Z@(@x5d{D58?UXGWko}Sh*jvmI77%kX6$g`@qqPx+LLF*hrgeY
zc)V>Is8J*5hP$dWkum`Y$Wr>y$2<fvO2iS(rhEVZ;IH`4&Ez9BCW`z$3}$Pt$=!GH
zOoc~{X|JfYIEK}eQ<&~yw%V8!m-t7XP0+6wF-r0B|1zJthlOFu^n;eI0`XTPYTrO`
zp=|9W2&Cq<&Q>$XPwr~trG)@hO-)T8TKPLUt|Ak8ywCNi>wo|Khs~#62On<~i*La;
z^QyvcG<XwwdwXBpXCfV>LeKf+uaJ5|v=EuA4XC+se=zSCo~Y|ExjbFYE*t&iRzW_#
z(uxWVuXGmt$4CeAx|zh0Emms6G^E4ESK+qBj-u%V@aw>^uslpSCUkZ`z}GH0NJd+C
zuxNr-ziLy`6p3#5Lr$h59H;B9QZxQVo8xM}^UfUS{9v(dD$8c+N=HX$^(-X#?rdfT
z;8ySSKP-P}`Id;CojpB0eL<Y$x7(NEtmVju@H8Y_<hgUCnz{LW+WgJky|{RRPWi;(
z@Nj=NUZSwHbieg&ul35sP4Gd>Rz-F7uadfKHZVg<Tu~A8__mmij?RzfW~^~o-2Z6I
z1&}qMs;5VytgKuC=GocZ-O6}r<=ued%M!F!tD3@A2Gy<IiX6~YMCTp<-Q68_iimDH
z$+70o`a1#Zj=`$Bj#iJGW|(QCjgFq)$?zKt7Ubq90nR7mM}L^v#o8H)HO41;58Lvv
zq9R*V_%AC#<Er;MQSU`XMNMm_9nJGv7QOE8Iv*~QAdsVREkVz!O4{9cCVVV~Zr!QN
zld<+UmGwtc)1q<bUwy7WP3|);-rnjk5SGLu@{3`EY6@7kenL86+kUG_Un@dn8Y4aZ
z#@|%d+-XKX@z2G7dlRWzFda9Pd;-;<#1U7m0sFL#jo9H)uQO_oH>J-uvpR3t31Xrn
z&qwZ2{JlUo8y`RX9v~9!>&v+g6Ux^9(bV+r?)v?3p}d}@<)SCm%6zi6uI~8Qm|}Ri
zEOz>PXlMwrSOxk&MCV|!?K$pa|A2tvF&7CHz@(cvaoor3Y#Qv(C31V68u^2XkAm_J
z4!o8^F|tZUq|Zng(&?7HBujf?K{8mRuM%@6{?@d`A{nt9LDyuaV`*s_fea%~W8A<(
zE@<B)!Ta7$o0(cm#Dd;Vvt1)<`m`P8L0LDGIONm@>)rKjxy0I;*r9{{rkR7UsxJ)y
zShvs3EuoJgG)Xq}+(Uy9B#>3o)|NX_u7_o#Y!`F=TIdZ84G9SeneZROU@)+;alhQ~
z|51WaD3p!-`OeNxMNQ4(^ivL4Hn!u8Jm!pS*x4a+Z}{H5Dzr76U((zxA^*zaQ(fnM
zj#ieyk#pp^Gxj7_y-{Hy^Os)CIjJtCJuTA5Z@22)d*UFHT>*!$uBXUnnx}Zjt#r>T
z0#rjnLa-BoQzq7yqaWVOlHo?BrIA<uzqZaZ8m=!~<06QN=sjB0F}jF4h%(CPqW1`c
zA$pGzM1+Zm-a8Rx2%|(NB03Qf5oMyc=tR`qwf*l}_sjik&Ya`SK4<U!KF{-eD=L~i
z=JCgzk_!t9egDZTQoJ|E)T+ZdD0z6U{9E?+DsIjuMn-T=O>{PE<E(y}p;V4ec}0cE
zlbcn1m5+jgn4**tbp6_IMk#fztwHj_E~QI#auUxrW=YC!4Q$D%m&}NE;KBw~3osZ=
z>;3@$`EImAaeI4i$l0H*H5X|S5ipp+Re5U6PnQ%HMgadnBQ7+nprF8a$BQ&<h$SU)
zFm2kcG=Bm$hN{=n*48&NsxJ?j<m%NarB3Rv6XbAeyk+1!qN{L06W!gVDcn|9SS7aZ
zlc@)(L*gceO$F!-p|n^mws?Hqp)urquXn1^oh>i)l&{OyL(N$2O@wD}Z*Smy6upFY
zB^NN^T%N2hGk=L=>dv}_*gnKh@@vW2+uJi@J1ZyT&(T@*k>P_ve<ob7*H@3@jE;^5
zP8Rp3+N5D*j0y(<{<S8WgP=!OVXeOxp&#dW6XjJSyE+GjJG4X?ird;k)T~DXV8AT_
z_CmhCz7}4j_4W0^n-;jj($Z*Cfrbg?T22TA(z$s=6{l)ak1HqCERSqwNz-afG!^(f
zg>`gxax(RTLNH5&k%~x1$K{E<I0*j}ai*H-Ew3;3A`Hn-g+?59=GtbwN3S+^9k`Cg
z%F6KYYXbuV#=rSzAY`mCbu%-@>({Sa$Z<`xmeqJdQ$DU9U{E-tTdC7qs%3_5=yu0x
z!YHM#zCPllq@>`pX<TYgu$zW$2QGeem6Hx#U|dl%y=98|emlpw!VpSALh^pfl{n%7
zJH?yn(dh0+3wu%|Q4!R<IutP~YwPP%8wHl42AiUd)59^;ybUvQ1qNkOo(lxl)oFT=
zy2a;V*o5*ohzV=sf%5A8A3qof2?<YBeoEVmF@owxhE`o&9R(@Tva!}POAlR)akWe1
zQc9sg*?Uug^kJk}#;fxrEglUnDp1-oHy@a&Fp>6J>U$l?829?MfsIYa6T55tP^goW
zldY?(YyUt&pc^|ezC>1Be}BJ`QJPgsREj#6N0X(?YuaXNN&?00zz^;?d1kU3sCuTP
zeo$wLii$GD82iY~roNmQ?kzX27~4EbA4X1{mcM(KkHOq79q<44?c3}3WK=N(*46$N
z;#)a`U6D8T0$}Lx^#ccLD*DCw`Ol`Nri@N%jJZv(^4NZpeoI!Qd<FNYVu1h4RpJg&
z<h3|e>@t46L9r_Jlxu2DP0f?ACne0<MPnbHRPx6R3?N>qa#~mWs}cV*zI#$*SHoak
z?cZ~TLA<vVqBqC<soMP9!dwUulaYxv$IQKv${x0xtg@n^p%IahX?~k&nH4v^^|rY=
zXqr%{VgglOQQ_G#YY_sOW=%oVqZGcE6S&yfMMOkIuuy8Zm=%vZTME(Bp&it!vop1L
znnrD5thn#r6(zE`naQeU);zH9%F8*J$&!YVji-7I_YJ0&*4Ni*OOG+8fmAWiEh%kV
zbQvXXDN?-bu_M6078@J;-4gC8n?Jq|;pgY1is|!hYTz$3j5UP%4jO#5fIoV4cgoez
zy0Hj$E1`Kkpv`(=?{DlMvl?4M{A(Nu>T_Yf)G;a%z|xNXQKn9dzpy7Y=HxRi?_{7I
z{DCs~151rL#!IdWrpcM2ty5w^fFDk~g|+L-%*{=;I9h57KiuU?>L<iZ`Ex*1Vhy2i
zv5cATtBHfleMs!IpT2U5LBcTdz(~vZnQD<@>A0wzTwCFmiGb<DhYw9L-&_A}@JL{<
zd*>=7vhB!Tk5USsas{F}e9{NLk%TDO4QivIp;>ZI=KerE_fFP<gp(K_nu401Ll;8k
zDCv%o>?buyB+@OTlANEW(n%Zvp=o|h()NVFpnOn=J8kgEQ^%I)h!T#Z{>mRaHB$um
z*Tgc08ggpgc#8unRX7wOG|kI@_^B#0G8mH)%gx3#A0FzJ89LRQBaujAqDYGnDHo8H
zmy?S#$IN}F<%jDh$Ganu$O>{teIydO!s3{_oZ!>5xHsc9O?xwSa9OE((mgO@-A|bY
zUS}@IlN6%|se6L^%deREXY=UP$bW0fwfI^078ICmipJ8ztc_p#$eB>NKGg(@`Owgi
zEp}?(9i2r1r;O}+Hi6=1iW7suS|_6GkT6#A@CSHBV;{CkFG-^CTV{1kOePx+?!*@M
zO;ng1+%l|qKm&J`xbyJg!^YO!MrM7!eji>nPj@b+IKYDt%OIVdot5RlIEcQ8j=mY)
z{bS4TmFi*xoq#?K9~5e5XJ<EUX6DwI6%!K^96o4dCy{kCN~uxcS%7922?4%6cB-YJ
z=LDk%q51ahTfRXV5ZI}ysl9ktOa)ZMGG<aM+^1ZP$%2joVA*m{Q?G)t!wsXfwD5$F
zAC<nYi_;5R&unyOfMQ+0{eIO(RY;5ay%ZmrINXkn-?W8JtsE;kGzH2g(o9eYF)%ZW
z>9Ko+LV;wrtHhlQEh2py2Wpc7y*{g)#(~BJozj@z#oCvMUU4}&ZAV95nVi>|nVBs5
zn_5L<de+t>>*J-;o(rEE)X^l--Cmo*7~__$UJu!VF(<u>iGa2_2X7U3=SLc3pU#7W
zJ&V^hw6$;7n7*p25*k9@gTvu8^z@4!QV=1b)Q6eD@@xfqPUFGCg%GOv-o2o<zrpfi
z8KgW(8uAhq69`8~UirNE+FCIv6zcaWl7|?7czBqUoZNe5C<7zUj0c3w7cXA?sCO}u
zCvv%MiZSNl<xQJKn$Zp{dwrPQ4(?nN{Nf~DS6^Q+<^<OEAt53AI0D5tf{Yat(6g5F
z(0?ypmqB7{|A{ii*@-ZCNHPD|@;eM_W9Af>lN;vE3yxqXu4`y;dm7!MB9xZIUjjrf
zM^{%@&3H#w*H?M}&Q}2lL0`XSi|)D~J`&4VJ=s#p7GTzu7|c8!lJT^H5}vTKf*cqe
z+zWuU{<}OYHYkHP8bMRMMmyt3z6~L<e=kCtICURAx=R%KC_F_VmIGwki;9YVZ2A5C
z`LiJiViILtz1o++simW{U&MCtQk|=oyO%Of^<*zT?A7@C(%M+jov(&VZk={D6mhC)
zAwsFN0(^FoI1%4K75z_kH6BZSl;2SI9Y?a~v)tRwyq+pjyf+o#qKcs{;jDb&BNI2e
zs$6Ec;31W|g+DtxJAAg&5f6z42JytiL>B*?<KI)tj~{d91@GTfxLDWK;7Q6lz38`3
z1W}G``H;*PFNn-7EE<E<{kX0yIPU8KHpcIZ8*~Gs&jvu**4NkfdH18x!y-083l04;
zLpu?M@AdIkJV}rI{OF3t0tTh>AFy}EhaPgyxJi;lN1p9;g!P{AmF#oz>ST91iSPfJ
zc0WkUJGUQK(WI)dIbWb>ASGfA{rgCZXZ$tw#a4tt*(X<tMX#pR8RV3#4-!d)oyzuS
zufppeNHne_A|m=*{qLwl$imjfe88&ueY76rxpj4igH@FlPxrKY$8ZmtehgI)JN%+7
z`?WbjL8mvKMOKw3X&y)<VHcBOZS&3s1$r+#E;l<?+%H$$`|QP-6+*LDR#sS~UrZA!
zQix<|4XU>C<AOFZjj5-LQMc&7Y#yCJj%hi1ZuHoRe(voBl2h7XjsMOZT$zzT@lA+T
z<DIi)EuNSjI}pOL5t(vLJ)V0SpLf2*TWr7wQcV3xyp18hC%hmuBv2@nm?%;zM<*yK
zh=GNrq`W-#<HwJ_A@i|?fM681M<3SJ%NC|3k+s~Hz?m)M3(a$BAuAqtZnYN1U@&O;
zdzvK1(3HZqww%Jk!q)K+T1X0FU~tg0$@0T2px;o!J^OFrNj9tEwi%+8?)u2g){<*W
zWG!DD<5sKxomStB?*8`e+wKBdc#g87lPT^+W+qca7rRgzx~4`HX!kNXZ(Cb~t+pRk
zPY&WPW^sFL{}#iFTUzc!DRqTkzY*|f%F%ylW5Z9aKu<(eR8doNun<kJNn$L*0PqXt
z<>f3Fe`ZOFPuHlass9Gc2R(hNQDRV6S0}K01K~UGD>IuJqFxB0B8wKy8rDn|*C-u7
zKb`DYiB>qjTc8IBAlAWq@bZd^o%9>prQ`Y*7MfgC2^Ef(O<qx&X+o4SDk53K>BB2V
zao#*hk6c|}ff(QUgv|vl7}W)O#P#OG1<KLjG7mz?zEegibuBFc>=ycuf|b~k3{}h<
zozer!7MBM!@PWa>z{``>z||c8^z7^<`i{SZSS<ERRdsN1*l$3TP(>*z%H&vkUvTx`
zXh<epJwChI<A+{s+EB;$)=Y1~&VFOXB_!tbCyi;~mB#$St-JVS(N|%2JqVz3L`Fse
z^N!u|_Uvz5M_zNYjH|?*o}QkAxuv}TOC16>R@S#zY|`AEb*r^-lO@^JJ_wA-#oqW;
zlP{BuDTt^pTic+Z%;x51!Z7+z+^S~-Dg2hL0iM&o-)A+5BRc!~h<Do0gg|xF=TDY<
zd;i5TPT0a?-Xq;oD0%{AHGW)dz;_<1Ko<Qtw}U5Z`0LbEKkx`wSvDyNr4@bnknWfl
zk_vJlN4u^J2G?H}6x<!jmhS%bEB`lta(Q_91ZoI*&#%QQl<!u=1F?)xJIB-{QR=1R
zwd!4Q&W?{Ca{_tD$<<Y*%y6X#m7@=#IXpbHmB<SGGv!Es9-`58x>gjw8vy$~h2;&?
zce}1g;n8FnyxVo-@bK`>Fj6#Y7(B7C;~8&pNy)*GKi_{gKr^(chzab$bPwWm^U-Yk
zEw~G^ywPZ-g8YVtRL9)F7pJGEEen}Y8j`{>2#}H5gEMMsMD1#Rw0hgPGOxt8vlBCr
z5}{BiDW5e83<kpx_c@sBjOZ>gKA?8sUu!>`-4XIo6XY}P_}e3_2Tl1lIk_r4@`QsJ
zf8HZ~RN-H?_v#2GSu`a<cwr&OYc_?E#`Yt@STwq<veGh%O%rh>nl=3D^=q${Ax1EL
zHMPI7u3iP{+|#upf2%2KMG6Xn@BrAz(h}G8>(^hsdiCqzWQ99I^Cr%~!K%#~%oO$Y
z^#JN)X2xeC(3JJr9ZN|NZY!eh?k<e`cX>?zd`$pqYVg1^Fi@H-nlmi?`!(lGAhTuM
zb7Wv;<;l_EB*sT#Gpt(t_Wmvc77|D4*UIPiVljiu3qUDvY028&c9YiCFEcbSGwW9-
zm;2Nna`weZ+<&V+`8j{uU;?6qIJ%nv|61YLTI<aHvQq~|#cN0`W1MQFQbFIX37$kP
zo~D33j_Qs}88B)u8{VZ!u*Or9MK^}rZOnPTBs+z5B%hd=@bUBWn*T`n_U&8ZC?(*@
z+unAIjg5Wx?j88KK7Ld}Xln8a2xPCmiB~Ps($*IJj|6yeaq(f+t!ex{qU7Ve2iS^`
zvB?Ycj?E5FdTpO*!s*dyG=1DyVna&9=%|PUeF`E9QNlq%Txt2<tI1NH+wpqevRAqm
z56FU8SlkH-3Gwmu6_uCQfza5wy1uHZ5e2rcCbEpf)Vwps7?lV^D7UU-GJ@N<A|*DK
z<j?l3ri%-|MAj3vZw)_5w*9W*M${wfO?BoAf#flUsy~r{-+6wRZz@0sP(dK;KDp@-
z5RksN=lQm@^k#H7SCWQ7*|&&b<q`wFYOf3}9)zZ5S$R2t7bGT9`N-s)%bi4vjp`^<
z5ctT<7OoqiNm55wvn2gTv7+h`g~k<p!osD6g%Lh7+F}`845U<~L@_EHw-6KWCQ#B{
zQ>gmF@pXF_DPe=aZGu;-oS_|gmO_&5el_oG;h+Fx6)IB`qpnnB2o+_DV~A6QLZPWc
zky-p&-kPGT{n+t@au2B-ou=f*PxxJlGI*<l_O2}6Q4rnS7RnqQHI4-K46PA#k2%F*
z5~75dD6&yNKap2A7j`Ec66+++BpvE0bc=vLM<+?0>&v>&iDYmtEU<xq54oEfK^v#K
zZ1fHmxW6<-l8oSnrl1saE(s%Oi3yhC4wm|p94kZ^NN*|Kp(8ei&?IW+F7+qzjv7A_
zVMx!($yv=b_d$HHEKRvOp7bzCE<xSi89eTPFD`@09)Z&^=jf=(<mA#z$?3i?Cdxih
zeFM&g5@))-?h|B<`U&ew{3d|A;MC29S;Www>nm+F<PNu2nl-@3Sl<~!y_%T!0xU0Q
zVO=CdkxO1p!RpFa-y5Y=laK1gzoiMqO9TI`MVxhYo(a86u5DEJeDL@;Sm3_vt>R`=
z?{V*yo2jF#gS>L9{Yj3~`D0EizA}k~{Aq)LU4u#q++XU)ro03)7-tHizs9uI)&XnQ
zH13@XzT$?D3`@U#qP^J7A<D`Cm<~@;|1D#10fgR<Yv@c($DEQ4p(*iQ14+E24T>1!
zq<(w#((%r0s(u5P>R^`2mgo|y8A<5gg|QsI+fm_Ahx(2@4GAGM1@YQ1kJnTtM+nEa
zO7?&%yW}}<Qh%SqlxwP`5U<Ta08B`Yu6NP%WH@yg>7ek@D=*}pBu>+yx~J)%aMaf|
zADLIGMKgTxjYdch(OmiarJ0=pT(>__1bhAj>LvkxCv(>TuiOr-_|Il%t5DCFQ?d$&
zB2UuY1odCXXE7=qwRvK6Xi9XCz2X28YmYUH=we^@$+Q&WZS+lRS37lGmt74#woIkE
zT{akBhnx9l0!^t^*RYD@qI?J()g*^Oa!heVN&Q@sKfkT}q-*gEA@31IUW-x+H^-<}
zOcai<uN+Ne%jyJ*PD>L<JTu3n^2ZN=akY<WYmolhojbT}|A-_?>64x4jGJWmgJ(|S
zvACTyS>@4@kwh(?<&YAI<3vKv3;tLRx5g|jo_o44C2EC!+8t*=Vrl5;22xY)FEkWL
zq9QgnP=?Tn)(b(pTXblL+&7G*M5IL52?+^*Z28rh3;qWuHOHim+MLdvhjd)LA#mwR
z7Ga88F(Gbb^u{C@LZfgyj!5K-vNFD4c{c0nG$--c(N#{Wn0(`kn*{g)FxDp2@87=#
z$_!DtQ8lwq8JcIe9sbGRzt8=zkxLATHKS{Cl|Um(3jZ@H2&Hv9iQ6?!0|exUDOU*u
z0wI#2^}|(S2#JLqCCkeS+gZe$V|WtO@xmx7wRn`FDIe`>mW031amE<(B;93-TkvX1
z&&&jQ+KdcFjs#-)y!Zgv$l;-QnIYnj?5yB-Pl+t6UD>jSe=IG9=slDJ4uj-~BEwxJ
z(AL$Zm6fktCD0S79wfG4a<gW7i-wjK1avhtZjwbSSGBjy!Y_4HD<%>VC2p-R@uWrg
z*_PXV)l;A0b{vC)vkMCD^6>KR1;CznKSDY>-i+@4dvO^!vfDIs+peBz<#q2&&+`ZD
zorj0w9^GTrS5+(;div{n#>Ov(kwx#`y*xb)%FN7!@bfEUj8`#L+N!aBY3CKtXDS?u
z90`5Bwok5+L;=pjr%wd4v$LdRWD8zRyC=azLqosz0_<-|jh=GOp3QrtXJjxEDB3zX
zy(}!`_%CXn-`1AX+${6+=g)T-47_@BRj^81C6fv%mT?ClFZ=ApP8ce+RSNXpAW9hi
zTaXnL+=a1{-@A7Y@U=WW110G7X*9T~q;hoLzJ04#F#){b($f9)E|c%7t5?4iD2v~}
zzZ~U~q*pOfJie|#Vhm$VON&2n6-ZRD_wh+SSREb5;o=9E?R<QaGcqy)MfC$4QZ0ql
z#4^C2_x3z1jrny-lg7sMneN;H$hM=Sqg%!T2bFAvkbwy9v-c5Q?B*B=+)tNCeF)9p
zi%=oU4-ZUC=&h^Mwzu6Zg(eGMFTtj7^mnWspE-mreELKHV(@cMcS<TNN&C(yCGq>;
zAW94*3HX`GiVVuOGmYL3t5OiuP6@QNwE<HmSf2REFtV|wZLYZ!sTNUUj5TF)R15UJ
zeEITBwdihAKY+9drE$`shtW<r6b%U>63f_Tt*fma7kq$VWL)>jEGW2ZP?pSWk)qDE
za$m^Q{c~@x=as>K@!*7kjcs*zzMB~qpht%3!-lGN^(3e-y|9HB>7UrG61s#?UagfT
zZNi3^2h%`W9gFquW`(RT{M_;*P|Pnc2XF+Tw4&Nt;D6BKp*F{)MnvF$L)|YkjLpbk
z#1F^2xVTW^prnc+xPJY*J=QE4QNk=L91{I$YerZy?DbXZR<BB&?<UII`<{`J(YHy!
zszmT4C74`rBmiL2l>m{g!)sklAEgvNy4t<&!$FL1UF|>ncIH3w9@5b<BPXY4aZf}{
z>|-Rkyt=Qi@1>c!S~2O%0NABk>DkPA6>Kw7si1RlZ?~T}@5}VGW>}a4Se#SL1hFqq
zN;8wG=ogoj#eDpzghHXf0;#Uf@HM|!*6^B-3@K4JKK%n|%6~yt`_+!oRZeCy>MJax
zmX1!LA(RrHpvBWYG(_6n-R*^V<pa}fqFYg|;!V;R7#Mh0R+eCs8o>^Jv+ns$Bo;is
z4i4OKINTItEKU7b$RItOCY}d#s<Ar17m%Kl)3fC_j>GA4Bmlpiseq~!GY<pl+;<-s
z4awNlRLuA~7gfwJzZNhe)m}4q*@`T|U0B{&f9$uXG7?JTOhFWkukS~;y#8+=(s4Gs
zv$nJ27!Z(NQ&Tg2X{o_nOuY5^vuZ3F?d;@~UtS&?8%qM^=dYP^Wr+I>XWQ@jf~u#X
zrytBC?E45_-kB=%9_b!ZTH;LHbm#<iuD)e2uepVpnNO|~{1!UU6p|>VaMdEkiirU}
zaf9d0J$7BL5`%%y3_4d3pUrCfQe!!_N(^crG+7D(wz5nPDLMH)85yWW%DsE{iVez)
z6mAqk7LI}drqapHjfaBxmye9J=K{g<^76^*hC~LhX_;ZHlX&a|YIb9>ne&bDHCY*%
zzYAz#1{Rj(uO*s|%N2=GCPQOmyBbqqH}LiK1q*m9D?k!v#>h#|`^$|uNZ(CI+sn;n
zpYevgJ}lCMEaeR=6^-SOIYA&0a1%JyUiTTNkFVQ%c)Z!1tiC5A(s{Hw$;ise!xWd;
zZ*P1gx9*d<z3mn(&vqpO4#rUP{=hoMyJoDI$$bq;(&EuC8Fx<Xw+}^pAX6v9VI4=k
zF3$sJ+$2q^EX|TkHH=lAo%!nP>wnL-q*=B2jm^wxIXH0l^z?W|MQn8<(O<UMiSdKl
zSlg_1H8gJCAZO)bCc7slrsU|zo0F4sczEcs^|Ssy=2x?&(8qZZK|#S<Bmdt&L|>^s
zwyyjBjLS4biztN#E?B~{WOj!nD&hfqXK7w2LRXg@yqU?#t2YD%iShkftQxX2v$CAs
z+}>g^alo}iLb5N%DT#NLGg|HpzYeZXjV&a(!lWAb@x1pI;LR;98M(RE6B{<-Ow0Sr
zgC8t~49aM%tJB=W&Zd)7Q&&tVC!ZOVwNgf>^xO9>du__3e3+&n2>)N7<>}cOBO~J@
z4-bzXVZ1n1Wg{cn7Qd~+l9DLpXtEl|QP%Q`iW+l_>}RhgYP~W;pxRhlk0fxaefSTm
z8`bJT6{BJtY~|gQ-KxZh?ja_?2gZ%sc#+Y8g!AHZ6^^^rUzg18fcNI<dg-gUxUspp
z_Iy;Q0VD;1a&d8XaaqiLx;=k+w&OUOEB9mT&-pETG$ld!!h#*^)8C?hwx)Z#B5z2C
zoQm6oo^VG-Mpo2j^YZZQ2DR<ue~u)V@9T=ZaS)0z$~Ug)U-o*(k?^uLBFS-Co!hop
za(8HmG)>6LJi%1sVMl5z9msy_WJ`5jUYymKV@~LMC6o*Fz&~_LxV3Yx?WyyVC(GDT
z`J$qt$e5TI+Atj$>*_!X|31`3ih1Qn&Eu1Z>-;Je6Lat17vp_CkF53LT0Nz=3GOP<
zOk1LTn__7A1qC*!dta2v_tuKyz0Uu7#>U3(FLn&;ml@X8)#+JTX<Jy_0c1+Y(cBU&
z*1N~k_rDTx(@_u?6)+X|%PyKcqjBNYy?HRqYy9F0sHKx9uWe(K*Gkh)rB*)Xv{Vqy
zy0Fxr1lUq5D=V$kA<>V-nF9aLN0(Jp6g4$v*!(-4tZQt%Co9`hcmdb9_wg~z9s6V_
z3MiS1ii(#f7DO8FldC%}Pb~`cUM40cV&vaGiNE4X0hp$YtnB*Q+8giPRB(GtOnRwx
zVO^Wm9U}*$3c9|&zM)L*%9I4xvW7oz&$a-Y-NDSq`Q2D$_VZAMDOb9yf`!+Bp>-V{
z2Qj{UUc3rNI5b0R#6{(eqvwihReW3=$Y%!2;{=b#*L`N5?zDl5M(f`N^zYdgNq3{!
zyXjgy;9B8u!ikBA;KMPsY=yAUG1PmssJJ+n$+Ny?FW^!E!#l6rK~Dpk=NJeGy=rVB
z&j*(ai;5n@?HnYsnvUn52CkQ+1)Q#z@(Bx%#vie~Fen4)HmNHYoN7^mW}49aQILC6
zH6-?Luspztu@e`MJLiU;Iz##S4{FRc^FbKrjPAjsM~|$h=oM+;GBPrM|1QP@w%Gpi
zVC}e%G?bq|@N~U2@L*Una3#YLA|y0|o?v-3<%&Gso=r|mOVTL?&#31MumoK_C>V1B
zQ^~x?(!=EycI}(@GDrtj^TI9#6)E;3e5nm?S9q_Ec&-dFo}QgG`EC6a91c;Wcvo4u
zH07ALJS>SzHVNOKIdKwaLb<q<m6zkYJs0~M+)itzndszPZ$9HD85I@vW9tt_zT`<b
zJMqxS$eem{*ml$EoB@O;uq!i?ow(S550qd4z5mM>3M(tCMpC+OPU6hcUe7^si|zc^
z4Q9C@@tx}C!8Z#H8=ISy@Pr5KokK%IvAKeLQN6YzzxDzkQ0M@fPBK@m0~b~#^xb<@
z?l{%Dx)+IECPbguP0Y=W^z{*&R9m-|n3heTKqlRLRIc~9{aDU#XD-KvuvIewDNtWu
zUp(&Ibj{7W?)!_n#PTsGz4qOYx7-=yRELlU#%z<RoWO3B2<khQO<wSkIhz>M*{3^g
zV6?Peo^F2o_HF6HDDb^G#?aW9D!%t-l#&aTVD+S?nc0*TODXsA22<SUR&tl^eD%}`
zRL@5H+4f=!?m`H6vF*Q%BnaHc`{619>devIq_=NloVtis(BFUm7APqxF%?L~$ma+u
zQV_f?E#-qi9-MsD6kZN7o#`X`w?8Pn>};#1)*CBWu@m<140!&%R)4_)SL_<6`S|$m
zGLu!8@4e(QXNn`r8&!kD3F*+wRlz#Eyu5r+s1le^+fxRYw^3bG@Pvca(Su=0Twk2F
z3Dj8OZx?yMdP&-Lkb-h<2_?a`=x#+bGsZC|n$q#6jW;*y&9xykh2`ZNRhGWF+1afL
zM!Od~VKzF$O%{X|SZorwQ>0{MRX@5yciN8kk1ywNi#_x<#Q>VEdv{bqje-CamxP3P
zsA5F!->-*`W#;6-DF~DbD13c=*N#px@+I1wX@jDoqKc0na}I?4CI2^XA(V#x`t>VD
zzDls5s3>y0RCgSQ>nQv}*zcG^UjeItQxFUc4%V0osBlnP3Qd-)@YA6m)tm2~1b_Sf
zy>J56c$zE`<tj1w=@Y?|Cr=>%)%7ccK6H#z5`=F~Ru86dRa><*6iQV9rY~@iweEhr
zb>g%Ht57X7-2W9xzW>vu+H-$NgPE*1_W0-|*s{ehuAty9z!6i$e6p%x%DIw<)3taE
zRg3hu54{@MV<vz$U}M8JJ3Gr?TL~&sz^m7Okh8NSSOIfU#TXy#c9SQmbM+yy+43Pl
zJx$Td%F6p;n?5q_7hCSQy$gn~>*80a*GR+$qrdDhmp@gaX~^IC=vS{_i;0N5FVFw7
z6TB)Lc;jjAG_Z^PcpRUgQ@R(_mM!g#G%{i>mOv3jhA;NU<7!e<ze&&9ip)?5q#&Zq
zF+4dsxV;?IYOImJzoeX;Tq6y?A_WkQbmdRDggegn%eDT(0#mzfMRq??>r%w2YH(3y
z%lf<Z6yAryUQM8uKSte3*Ww{#g?*SP#okrF4b$Qok0WYD)idSjsEK9FY&@RcrA|Y9
z3V^Ymo}L;nHCDWP_iH|yZ6(FTy5Q|wWQ8v0D9ej}`-PL$ytF}=YSp@+r%y#Qw1O{B
zR!s%ynC{%!QIF(gjejhW<?cf<iK=HHC0f|~%VP0Kmx3VZ=~G~k_iVEC@%OJ*&#x#i
z57_IWKe;^a(0%xD+&E7)S2j5!0w3J#H;9s@^v;x*#xT~>wzeEgq26A$uvcSF#jUO9
zulLo^h3Xs$`OVEtcqyO){erfX^tX61q5!CYi;Ih(bPrE8GBTnal|K^zhASma&B3b^
zWPkjqWF2y3R68ZmWceCRFI;6>2j1ZQ_6tSv@`*0hvwVdqgUc^_>}vT{2_+N7+pKq3
z9Ib9fbgr#II!=b&jV*nzxzXUBZj_b&ojY#ty}UTvF^xv%Zoxf0MXOu)V+9QPX)&e(
zpN}>t$58b^#RO1G8d};}%298gBtR3rs{(b-ud-@U6-sM)%&MbE!NA0{AlY$pJ2EoT
zvOSowtYivs+4nzD>+XKO;||P$!7=HuEQFa^hO2Ye0Nf=wnE8WfRM5YRV=#&E2?@=O
z6>@{3I>S{j3j9lUQ$j+*VuP|fZJRsKBD^Jg&3t`)D&INUIyi90D_lysx9$-g&-&Z6
zpLyj97L=DG8tRZpBm*<E<ydH<(={L+$XeHNb=8_<7)XimXgnU5D3y-)zdp`+#bpfc
z!){O;cw?AWf(6%Hz~b%KEV6!T#QwQCnpRdU;7tikSMMq-E%!nf7Z(A6R6^qO4YuHC
zy^B*dSOR^Tn?#WZnT?PuA<z&?dvS3Ap^0U&YPWOCHqzB4XJKLCN3jUUOn^m1B)R-c
zbIjbv!~P@yqw)2<AESbQg>p9^3oX!lslpMiQwkbR#Ky+5OdW`14U373f12-(UbcO*
zY~kK^l&Vx<i$alf;B@u%$BfxlGt=)lPE1d0nwU(+D$#S*1RV@Z9@wQgPV1YRss{#2
z$EZY<m6g$=jYSx^64di2Hyy@)YB)F-ujh}hF3vsOftQY73!@Ntroz$H*@;I>OKTBQ
z=^`WDU%RohQ`*syr^4Ymc)^u70mP!c#onv07Hv#57N7$$C8I*x_+I~FCk@}3dUHYG
zWGt<(EmAFy=FUizjj1rH_BuUWr!AfCWK*UG_jbGE-(~A4bhH6ZK>!xFdFTCkZw8kE
zrZFQu-E^#dadGiwp}GK_G7TIoLzu~WU%wpR4}bw&{oF#@c`_XhP5$KO&FJp6qf?f9
zxUIFdU;Z6uEFmEw{B#xN<<Q)~6~^}CwjIyIwXt)QZSIqJrGj5y3Y2TVRI1kT@bJ9s
zvGe-zm0B03=<K}SK!*u{$qRq9Qlb;6H`j*43GdyzC(F}i0&Q>nN+l|yFbfE(vVMfz
zqqEUU1;6?dIG4PnrRN6LeX5*n@<w@Y=<rhA1gC`Z^EZ|_-HdqFyVzw{Bd}XGnssAh
zVqy%33oGJ2lxUFgYGU5n+5*)RemedX1X$e(w;fV}3GWBiar8C$e4qDmfgVIE=nxXY
z&QAQXTtKjTaxm%^{Ze+1V_t}#MQkc0_QR~(pY2(+YEi~<V_<}lwY3m^OXKv`w41q9
zW5{`$O=$nGU%z6ZQHY~TogA4Sm+H1uUHcJikv=qqSuThsN-3P3xb=AMDL)-Xg##p=
zJQf3kPS;DzDl2CsMw{zo7~*@K-Q28qj{_qd#F@&<%DR@lp0sfI8sHw3(N3a%_Ts!p
z<zWBL55Sy%Yvohm{%;i;62fS5HdTyqk#WUxL^8j2`u5t|0}2AM3{vnuKRP;^R;}aV
z<pr41_wPNra7*urPUsQb06tk)=QFK!tK{{N<4ATw4~jcx$Q+Xjra{1pHL(ftReRyO
z)Q_c!U<b{NtgKj=;$Aq34}is3`3*-g##U=#RDI^ulvykq-3YJf@R89D3sWGMJN#0p
zI*#8Z#uP_NP7a)3@KUp~g<m_N$Ffz{ZOseipdWzOgEh2p`-jKZ?GBdA$P_6cP-tOQ
z6<G=bF2($Laj&xP>wvx3f89H<SS(tmN%G9{b8qh$svcPM(M(!sb70fW&CLyzhFSRH
z7wEkN5_4T+<M`yH{~)3OQIZ%NO9Fn0JMOJr)Vi?nDc8AL@4h6*d+*IL;*ye&>&^8c
zGy$+&+Ios40YQv0fA!E4qvQuNIV-0}n*iOLoSZDsJdEFk|K3!<vLlowN~y+yyoH@O
zpv_wTd{-H~eAU!$EG{k%RyjdZ5M<0!od=@|!fMqx!M5rBrLoN;@%#7tBRGBI+9#m-
zT;@cPiVYt?h<w5{f#eBOoa$>9*@j|Slzvy@Pa<D`fA`aH%^M2x@*~k~p`aB_ny}61
zEkEIw_#QhD<+)mUo~&fm)z?3{!)BQa%Zfsj6gD>lKZrQf?F9Abwju$8tv|JRB6}CR
zoWuvL-tt4C65KlaR|uc$*RK>$w9GU&9jyRf)-X>Ra;lOwI8g+#{D_B_x5;aHpw^Ci
zc%CifP#-+Td;5dJ56#Rn;%f%HCkyo;5Fw$feMNF|UsZ~SRBPo!D=I-}1YgW|Wb5Cj
zK|$}z%Yk8hP`*WzB=xExf!Fc?Ey=B0^aLJHKC$;MdIFITq$g}_*wTco?EL)vrb7Pw
zp6b3g3hQ>MZu?yJuylVm{b1?jI#Fc!+qXO$8yg}Fq{Rk&_~D(kNAqGCq~qh`TuB;K
zF$C*AnF9j@xA}o(+O6?U2X1sRUO|X{!y=ZO@Rr*W{R^eLFJ8Q`FPVFJ{ly)POfadN
zR9ONi!pMjYKw_Pl3D9k~?8pNjgEX&45&XVxZq5sXvf|20VAIyKwkDf-*&VA|H26Y+
zAX3qwjOM@YVh#?=&1aE>itGvMUnVAc_7-~q3-?HVK@eZKa0~(@eng4aEa#_^rp+er
z)em0FB-Yhwb911BQkoCV#!=A5#)g#F67i_QKNzsvAhDQD&*gq^-o$?UwVj>Sab1OF
zv~YVq7MrxUx5s^95y1|&!k|wZ2DALF?4cC%YhUyP6+B^NM2DH|hAwRHQ!MnYfXkz<
zIQ6~6L@F6s*?uH;b7ho@Abfq@`D$Y=BLkrMR#sL+BO^jG?1&Po=<cqX$Gv|?{M)<1
z{8IC{*H0@X4;I+K)ZbX|zhlkB!~_u#_~ay>c;#9~n_Gr<<k^d9@FaCDdp*KVy`SD{
zl$%a8CZvub(3L+~5-g3_4{fY{&&9*T^LMQ%9<bRbCT9J{C&I(8>Ey`|cXr~<&d&b5
zxa5v1|L`GQ?&%+o!!>>2D%x&4o@=d!>gG;!Q4oWhDv1m3?m^S1)ql|9p$2@H+S){r
zWs1B(UO2w~z4)5J{TFj{*12JqCq}-8HZ`_gam;z~@~6c0=Gxxg_n6|4+Baq<CVEQq
zLSz49B&l=N+TPK4XKrBu_U29hF3+UBmWa8zxla;B0{1I9yKLXIx65CR&m7s_&Q83=
z#l>1SO{JnSJrff(P0d?pf3_C)df9C1ai#@&zm9^M{I;0L<qj#L$ym%&>KmY45qHYZ
zryTP@V}K`51i87n-x-!$5S8-Lka#sQTUl8J@Ava+>FRpVe~b#WE76015@TIm^3R{<
zWNh+77st5KuE-mnQp|w`14)k8V|wgB*QBYb{)q~c^{p)jA0L|1@&4bx1v0dV6e*lg
zsKWaC6ng7`@P>v4+LY1+C`Kwr=W}nbwBK(Aa7{<|+E85)ckUjxwY6D(@CXlp>A>NH
za5#MJ=rmCDP6Yd#!DaQU&R$JPpzRmEur(KJ{9rp@(U`io_r2S<Z`ak;y$|~rnwgbV
zGv#`cUJeVCNN|-v<92`#uf1J<>dE3!5F;xq&>m)HhV~YF1NZxRSLN~&v(-BWm%WM&
z_*$)nlai7cNQr>%Z)G)`N&4pg%~TZuy2rM*&)VDNErsZr;)vR;g=KeYrz(T<Lp#_$
zP{vG;k1NaMye%uciS7Z@4yfIVi}yKj@82Z}+;^3ma!vJ+dNsX;baj2TzV7_??c3b|
z*e5&D|Jafs`md+QuF%+TpJ*ze%8|g%8vnR)8u%YT7rN@n>XQIB&G%el8KhV&R!d7u
zL|VH4*DufzCjcfSyZc{%z&7jnS-0MK4?RmuEi*GlI2@j?^)?u)oeP`J_L0%%NML6s
zyC)&>d1;BO%l3^r7f0z~nIV*v=sF!bYGJ{yyu92)ig}Z&_vqgZK`GH1=U>+Z@$m5I
zeBh=&%3cnSe4O3g*bSYZIN*s&2#bmci;6w{TEU2ihsO;*VgJa-LFO^|m;;`ei0C~*
zk^6!o;)WvPGU8G)Vv>R)k}@J9MAu$|?w9{}z!P_SXJp|2bHM%o4*1o5_YEE%9y2(@
xLwBT)|06F4JVkqVI|p`EXD<hTcP|%jcIAinJ?j@G@bK{PG~hZaRZ6xI{{!z;TP*+p

literal 0
HcmV?d00001

diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index 9840038521..d694bcae1d 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -1,166 +1,116 @@
-//
-//  main.cpp
-//  tests/gpu-test/src
-//
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include <unordered_map>
-#include <memory>
-#include <cstdio>
-#include <mutex>
-#include <set>
-
-#include <glm/glm.hpp>
-#include <glm/gtc/matrix_transform.hpp>
-
-#include <QtCore/QTime>
-#include <QtCore/QTimer>
-#include <QtCore/QDir>
-#include <QtCore/QElapsedTimer>
-#include <QtCore/QFile>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QRegularExpression>
-
-#include <QtGui/QResizeEvent>
-#include <QtGui/QWindow>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QImage>
-
-#include <QtQuick/QQuickItem>
+//
+//  main.cpp
+//  tests/gpu-test/src
+//
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <unordered_map>
+#include <memory>
+#include <cstdio>
+#include <mutex>
+#include <set>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+
+#include <QtCore/QTime>
+#include <QtCore/QTimer>
+#include <QtCore/QDir>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QFile>
+#include <QtCore/QLoggingCategory>
+
+#include <QtGui/QResizeEvent>
+#include <QtGui/QWindow>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QImage>
+
+#include <QtQuick/QQuickItem>
 #include <QtQml/QQmlApplicationEngine>
 #include <QtQml/QQmlContext>
-
-#include <controllers/NewControllerScriptingInterface.h>
-#include <DependencyManager.h>
-#include <plugins/PluginManager.h>
-#include <input-plugins/InputPlugin.h>
-#include <input-plugins/KeyboardMouseDevice.h>
-#include <input-plugins/UserInputMapper.h>
-
-const QString& getQmlDir() {
-    static QString dir;
-    if (dir.isEmpty()) {
-        QDir path(__FILE__);
-        path.cdUp();
-        dir = path.cleanPath(path.absoluteFilePath("../qml/")) + "/";
-        qDebug() << "Qml Path: " << dir;
-    }
-    return dir;
-}
-
-class AppHook : public QQuickItem {
-    Q_OBJECT
-
-public:
-    AppHook() {
-        qDebug() << "Hook Created";
-    }
-};
-
-using namespace Controllers;
-
-
-QString sanatizeName(const QString& name) {
-    QString cleanName{ name };
-    cleanName.remove(QRegularExpression{ "[\\(\\)\\.\\s]" });
-    return cleanName;
-}
-
-const QVariantMap& getInputMap() {
-    static std::once_flag once;
-    static QVariantMap map;
-    std::call_once(once, [&] {
-        {
-            QVariantMap hardwareMap;
-            // Controller.Hardware.*
-            auto devices = DependencyManager::get<UserInputMapper>()->getDevices();
-            for (const auto& deviceMapping : devices) {
-                auto device = deviceMapping.second.get();
-                auto deviceName = sanatizeName(device->getName());
-                auto deviceInputs = device->getAvailabeInputs();
-                QVariantMap deviceMap;
-                for (const auto& inputMapping : deviceInputs) {
-                    auto input = inputMapping.first;
-                    auto inputName = sanatizeName(inputMapping.second);
-                    deviceMap.insert(inputName, input.getID());
-                }
-                hardwareMap.insert(deviceName, deviceMap);
-            }
-            map.insert("Hardware", hardwareMap);
-        }
-
-        // Controller.Actions.*
-        {
-            QVariantMap actionMap;
-            auto actionNames = DependencyManager::get<UserInputMapper>()->getActionNames();
-            int actionNumber = 0;
-            for (const auto& actionName : actionNames) {
-                actionMap.insert(sanatizeName(actionName), actionNumber++);
-            }
-            map.insert("Actions", actionMap);
-        }
-    });
-    return map;
-}
-
-int main(int argc, char** argv) {
-    DependencyManager::set<UserInputMapper>();
-    PluginManager::getInstance()->getInputPlugins();
-
-    foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
-        QString name = inputPlugin->getName();
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        if (name == KeyboardMouseDevice::NAME) {
-            auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
-            keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
-            keyboardMouseDevice->assignDefaultInputMapping(*userInputMapper);
-        }
-    }
-
-    // Register our component type with QML.
-    qmlRegisterType<AppHook>("com.highfidelity.test", 1, 0, "AppHook");
-    //qmlRegisterType<NewControllerScriptingInterface>("com.highfidelity.test", 1, 0, "NewControllers");
-    QGuiApplication app(argc, argv);
+
+#include <plugins/Plugin.h>
+#include <plugins/PluginContainer.h>
+#include <plugins/PluginManager.h>
+#include <input-plugins/InputPlugin.h>
+#include <input-plugins/KeyboardMouseDevice.h>
+#include <controllers/NewControllerScriptingInterface.h>
+
+#include <DependencyManager.h>
+#include <input-plugins/UserInputMapper.h>
+
+const QString& getQmlDir() {
+    static QString dir;
+    if (dir.isEmpty()) {
+        QDir path(__FILE__);
+        path.cdUp();
+        dir = path.cleanPath(path.absoluteFilePath("../qml/")) + "/";
+        qDebug() << "Qml Path: " << dir;
+    }
+    return dir;
+}
+
+using namespace controller;
+
+
+class PluginContainerProxy : public QObject, PluginContainer {
+    Q_OBJECT
+public:
+    PluginContainerProxy() {
+        Plugin::setContainer(this);
+    }
+    virtual ~PluginContainerProxy() {}
+    virtual void addMenu(const QString& menuName) override {}
+    virtual void removeMenu(const QString& menuName) override {}
+    virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr;  }
+    virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override {}
+    virtual bool isOptionChecked(const QString& name) override { return false;  }
+    virtual void setIsOptionChecked(const QString& path, bool checked) override {}
+    virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override {}
+    virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override {}
+    virtual void showDisplayPluginsTools() override {}
+    virtual void requestReset() override {}
+    virtual QGLWidget* getPrimarySurface() override { return nullptr; }
+    virtual bool isForeground() override { return true;  }
+    virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr;  }
+};
+
+int main(int argc, char** argv) {
+    QGuiApplication app(argc, argv);
     QQmlApplicationEngine engine;
-    engine.rootContext()->setContextProperty("NewControllers", new NewControllerScriptingInterface());
-    engine.rootContext()->setContextProperty("ControllerIds", getInputMap());
-    engine.load(getQmlDir() + "main.qml");
-    app.exec();
-    return 0;
-}
-
-
-
-//QQmlEngine engine;
-//QQmlComponent *component = new QQmlComponent(&engine);
-//
-//QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
-//
-//component->loadUrl(QUrl("main.qml"));
-//
-//if (!component->isReady()) {
-//    qWarning("%s", qPrintable(component->errorString()));
-//    return -1;
-//}
-//
-//QObject *topLevel = component->create();
-//QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
-//
-//QSurfaceFormat surfaceFormat = window->requestedFormat();
-//window->setFormat(surfaceFormat);
-//window->show();
-//
-//rc = app.exec();
-//
-//delete component;
-//return rc;
-//}
-
-
-
-#include "main.moc"
+
+
+    {
+        DependencyManager::set<UserInputMapper>();
+        foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
+            QString name = inputPlugin->getName();
+            inputPlugin->activate();
+            auto userInputMapper = DependencyManager::get<UserInputMapper>();
+            if (name == KeyboardMouseDevice::NAME) {
+                auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
+                keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
+            }
+        }
+
+
+        //new PluginContainerProxy();
+        auto rootContext = engine.rootContext();
 
+        auto controllers = new NewControllerScriptingInterface();
+        rootContext->setContextProperty("NewControllers", controllers);
+        QVariantMap map;
+        map.insert("Hardware", controllers->property("Hardware"));
+        map.insert("Actions", controllers->property("Actions"));
+        rootContext->setContextProperty("ControllerIds", map);
+    }
+    engine.load(getQmlDir() + "main.qml");
+    app.exec();
+    return 0;
+}
+
+#include "main.moc"
+

From ebeb87ba62d7c6b0b82e3fc6bfd69ccc42e38553 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 12 Oct 2015 11:21:40 -0700
Subject: [PATCH 015/301] test

---
 libraries/input-plugins/src/input-plugins/StandardController.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libraries/input-plugins/src/input-plugins/StandardController.h b/libraries/input-plugins/src/input-plugins/StandardController.h
index fa660e15b8..7e0e163358 100644
--- a/libraries/input-plugins/src/input-plugins/StandardController.h
+++ b/libraries/input-plugins/src/input-plugins/StandardController.h
@@ -21,6 +21,7 @@
 
 typedef std::shared_ptr<StandardController> StandardControllerPointer;
 
+// small change
 class StandardController : public QObject, public InputDevice {
     Q_OBJECT
     Q_PROPERTY(QString name READ getName)

From f860ca923ef84a47cd93c25daf4e5ed2d367e121 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 12 Oct 2015 16:01:26 -0700
Subject: [PATCH 016/301] revert small hack

---
 libraries/input-plugins/src/input-plugins/StandardController.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libraries/input-plugins/src/input-plugins/StandardController.h b/libraries/input-plugins/src/input-plugins/StandardController.h
index 7e0e163358..fa660e15b8 100644
--- a/libraries/input-plugins/src/input-plugins/StandardController.h
+++ b/libraries/input-plugins/src/input-plugins/StandardController.h
@@ -21,7 +21,6 @@
 
 typedef std::shared_ptr<StandardController> StandardControllerPointer;
 
-// small change
 class StandardController : public QObject, public InputDevice {
     Q_OBJECT
     Q_PROPERTY(QString name READ getName)

From 58d3578fb1e53c3f58165cde3637ec360f1de0bb Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 12 Oct 2015 17:59:01 -0700
Subject: [PATCH 017/301] Making anonymous mappings work

---
 .../controllers/src/controllers/Mapping.cpp   |  4 +++
 .../controllers/src/controllers/Mapping.h     |  3 ++
 .../NewControllerScriptingInterface.cpp       |  2 +-
 .../NewControllerScriptingInterface.h         |  2 +-
 .../controllers/impl/MappingBuilderProxy.cpp  |  5 ++++
 .../controllers/impl/MappingBuilderProxy.h    |  4 ++-
 tests/controllers/CMakeLists.txt              |  2 +-
 tests/controllers/qml/content.qml             | 30 ++++++++++++++++---
 tests/controllers/src/main.cpp                |  3 ++
 9 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/Mapping.cpp
index 0063a1d24a..7e9ce5d1c4 100644
--- a/libraries/controllers/src/controllers/Mapping.cpp
+++ b/libraries/controllers/src/controllers/Mapping.cpp
@@ -1,5 +1,9 @@
 #include "Mapping.h"
 
 namespace controller {
+    Mapping::Mapping(const QString& name ) : _name(name) {
+
+    }
+
 }
 
diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h
index 5b54a1745b..88d2492986 100644
--- a/libraries/controllers/src/controllers/Mapping.h
+++ b/libraries/controllers/src/controllers/Mapping.h
@@ -27,7 +27,10 @@ namespace controller {
         using Map = std::map<Endpoint::Pointer, Route::List>;
         using Pointer = std::shared_ptr<Mapping>;
 
+        Mapping(const QString& name);
+
         Map _channelMappings;
+        const QString _name;
 
         void parse(const QString& json);
         QString serialize();
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
index f5d6276b91..80089b1136 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
@@ -158,7 +158,7 @@ namespace controller {
             qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
         }
         qDebug() << "Creating new Mapping " << mappingName;
-        Mapping::Pointer mapping = std::make_shared<Mapping>();
+        auto mapping = std::make_shared<Mapping>(mappingName); 
         _mappingsByName[mappingName] = mapping;
         return new MappingBuilderProxy(*this, mapping);
     }
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
index 6bf0bda40d..659c8bfd05 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
@@ -39,7 +39,7 @@ namespace controller {
         Q_INVOKABLE float getValue(const int& source);
 
         Q_INVOKABLE void update();
-        Q_INVOKABLE QObject* newMapping(const QString& mappingName);
+        Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
         Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
         Q_INVOKABLE void disableMapping(const QString& mappingName) {
             enableMapping(mappingName, false);
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index 4e2c6a4d8c..a826b4fd4d 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -41,4 +41,9 @@ QObject* MappingBuilderProxy::join(const QJSValue& source1, const QJSValue& sour
     return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint));
 }
 
+QObject* MappingBuilderProxy::enable(bool enable) {
+    _parent.enableMapping(_mapping->_name, enable);
+    return this;
+}
+
 }
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index b5e02bbfdf..70495a9cfe 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -30,8 +30,10 @@ public:
 
     Q_INVOKABLE QObject* from(const QJSValue& source);
     Q_INVOKABLE QObject* from(const QScriptValue& source);
-
     Q_INVOKABLE QObject* join(const QJSValue& source1, const QJSValue& source2);
+    Q_INVOKABLE QObject* enable(bool enable = true);
+    Q_INVOKABLE QObject* disable() { return enable(false); }
+
 protected:
     QObject* from(const Endpoint::Pointer& source);
 
diff --git a/tests/controllers/CMakeLists.txt b/tests/controllers/CMakeLists.txt
index 34ab4c2eba..d9bef079ff 100644
--- a/tests/controllers/CMakeLists.txt
+++ b/tests/controllers/CMakeLists.txt
@@ -2,7 +2,7 @@
 set(TARGET_NAME controllers-test)
  
 # This is not a testcase -- just set it up as a regular hifi project
-setup_hifi_project(Script)
+setup_hifi_project(Script Qml)
 set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
 
 # link in the shared libraries
diff --git a/tests/controllers/qml/content.qml b/tests/controllers/qml/content.qml
index ce8a491419..aba40af007 100644
--- a/tests/controllers/qml/content.qml
+++ b/tests/controllers/qml/content.qml
@@ -11,7 +11,7 @@ Column {
     property var xbox: NewControllers.Hardware.X360Controller1
     property var actions: NewControllers.Actions
     property var standard: NewControllers.Standard
-    property string mappingName: "TestMapping"
+    property var testMapping: null
 
     spacing: 12
 
@@ -55,7 +55,7 @@ Column {
         Button {
             text: "Build Mapping"
             onClicked: {
-                var mapping = NewControllers.newMapping(root.mappingName);
+                var mapping = NewControllers.newMapping();
                 // Inverting a value
                 mapping.from(xbox.RY).invert().to(standard.RY);
                 // Assigning a value from a function
@@ -63,17 +63,22 @@ Column {
                 // Constrainting a value to -1, 0, or 1, with a deadzone
                 mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
                 mapping.join(standard.LB, standard.RB).pulse(0.5).to(actions.Yaw);
+                mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
+                mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
+                testMapping = mapping;
+                enabled = false
+                text = "Built"
             }
         }
 
         Button {
             text: "Enable Mapping"
-            onClicked: NewControllers.enableMapping(root.mappingName)
+            onClicked: root.testMapping.enable()
         }
 
         Button {
             text: "Disable Mapping"
-            onClicked: NewControllers.disableMapping(root.mappingName)
+            onClicked: root.testMapping.disable()
         }
     }
 
@@ -85,6 +90,7 @@ Column {
 
 
     Row {
+        spacing: 8
         ScrollingGraph {
             controlId: NewControllers.Actions.Yaw
             label: "Yaw"
@@ -92,6 +98,22 @@ Column {
             max: 3.0
             size: 128
         }
+
+        ScrollingGraph {
+            controlId: NewControllers.Actions.YAW_LEFT
+            label: "Yaw Left"
+            min: -3.0
+            max: 3.0
+            size: 128
+        }
+
+        ScrollingGraph {
+            controlId: NewControllers.Actions.YAW_RIGHT
+            label: "Yaw Right"
+            min: -3.0
+            max: 3.0
+            size: 128
+        }
     }
 }
 
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index d694bcae1d..7182862ff1 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -82,6 +82,9 @@ public:
 int main(int argc, char** argv) {
     QGuiApplication app(argc, argv);
     QQmlApplicationEngine engine;
+    for (auto path : qApp->libraryPaths()) {
+        qDebug() << path;
+    }
 
 
     {

From 9a9bdbbc4462d78769f08ce2f58241e5a98b7b65 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 12 Oct 2015 17:59:58 -0700
Subject: [PATCH 018/301] hack in mappings to interface

---
 .../example/scripts/controllerScriptingExamples.js | 14 ++++++++++++++
 .../src/scripting/ControllerScriptingInterface.cpp | 12 ++++++++++++
 .../src/scripting/ControllerScriptingInterface.h   |  7 ++++++-
 .../src/input-plugins/InputPlugin.cpp              |  2 +-
 4 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/examples/example/scripts/controllerScriptingExamples.js b/examples/example/scripts/controllerScriptingExamples.js
index 6db7b38705..e678ff26eb 100644
--- a/examples/example/scripts/controllerScriptingExamples.js
+++ b/examples/example/scripts/controllerScriptingExamples.js
@@ -12,6 +12,20 @@
 // Assumes you only have the default keyboard connected
 
 
+
+var hydra = Controller.Hardware.Hydra2;
+if (hydra !== undefined) {
+    print("-----------------------------------");
+    var mapping = NewControllers.newMapping("Default");
+    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");
+    print("-----------------------------------");
+}
+
 Object.keys(Controller.Standard).forEach(function (input) {
     print("Controller.Standard." + input + ":" + Controller.Standard[input]);
 });
diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp
index 9bdf8d1a4a..54aa72da6b 100644
--- a/interface/src/scripting/ControllerScriptingInterface.cpp
+++ b/interface/src/scripting/ControllerScriptingInterface.cpp
@@ -14,6 +14,8 @@
 #include <HandData.h>
 #include <HFBackEvent.h>
 
+#include <controllers/NewControllerScriptingInterface.h>
+
 #include "Application.h"
 #include "devices/MotionTracker.h"
 #include "ControllerScriptingInterface.h"
@@ -31,6 +33,11 @@ ControllerScriptingInterface::ControllerScriptingInterface() :
 
 }
 
+ControllerScriptingInterface::~ControllerScriptingInterface() {
+    delete _newControllerScriptingInterface;
+}
+
+
 static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
 static int inputChannelMetaTypeId = qRegisterMetaType<UserInputMapper::InputChannel>();
 static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
@@ -121,6 +128,11 @@ void ControllerScriptingInterface::registerControllerTypes(ScriptEngine* engine)
     qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
 
     wireUpControllers(engine);
+
+    // hack in the new controller scripting interface...
+    _newControllerScriptingInterface = new controller::NewControllerScriptingInterface();
+    engine->registerGlobalObject("NewControllers", _newControllerScriptingInterface);
+
 }
 
 void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h
index aa0526accb..dfe87043cd 100644
--- a/interface/src/scripting/ControllerScriptingInterface.h
+++ b/interface/src/scripting/ControllerScriptingInterface.h
@@ -18,6 +18,9 @@
 
 #include <AbstractControllerScriptingInterface.h>
 class PalmData;
+namespace controller {
+    class NewControllerScriptingInterface;
+}
 
 class InputController : public  AbstractInputController {
     Q_OBJECT
@@ -55,7 +58,8 @@ class ControllerScriptingInterface : public AbstractControllerScriptingInterface
 
 public:    
     ControllerScriptingInterface();
-    
+    ~ControllerScriptingInterface();
+
     virtual void registerControllerTypes(ScriptEngine* engine);
     
     void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
@@ -169,6 +173,7 @@ private:
 
     void wireUpControllers(ScriptEngine* engine);
 
+    controller::NewControllerScriptingInterface* _newControllerScriptingInterface = nullptr;
 };
 
 const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip
diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
index b52dd3f658..2b16d905f5 100644
--- a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
+++ b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
@@ -22,7 +22,7 @@ InputPluginList getInputPlugins() {
     InputPlugin* PLUGIN_POOL[] = {
         new KeyboardMouseDevice(),
         new SDL2Manager(),
-        //new SixenseManager(),
+        new SixenseManager(),
         //new ViveControllerManager(),
         nullptr
     };

From dc32d5ae8d7c491e63b568c4f47cb07d12a655b2 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Mon, 12 Oct 2015 18:03:21 -0700
Subject: [PATCH 019/301] Current status of my code for json

---
 .../controllers/src/controllers/Mapping.cpp   | 10 +++-
 .../controllers/src/controllers/Mapping.h     |  4 +-
 .../NewControllerScriptingInterface.cpp       |  4 ++
 .../NewControllerScriptingInterface.h         |  2 +
 .../controllers/impl/MappingBuilderProxy.cpp  | 50 ++++++++++++++++++-
 .../controllers/impl/MappingBuilderProxy.h    | 12 +++++
 .../src/controllers/impl/RouteBuilderProxy.h  |  4 ++
 .../src/input-plugins/UserInputMapper.cpp     | 24 ++++++++-
 .../src/input-plugins/UserInputMapper.h       |  5 +-
 tests/controllers/src/main.cpp                |  4 +-
 10 files changed, 111 insertions(+), 8 deletions(-)

diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/Mapping.cpp
index 0063a1d24a..b6214a43fc 100644
--- a/libraries/controllers/src/controllers/Mapping.cpp
+++ b/libraries/controllers/src/controllers/Mapping.cpp
@@ -1,5 +1,11 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
 #include "Mapping.h"
 
-namespace controller {
-}
+
 
diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h
index 5b54a1745b..39fe6ba788 100644
--- a/libraries/controllers/src/controllers/Mapping.h
+++ b/libraries/controllers/src/controllers/Mapping.h
@@ -28,9 +28,9 @@ namespace controller {
         using Pointer = std::shared_ptr<Mapping>;
 
         Map _channelMappings;
+        QString _name;
 
-        void parse(const QString& json);
-        QString serialize();
+    protected:
     };
 
 }
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
index f5d6276b91..c4d1bb65c4 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
@@ -301,6 +301,10 @@ namespace controller {
         return Endpoint::Pointer();
     }
 
+    UserInputMapper::Input NewControllerScriptingInterface::inputFor(const QString& inputName) {
+        return DependencyManager::get<UserInputMapper>()->findDeviceInput(inputName);
+    }
+
     Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) {
         auto iterator = _endpoints.find(inputId);
         if (_endpoints.end() == iterator) {
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
index 6bf0bda40d..39791eacb2 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
@@ -68,6 +68,8 @@ namespace controller {
         Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint);
         Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
 
+        UserInputMapper::Input inputFor(const QString& inputName);
+
         friend class MappingBuilderProxy;
         friend class RouteBuilderProxy;
     private:
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index 4e2c6a4d8c..71a8a417fd 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -11,11 +11,14 @@
 #include <QtCore/QHash>
 #include <QtCore/QDebug>
 
+#include <QJSONObject>
+#include <qjsonarray.h>
+
 #include "RouteBuilderProxy.h"
 #include "../NewControllerScriptingInterface.h"
 #include "../Logging.h"
 
-namespace controller {
+using namespace controller;
 
 QObject* MappingBuilderProxy::from(const QJSValue& source) {
     qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString();
@@ -41,4 +44,49 @@ QObject* MappingBuilderProxy::join(const QJSValue& source1, const QJSValue& sour
     return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint));
 }
 
+
+const QString JSON_NAME = QStringLiteral("name");
+const QString JSON_CHANNELS = QStringLiteral("channels");
+const QString JSON_CHANNEL_FROM = QStringLiteral("from");
+const QString JSON_CHANNEL_TO = QStringLiteral("to");
+const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
+
+
+void MappingBuilderProxy::parse(const QJsonObject& json) {
+    _mapping->_name = json[JSON_NAME].toString();
+
+    _mapping->_channelMappings.clear();
+    const auto& jsonChannels = json[JSON_CHANNELS].toArray();
+    for (const auto& channelIt : jsonChannels) {
+        parseRoute(channelIt);
+    }
+}
+
+void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
+    if (json.isObject()) {
+        const auto& jsonChannel = json.toObject();
+
+        auto newRoute = from(jsonChannel[JSON_CHANNEL_FROM]);
+        if (newRoute) {
+            auto route = dynamic_cast<RouteBuilderProxy*>(newRoute);
+            route->filters(jsonChannel[JSON_CHANNEL_FILTERS]);
+            route->to(jsonChannel[JSON_CHANNEL_TO]);
+
+            return 
+        }
+    }
+}
+
+QObject* MappingBuilderProxy::from(const QJsonValue& json) {
+    if (json.isString()) {
+        return from(_parent.endpointFor(_parent.inputFor(json.toString())));
+    } else if (json.isObject()) {
+        // Endpoint is defined as an object, we expect a js function then
+        return nullptr;
+    }
+}
+
+
+Filter::List MappingBuilderProxy::parseFilters(const QJsonValue& json) const {
+    return Filter::List();
 }
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index b5e02bbfdf..d0101b95a7 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -32,12 +32,24 @@ public:
     Q_INVOKABLE QObject* from(const QScriptValue& source);
 
     Q_INVOKABLE QObject* join(const QJSValue& source1, const QJSValue& source2);
+
+    // JSON route creation point
+    Q_INVOKABLE QObject* from(const QJsonValue& json);
+
+
+    void parse(const QJsonObject& json);
+  //  void serialize(QJsonObject& json);
+
 protected:
     QObject* from(const Endpoint::Pointer& source);
 
     friend class RouteBuilderProxy;
     NewControllerScriptingInterface& _parent;
     Mapping::Pointer _mapping;
+
+
+    void parseRoute(const QJsonValue& json);
+
 };
 
 }
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 63cd106edb..a62a465700 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -40,6 +40,10 @@ class RouteBuilderProxy : public QObject {
         Q_INVOKABLE QObject* constrainToInteger();
         Q_INVOKABLE QObject* constrainToPositiveInteger();
 
+        // JSON route creation point
+        Q_INVOKABLE QObject* filters(const QJsonValue& json);
+        Q_INVOKABLE void to(const QJsonValue& json);
+
     private:
         void to(const Endpoint::Pointer& destination);
         void addFilter(Filter::Lambda lambda);
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
index c29acc09af..325dc5dfe7 100755
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
+++ b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
@@ -64,7 +64,7 @@ void UserInputMapper::resetDevice(uint16 deviceID) {
     }
 }
 
-int UserInputMapper::findDevice(QString name) {
+int UserInputMapper::findDevice(QString name) const {
     for (auto device : _registeredDevices) {
         if (device.second->_name.split(" (")[0] == name) {
             return device.first;
@@ -82,6 +82,28 @@ QVector<QString> UserInputMapper::getDeviceNames() {
     return result;
 }
 
+UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
+    
+    // Split the full input name as such: deviceName.inputName
+    auto names = inputName.split('.');
+
+    if (names.size() >= 2) {
+        // Get the device name:
+        auto deviceName = names[0];
+        auto inputName = names[1];
+
+        int deviceID = findDevice(deviceName);
+        if (deviceID != Input::INVALID_DEVICE) {
+         //   getAllInputsForDevice(deviceID);
+        }
+
+
+    }
+
+    return Input();
+}
+
+
 
 bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
     return addInputChannel(action, input, Input(), scale);
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.h b/libraries/input-plugins/src/input-plugins/UserInputMapper.h
index 304e74e8cc..b7b105df5e 100755
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.h
+++ b/libraries/input-plugins/src/input-plugins/UserInputMapper.h
@@ -140,9 +140,12 @@ public:
     QVector<InputPair> getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); }
     void resetAllDeviceBindings();
     void resetDevice(uint16 deviceID);
-    int findDevice(QString name);
+    int findDevice(QString name) const;
     QVector<QString> getDeviceNames();
 
+    Input findDeviceInput(const QString& inputName) const;
+
+
     // Actions are the output channels of the Mapper, that's what the InputChannel map to
     // For now the Actions are hardcoded, this is bad, but we will fix that in the near future
     enum Action {
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index d694bcae1d..b42359e48a 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -83,7 +83,9 @@ int main(int argc, char** argv) {
     QGuiApplication app(argc, argv);
     QQmlApplicationEngine engine;
 
-
+    for (auto path : qApp->libraryPaths()) {
+        qDebug() << path;
+    }
     {
         DependencyManager::set<UserInputMapper>();
         foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {

From 3ca3c635c01e7c4606859d44d9f79878d46a0a4c Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 12 Oct 2015 18:40:47 -0700
Subject: [PATCH 020/301] Support functions in QScript contexts

---
 .../NewControllerScriptingInterface.cpp       | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
index 80089b1136..4bc5b9eeb5 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
@@ -59,6 +59,25 @@ namespace controller {
         QJSValue _callable;
     };
 
+    class ScriptEndpoint : public Endpoint {
+    public:
+        ScriptEndpoint(const QScriptValue& callable)
+            : Endpoint(UserInputMapper::Input(-1)), _callable(callable) {
+        }
+
+        virtual float value() {
+            float result = (float)_callable.call().toNumber();
+            return result;
+        }
+
+        virtual void apply(float newValue, float oldValue, const Pointer& source) {
+            _callable.call(QScriptValue(), QScriptValueList({ QScriptValue(newValue) }));
+        }
+
+    private:
+        QScriptValue _callable;
+    };
+
     class CompositeEndpoint : public Endpoint, Endpoint::Pair {
     public:
         CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
@@ -297,6 +316,11 @@ namespace controller {
             return endpointFor(UserInputMapper::Input(endpoint.toInt32()));
         }
 
+        if (endpoint.isFunction()) {
+            auto result = std::make_shared<ScriptEndpoint>(endpoint);
+            return result;
+        }
+
         qWarning() << "Unsupported input type " << endpoint.toString();
         return Endpoint::Pointer();
     }

From 8a0540234cf0979ef7654ccf91962f68cdecf676 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 12 Oct 2015 18:47:59 -0700
Subject: [PATCH 021/301] Find the joystick controller dynamically

---
 tests/controllers/qml/content.qml | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/tests/controllers/qml/content.qml b/tests/controllers/qml/content.qml
index aba40af007..41d623a389 100644
--- a/tests/controllers/qml/content.qml
+++ b/tests/controllers/qml/content.qml
@@ -8,10 +8,21 @@ import "./controls"
 
 Column {
     id: root
-    property var xbox: NewControllers.Hardware.X360Controller1
     property var actions: NewControllers.Actions
     property var standard: NewControllers.Standard
     property var testMapping: null
+    property var xbox: null
+
+
+    Component.onCompleted: {
+        var patt = /^X360Controller/;
+        for (var prop in NewControllers.Hardware) {
+            if(patt.test(prop)) {
+                root.xbox = NewControllers.Hardware[prop]
+                break
+            }
+        }
+    }
 
     spacing: 12
 
@@ -49,6 +60,8 @@ Column {
                 mapping.from(xbox.LT).to(standard.LT);
                 mapping.from(xbox.RT).to(standard.RT);
                 NewControllers.enableMapping("Default");
+                enabled = false;
+                text = "Built"
             }
         }
 

From 7f8f5f66c714bda8505f5787eaece6ffe88ad261 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Tue, 13 Oct 2015 10:01:01 -0700
Subject: [PATCH 022/301] Working on plugin active concept

---
 .../src/display-plugins/NullDisplayPlugin.cpp      |  3 ---
 .../src/display-plugins/NullDisplayPlugin.h        |  2 --
 .../src/display-plugins/OpenGLDisplayPlugin.cpp    |  4 ++--
 .../src/display-plugins/OpenGLDisplayPlugin.h      |  1 -
 .../src/input-plugins/KeyboardMouseDevice.h        |  6 +++---
 .../input-plugins/src/input-plugins/SDL2Manager.h  |  2 --
 .../src/input-plugins/SixenseManager.cpp           |  2 ++
 .../src/input-plugins/ViveControllerManager.cpp    |  3 +++
 libraries/plugins/src/plugins/Plugin.h             | 14 ++++++++++++--
 9 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
index 1f8242f081..914f80d983 100644
--- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
@@ -27,7 +27,4 @@ void NullDisplayPlugin::preRender() {}
 void NullDisplayPlugin::preDisplay() {}
 void NullDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) {}
 void NullDisplayPlugin::finishFrame() {}
-
-void NullDisplayPlugin::activate() {}
-void NullDisplayPlugin::deactivate() {}
 void NullDisplayPlugin::stop() {}
diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
index bb1ab2d97f..4f2cc77b8f 100644
--- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
@@ -15,8 +15,6 @@ public:
     virtual ~NullDisplayPlugin() final {}
     virtual const QString & getName() const override;
 
-    void activate() override;
-    void deactivate() override;
     void stop() override;
 
     virtual glm::uvec2 getRecommendedRenderSize() const override;
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
index 505dae824a..d93040690f 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
@@ -57,12 +57,12 @@ void OpenGLDisplayPlugin::customizeContext() {
 }
 
 void OpenGLDisplayPlugin::activate() {
-    _active = true;
+    DisplayPlugin::activate();
     _timer.start(1);
 }
 
 void OpenGLDisplayPlugin::stop() {
-    _active = false;
+    DisplayPlugin::activate();
     _timer.stop();
 }
 
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h
index 52715ebde7..4b0e03788a 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h
@@ -44,7 +44,6 @@ protected:
     mutable QTimer _timer;
     ProgramPtr _program;
     ShapeWrapperPtr _plane;
-    bool _active{ false };
     bool _vsyncSupported{ false };
 };
 
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
index d96566e9d1..e8a6131387 100644
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
@@ -13,6 +13,9 @@
 #define hifi_KeyboardMouseDevice_h
 
 #include <chrono>
+
+#include <QtCore/QPoint>
+
 #include "InputDevice.h"
 #include "InputPlugin.h"
 
@@ -65,9 +68,6 @@ public:
     virtual bool isJointController() const override { return false; }
     const QString& getName() const override { return NAME; }
 
-    virtual void activate() override {};
-    virtual void deactivate() override {};
-
     virtual void pluginFocusOutEvent() override { focusOutEvent(); }
     virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
 
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.h b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
index 52d39597ef..23e3ee059f 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.h
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
@@ -34,8 +34,6 @@ public:
 
     virtual void init() override;
     virtual void deinit() override;
-    virtual void activate() override {};
-    virtual void deactivate() override {};
     
     virtual void pluginFocusOutEvent() override;
     virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override;
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 3950fdea43..e7a4feedd8 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -85,6 +85,7 @@ bool SixenseManager::isSupported() const {
 }
 
 void SixenseManager::activate() {
+    InputPlugin::activate();
 #ifdef HAVE_SIXENSE
     _calibrationState = CALIBRATION_STATE_IDLE;
     _avatarPosition = DEFAULT_AVATAR_POSITION;
@@ -125,6 +126,7 @@ void SixenseManager::activate() {
 }
 
 void SixenseManager::deactivate() {
+    InputPlugin::deactivate();
 #ifdef HAVE_SIXENSE
     CONTAINER->removeMenuItem(MENU_NAME, TOGGLE_SMOOTH);
     CONTAINER->removeMenu(MENU_PATH);
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index bb8267b616..a3374cc1c0 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -79,6 +79,7 @@ bool ViveControllerManager::isSupported() const {
 }
 
 void ViveControllerManager::activate() {
+    InputPlugin::activate();
 #ifdef Q_OS_WIN
     CONTAINER->addMenu(MENU_PATH);
     CONTAINER->addMenuItem(MENU_PATH, RENDER_CONTROLLERS,
@@ -143,6 +144,8 @@ void ViveControllerManager::activate() {
 }
 
 void ViveControllerManager::deactivate() {
+    InputPlugin::deactivate();
+
 #ifdef Q_OS_WIN
     CONTAINER->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
     CONTAINER->removeMenu(MENU_PATH);
diff --git a/libraries/plugins/src/plugins/Plugin.h b/libraries/plugins/src/plugins/Plugin.h
index 68e012b8e1..f53d309e97 100644
--- a/libraries/plugins/src/plugins/Plugin.h
+++ b/libraries/plugins/src/plugins/Plugin.h
@@ -33,9 +33,18 @@ public:
     virtual void deinit();
 
     /// Called when a plugin is being activated for use.  May be called multiple times.
-    virtual void activate() = 0;
+    virtual void activate() {
+        _active = true;
+    }
+
     /// Called when a plugin is no longer being used.  May be called multiple times.
-    virtual void deactivate() = 0;
+    virtual void deactivate() {
+        _active = false;
+    }
+
+    virtual bool isActive() {
+        return _active;
+    }
 
     /**
      * Called by the application during it's idle phase.  If the plugin needs to do
@@ -48,6 +57,7 @@ public:
     virtual void loadSettings() {}
 
 protected:
+    bool _active{ false };
     static PluginContainer* CONTAINER;
     static QString UNKNOWN_PLUGIN_ID;
 

From 261384b4bb0e1244860926254c7b91bdfcab62f5 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Tue, 13 Oct 2015 11:47:06 -0700
Subject: [PATCH 023/301] Fixing build breakage

---
 .../input-plugins/src/input-plugins/KeyboardMouseDevice.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
index 202a767244..4703d3ae6a 100755
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
@@ -10,9 +10,9 @@
 //
 #include "KeyboardMouseDevice.h"
 
-#include <QtGUI/QKeyEvent>
-#include <QtGUI/QMouseEvent>
-#include <QtGUI/QTouchEvent>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QTouchEvent>
 
 
 const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse";

From cb62527bf93a1b32dcce94095a38583f163b4412 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 14 Oct 2015 09:22:30 -0700
Subject: [PATCH 024/301] Refactoring the filter for supporting the factory

---
 .../controllers/src/controllers/Filter.cpp    |  63 ++++++++-
 .../controllers/src/controllers/Filter.h      | 132 ++++++++++++++++--
 .../controllers/impl/MappingBuilderProxy.cpp  |   9 +-
 .../controllers/impl/MappingBuilderProxy.h    |   1 +
 .../controllers/impl/RouteBuilderProxy.cpp    |  64 +++++----
 .../src/controllers/impl/RouteBuilderProxy.h  |   1 +
 6 files changed, 218 insertions(+), 52 deletions(-)

diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
index 17715eceff..b7175f1716 100644
--- a/libraries/controllers/src/controllers/Filter.cpp
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -11,11 +11,66 @@
 #include <QtCore/QObject>
 #include <QtScript/QScriptValue>
 
-namespace controller {
+#include <QJSonObject>
+#include <QJSonArray>
 
-    Filter::Pointer Filter::parse(const QJsonObject& json) {
-        // FIXME parse the json object and determine the instance type to create
-        return Filter::Pointer();
+#include "SharedUtil.h"
+
+using namespace controller;
+
+
+const QString JSON_FILTER_TYPE = QStringLiteral("type");
+const QString JSON_FILTER_PARAMS = QStringLiteral("params");
+
+Filter::Factory Filter::_factory;
+
+Filter::Pointer Filter::parse(const QJsonObject& json) {
+    // The filter is an object, now let s check for type and potential arguments
+    Filter::Pointer filter;
+    auto filterType = json[JSON_FILTER_TYPE];
+    if (filterType.isString()) {
+        filter.reset(Filter::getFactory().create(filterType.toString().toStdString()));
+        if (filter) {
+            // Filter is defined, need to read the parameters and validate
+            auto parameters = json[JSON_FILTER_PARAMS];
+            if (parameters.isArray()) {
+                if (filter->parseParameters(parameters.toArray())) {
+                }
+            }
+
+            return filter;
+        }
     }
+    return Filter::Pointer();
 }
 
+Filter::Factory::ClassEntry<ScaleFilter> ScaleFilter::_factoryEntry;
+
+bool ScaleFilter::parseParameters(const QJsonArray& parameters) {
+    if (parameters.size() > 1) {
+        _scale = parameters[0].toDouble();
+    }
+    return true;
+}
+
+Filter::Factory::ClassEntry<PulseFilter> PulseFilter::_factoryEntry;
+
+
+float PulseFilter::apply(float value) const {
+    float result = 0.0;
+
+    if (0.0 != value) {
+        float now = secTimestampNow();
+        float delta = now - _lastEmitTime;
+        if (delta >= _interval) {
+            _lastEmitTime = now;
+            result = value;
+        }
+    }
+
+    return result;
+}
+
+bool PulseFilter::parseParameters(const QJsonArray& parameters) {
+    return false;
+}
diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h
index f3978e2c0a..425bba7512 100644
--- a/libraries/controllers/src/controllers/Filter.h
+++ b/libraries/controllers/src/controllers/Filter.h
@@ -14,13 +14,49 @@
 #include <memory>
 #include <numeric>
 #include <functional>
+#include <map>
 
 #include <QtCore/QEasingCurve>
 
 class QJsonObject;
+class QJsonArray;
+
 
 namespace controller {
+    /*
+    template <class T> class Factory {
+    public:
 
+    template <class T> class Entry {
+    public:
+    virtual T* create() = 0;
+    };
+
+    template <class T, class S> class DefaultEntry{
+    public:
+    T* create() { return new S(); }
+    };
+
+    using EntryMap = std::map<std::string, std::unique_ptr<Entry<T>>>;
+
+    void registerEntry(const std::string& name, std::unique_ptr<Entry<T>>& entry) {
+    if (entry) {
+    _entries[name] = entry;
+    }
+    }
+
+    T* create(const std::string& name) const {
+    auto& entryIt = _entries.find(name);
+    if (entryIt != _entries.end()) {
+    return (*entryIt).second->create();
+    }
+    return nullptr;
+    }
+
+    protected:
+    EntryMap _entries;
+    };
+    */
     // Encapsulates part of a filter chain
     class Filter {
     public:
@@ -30,18 +66,71 @@ namespace controller {
         using List = std::list<Pointer>;
         using Lambda = std::function<float(float)>;
 
-        static Filter::Pointer parse(const QJsonObject& json);
-    };
+        // Factory features
+        virtual bool parseParameters(const QJsonArray& parameters) = 0;
 
+        class Factory {
+        public:
+
+            class Entry {
+            public:
+                virtual Filter* create() = 0;
+                
+                Entry() = default;
+                virtual ~Entry() = default;
+            };
+
+            template <class T> class ClassEntry {
+            public:
+                virtual Filter* create() { return (Filter*) new T(); }
+
+                ClassEntry() = default;
+                virtual ~ClassEntry() = default;
+            };
+
+            using EntryMap = std::map<std::string, std::shared_ptr<Entry>>;
+
+            void registerEntry(const std::string& name, const std::shared_ptr<Entry>& entry) {
+                if (entry) {
+                    _entries.insert(EntryMap::value_type(name, entry));
+                }
+            }
+
+            Filter* create(const std::string& name) const {
+                auto& entryIt = _entries.find(name);
+                if (entryIt != _entries.end()) {
+                    return (*entryIt).second->create();
+                }
+                return nullptr;
+            }
+
+        protected:
+            EntryMap _entries;
+        };
+
+        static Filter::Pointer parse(const QJsonObject& json);
+        static Factory& getFactory() { return _factory; }
+    protected:
+        static Factory _factory;
+    };
+}
+
+#define REGISTER_FILTER_CLASS(classEntry) static Filter::Factory::ClassEntry<classEntry> _factoryEntry;
+
+namespace controller {
 
     class LambdaFilter : public Filter {
     public:
+    //    LambdaFilter() {}
         LambdaFilter(Lambda f) : _function(f) {};
 
         virtual float apply(float value) const {
             return _function(value);
         }
 
+        virtual bool parseParameters(const QJsonArray& parameters) { return true; }
+
+//        REGISTER_FILTER_CLASS(LambdaFilter);
     private:
         Lambda _function;
     };
@@ -50,17 +139,21 @@ namespace controller {
     public:
 
     };
+   
+    class ScaleFilter : public Filter {
+    public:
+        ScaleFilter() {}
+        ScaleFilter(float scale): _scale(scale) {}
 
-    //class ScaleFilter : public Filter {
-    //public:
-    //    ScaleFilter(float scale);
-    //    virtual float apply(float scale) const override {
-    //        return value * _scale;
-    //    }
+        virtual float apply(float value) const override {
+            return value * _scale;
+        }
+        virtual bool parseParameters(const QJsonArray& parameters);
 
-    //private:
-    //    const float _scale;
-    //};
+        REGISTER_FILTER_CLASS(ScaleFilter);
+    private:
+        float _scale = 1.0f;
+    };
 
     //class AbstractRangeFilter : public Filter {
     //public:
@@ -84,6 +177,23 @@ namespace controller {
     //    const float _interval;
     //};
 
+
+    class PulseFilter : public Filter {
+    public:
+        REGISTER_FILTER_CLASS(PulseFilter);
+        PulseFilter() {}
+        PulseFilter(float interval) : _interval(interval) {}
+
+
+        virtual float apply(float value) const override;
+
+        virtual bool parseParameters(const QJsonArray& parameters);
+
+    private:
+        mutable float _lastEmitTime{ -std::numeric_limits<float>::max() };
+        float _interval = 1.0f;
+    };
+
     ////class DeadzoneFilter : public AbstractRangeFilter {
     ////public:
     ////    DeadzoneFilter(float min, float max = 1.0f);
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index 71a8a417fd..9080555cac 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -11,8 +11,8 @@
 #include <QtCore/QHash>
 #include <QtCore/QDebug>
 
-#include <QJSONObject>
-#include <qjsonarray.h>
+#include <QJSonObject>
+#include <QJSonArray>
 
 #include "RouteBuilderProxy.h"
 #include "../NewControllerScriptingInterface.h"
@@ -71,8 +71,6 @@ void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
             auto route = dynamic_cast<RouteBuilderProxy*>(newRoute);
             route->filters(jsonChannel[JSON_CHANNEL_FILTERS]);
             route->to(jsonChannel[JSON_CHANNEL_TO]);
-
-            return 
         }
     }
 }
@@ -87,6 +85,3 @@ QObject* MappingBuilderProxy::from(const QJsonValue& json) {
 }
 
 
-Filter::List MappingBuilderProxy::parseFilters(const QJsonValue& json) const {
-    return Filter::List();
-}
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index d0101b95a7..799fc99399 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -17,6 +17,7 @@
 
 class QJSValue;
 class QScriptValue;
+class QJsonValue;
 
 namespace controller {
 
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index e6b67e9ca6..d606b52608 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -9,6 +9,9 @@
 
 #include <QtCore/QDebug>
 
+#include <QJSonObject>
+#include <QJSonArray>
+
 #include <GLMHelpers.h>
 
 #include "MappingBuilderProxy.h"
@@ -61,9 +64,7 @@ QObject* RouteBuilderProxy::clamp(float min, float max) {
 }
 
 QObject* RouteBuilderProxy::scale(float multiplier) {
-    addFilter([=](float value) {
-        return value * multiplier;
-    });
+    addFilter(Filter::Pointer(new ScaleFilter(multiplier)));
     return this;
 }
 
@@ -99,39 +100,12 @@ QObject* RouteBuilderProxy::constrainToPositiveInteger() {
 }
 
 
-class PulseFilter : public Filter {
-public:
-    PulseFilter(float interval) : _interval(interval) {}
-    
-    virtual float apply(float value) const override {
-        float result = 0.0;
-
-        if (0.0 != value) {
-            float now = secTimestampNow();
-            float delta = now - _lastEmitTime;
-            if (delta >= _interval) {
-                _lastEmitTime = now;
-                result = value;
-            }
-        }
-
-        return result;
-    }
-
-private:
-    mutable float _lastEmitTime{ -std::numeric_limits<float>::max() };
-    const float _interval;
-};
-
-
 QObject* RouteBuilderProxy::pulse(float interval) {
     Filter::Pointer filter = std::make_shared<PulseFilter>(interval);
     addFilter(filter);
     return this;
 }
 
-
-
 void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
     Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda);
     addFilter(filterPointer);
@@ -141,4 +115,34 @@ void RouteBuilderProxy::addFilter(Filter::Pointer filter) {
     _route->_filters.push_back(filter);
 }
 
+
+QObject* RouteBuilderProxy::filters(const QJsonValue& json) {
+    // We expect an array of objects to define the filters
+    if (json.isArray()) {
+        const auto& jsonFilters = json.toArray();
+        for (auto jsonFilter : jsonFilters) {
+            if (jsonFilter.isObject()) {
+                // The filter is an object, now let s check for type and potential arguments
+                Filter::Pointer filter = Filter::parse(jsonFilter.toObject());
+                if (filter) {
+                    addFilter(filter);
+                }
+            }
+        }
+    }
+
+    return this;
+}
+
+void RouteBuilderProxy::to(const QJsonValue& json) {
+    if (json.isString()) {
+
+        return to(_parent.endpointFor(_parent.inputFor(json.toString())));
+    } else if (json.isObject()) {
+        // Endpoint is defined as an object, we expect a js function then
+        return to(nullptr);
+    }
+
+}
+
 }
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index a62a465700..573e841e85 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -16,6 +16,7 @@
 
 class QJSValue;
 class QScriptValue;
+class QJsonValue;
 
 namespace controller {
 

From 1302b6a2388d466064363067ec428166a1488670 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 14 Oct 2015 10:47:49 -0700
Subject: [PATCH 025/301] Improving the Factory registration

---
 .../controllers/src/controllers/Filter.h      | 25 +++++++++++++------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h
index 425bba7512..4d21966731 100644
--- a/libraries/controllers/src/controllers/Filter.h
+++ b/libraries/controllers/src/controllers/Filter.h
@@ -75,24 +75,30 @@ namespace controller {
             class Entry {
             public:
                 virtual Filter* create() = 0;
-                
+                virtual const std::string& getName() const = 0;
+
                 Entry() = default;
                 virtual ~Entry() = default;
             };
 
-            template <class T> class ClassEntry {
+            template <class T, std::string name> class ClassEntry {
             public:
-                virtual Filter* create() { return (Filter*) new T(); }
+                Filter* create() override { return (Filter*) new T(); }
+                const std::string& getName() const override {
+                    return _name
+                };
 
-                ClassEntry() = default;
+                ClassEntry() : _name(name) {};
                 virtual ~ClassEntry() = default;
+
+                const std::string _name;
             };
 
             using EntryMap = std::map<std::string, std::shared_ptr<Entry>>;
 
-            void registerEntry(const std::string& name, const std::shared_ptr<Entry>& entry) {
+            void registerEntry(const std::shared_ptr<Entry>& entry) {
                 if (entry) {
-                    _entries.insert(EntryMap::value_type(name, entry));
+                    _entries.insert(EntryMap::value_type(entry->getName(), entry));
                 }
             }
 
@@ -115,7 +121,9 @@ namespace controller {
     };
 }
 
-#define REGISTER_FILTER_CLASS(classEntry) static Filter::Factory::ClassEntry<classEntry> _factoryEntry;
+#define REGISTER_FILTER_CLASS(classEntry, className) \
+    using FactoryEntry = Filter::Factory::ClassEntry<classEntry, className>;\
+    static FactoryEntry _factoryEntry;
 
 namespace controller {
 
@@ -150,7 +158,8 @@ namespace controller {
         }
         virtual bool parseParameters(const QJsonArray& parameters);
 
-        REGISTER_FILTER_CLASS(ScaleFilter);
+     //   static Filter::Factory::ClassEntry<ScaleFilter, "scale"> _factoryEntry;
+        REGISTER_FILTER_CLASS(ScaleFilter, "scale");
     private:
         float _scale = 1.0f;
     };

From 619fce0d7fa5720b863c62c86e0878d93d11664a Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 14 Oct 2015 13:40:22 -0700
Subject: [PATCH 026/301] Fixing namespace usage in input-plugins

---
 .../src/input-plugins/Joystick.cpp            | 334 +++++++++---------
 .../src/input-plugins/Joystick.h              | 146 ++++----
 .../src/input-plugins/StandardController.cpp  | 242 ++++++-------
 .../src/input-plugins/StandardController.h    |  96 ++---
 .../src/input-plugins/StandardControls.h      | 114 +++---
 5 files changed, 468 insertions(+), 464 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index 5c6f43c604..684b9e80d5 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -1,167 +1,167 @@
-//
-//  Joystick.cpp
-//  input-plugins/src/input-plugins
-//
-//  Created by Stephen Birarda on 2014-09-23.
-//  Copyright 2014 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include <limits>
-
-#include <glm/glm.hpp>
-
-#include "Joystick.h"
-
-#include "StandardControls.h"
-
-const float CONTROLLER_THRESHOLD = 0.3f;
-
-#ifdef HAVE_SDL2
-const float MAX_AXIS = 32768.0f;
-
-Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
-        InputDevice(name),
-    _sdlGameController(sdlGameController),
-    _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
-    _instanceId(instanceId)
-{
-    
-}
-
-#endif
-
-Joystick::~Joystick() {
-    closeJoystick();
-}
-
-void Joystick::closeJoystick() {
-#ifdef HAVE_SDL2
-    SDL_GameControllerClose(_sdlGameController);
-#endif
-}
-
-void Joystick::update(float deltaTime, bool jointsCaptured) {
-    for (auto axisState : _axisStateMap) {
-        if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
-            _axisStateMap[axisState.first] = 0.0f;
-        }
-    }
-}
-
-void Joystick::focusOutEvent() {
-    _axisStateMap.clear();
-    _buttonPressedMap.clear();
-};
-
-#ifdef HAVE_SDL2
-
-void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
-    SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
-    _axisStateMap[makeInput((Controllers::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
-}
-
-void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
-    auto input = makeInput((Controllers::StandardButtonChannel)event.button);
-    bool newValue = event.state == SDL_PRESSED;
-    if (newValue) {
-        _buttonPressedMap.insert(input.getChannel());
-    } else {
-        _buttonPressedMap.erase(input.getChannel());
-    }
-}
-
-#endif
-
-
-void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getFreeDeviceID();
-    
-    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
-    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
-        // Buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "A"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "B"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "X"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Y"));
-
-        // DPad
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "DU"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "DD"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "DL"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "DR"));
-
-        // Bumpers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "LB"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "RB"));
-
-        // Stick press
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "LS"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "RS"));
-
-        // Center buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::START), "Start"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Back"));
-
-        // Analog sticks
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LY), "LY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LX), "LX"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RY), "RY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RX), "RX"));
-
-        // Triggers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "LT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "RT"));
-
-        // Aliases, PlayStation style names
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "R2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "L3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "R3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Select"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "Cross"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "Circle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "Square"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Triangle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "Right"));
-
-        return availableInputs;
-    };
-    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
-    mapper.registerDevice(_deviceID, proxy);
-}
-
-void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
-#ifdef HAVE_SDL2
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    const float DPAD_MOVE_SPEED = 0.5f;
-    const float JOYSTICK_YAW_SPEED = 0.5f;
-    const float JOYSTICK_PITCH_SPEED = 0.25f;
-    const float BOOM_SPEED = 0.1f;
-
-#endif
-}
-
-UserInputMapper::Input Joystick::makeInput(Controllers::StandardButtonChannel button) {
-    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
-}
-
-UserInputMapper::Input Joystick::makeInput(Controllers::StandardAxisChannel axis) {
-    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
-}
-
+//
+//  Joystick.cpp
+//  input-plugins/src/input-plugins
+//
+//  Created by Stephen Birarda on 2014-09-23.
+//  Copyright 2014 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <limits>
+
+#include <glm/glm.hpp>
+
+#include "Joystick.h"
+
+#include "StandardControls.h"
+
+const float CONTROLLER_THRESHOLD = 0.3f;
+
+#ifdef HAVE_SDL2
+const float MAX_AXIS = 32768.0f;
+
+Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
+        InputDevice(name),
+    _sdlGameController(sdlGameController),
+    _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
+    _instanceId(instanceId)
+{
+    
+}
+
+#endif
+
+Joystick::~Joystick() {
+    closeJoystick();
+}
+
+void Joystick::closeJoystick() {
+#ifdef HAVE_SDL2
+    SDL_GameControllerClose(_sdlGameController);
+#endif
+}
+
+void Joystick::update(float deltaTime, bool jointsCaptured) {
+    for (auto axisState : _axisStateMap) {
+        if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
+            _axisStateMap[axisState.first] = 0.0f;
+        }
+    }
+}
+
+void Joystick::focusOutEvent() {
+    _axisStateMap.clear();
+    _buttonPressedMap.clear();
+};
+
+#ifdef HAVE_SDL2
+
+void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
+    SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
+    _axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
+}
+
+void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
+    auto input = makeInput((controller::StandardButtonChannel)event.button);
+    bool newValue = event.state == SDL_PRESSED;
+    if (newValue) {
+        _buttonPressedMap.insert(input.getChannel());
+    } else {
+        _buttonPressedMap.erase(input.getChannel());
+    }
+}
+
+#endif
+
+
+void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
+    // Grab the current free device ID
+    _deviceID = mapper.getFreeDeviceID();
+    
+    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
+    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
+    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
+    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
+        QVector<UserInputMapper::InputPair> availableInputs;
+        // Buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
+
+        // DPad
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
+
+        // Bumpers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
+
+        // Stick press
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
+
+        // Center buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
+
+        // Analog sticks
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
+
+        // Triggers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
+
+        // Aliases, PlayStation style names
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
+
+        return availableInputs;
+    };
+    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
+        mapper.removeAllInputChannelsForDevice(_deviceID);
+        this->assignDefaultInputMapping(mapper);
+        return true;
+    };
+    mapper.registerDevice(_deviceID, proxy);
+}
+
+void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
+#ifdef HAVE_SDL2
+    const float JOYSTICK_MOVE_SPEED = 1.0f;
+    const float DPAD_MOVE_SPEED = 0.5f;
+    const float JOYSTICK_YAW_SPEED = 0.5f;
+    const float JOYSTICK_PITCH_SPEED = 0.25f;
+    const float BOOM_SPEED = 0.1f;
+
+#endif
+}
+
+UserInputMapper::Input Joystick::makeInput(controller::StandardButtonChannel button) {
+    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
+}
+
+UserInputMapper::Input Joystick::makeInput(controller::StandardAxisChannel axis) {
+    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
+}
+
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h
index 70949a8b83..2a7a11d230 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.h
+++ b/libraries/input-plugins/src/input-plugins/Joystick.h
@@ -1,73 +1,73 @@
-//
-//  Joystick.h
-//  input-plugins/src/input-plugins
-//
-//  Created by Stephen Birarda on 2014-09-23.
-//  Copyright 2014 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#ifndef hifi_Joystick_h
-#define hifi_Joystick_h
-
-#include <qobject.h>
-#include <qvector.h>
-
-#ifdef HAVE_SDL2
-#include <SDL.h>
-#undef main
-#endif
-
-#include "InputDevice.h"
-#include "StandardControls.h"
-
-class Joystick : public QObject, public InputDevice {
-    Q_OBJECT
-    Q_PROPERTY(QString name READ getName)
-
-#ifdef HAVE_SDL2
-    Q_PROPERTY(int instanceId READ getInstanceId)
-#endif
-    
-public:
-
-    const QString& getName() const { return _name; }
-
-    // Device functions
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
-    virtual void update(float deltaTime, bool jointsCaptured) override;
-    virtual void focusOutEvent() override;
-    
-    Joystick() : InputDevice("Joystick") {}
-    ~Joystick();
-    
-    UserInputMapper::Input makeInput(Controllers::StandardButtonChannel button);
-    UserInputMapper::Input makeInput(Controllers::StandardAxisChannel axis);
-    
-#ifdef HAVE_SDL2
-    Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
-#endif
-    
-    void closeJoystick();
-
-#ifdef HAVE_SDL2
-    void handleAxisEvent(const SDL_ControllerAxisEvent& event);
-    void handleButtonEvent(const SDL_ControllerButtonEvent& event);
-#endif
-    
-#ifdef HAVE_SDL2
-    int getInstanceId() const { return _instanceId; }
-#endif
-    
-private:
-#ifdef HAVE_SDL2
-    SDL_GameController* _sdlGameController;
-    SDL_Joystick* _sdlJoystick;
-    SDL_JoystickID _instanceId;
-#endif
-};
-
-#endif // hifi_Joystick_h
+//
+//  Joystick.h
+//  input-plugins/src/input-plugins
+//
+//  Created by Stephen Birarda on 2014-09-23.
+//  Copyright 2014 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_Joystick_h
+#define hifi_Joystick_h
+
+#include <qobject.h>
+#include <qvector.h>
+
+#ifdef HAVE_SDL2
+#include <SDL.h>
+#undef main
+#endif
+
+#include "InputDevice.h"
+#include "StandardControls.h"
+
+class Joystick : public QObject, public InputDevice {
+    Q_OBJECT
+    Q_PROPERTY(QString name READ getName)
+
+#ifdef HAVE_SDL2
+    Q_PROPERTY(int instanceId READ getInstanceId)
+#endif
+    
+public:
+
+    const QString& getName() const { return _name; }
+
+    // Device functions
+    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
+    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
+    virtual void focusOutEvent() override;
+    
+    Joystick() : InputDevice("Joystick") {}
+    ~Joystick();
+    
+    UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
+    UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
+    
+#ifdef HAVE_SDL2
+    Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
+#endif
+    
+    void closeJoystick();
+
+#ifdef HAVE_SDL2
+    void handleAxisEvent(const SDL_ControllerAxisEvent& event);
+    void handleButtonEvent(const SDL_ControllerButtonEvent& event);
+#endif
+    
+#ifdef HAVE_SDL2
+    int getInstanceId() const { return _instanceId; }
+#endif
+    
+private:
+#ifdef HAVE_SDL2
+    SDL_GameController* _sdlGameController;
+    SDL_Joystick* _sdlJoystick;
+    SDL_JoystickID _instanceId;
+#endif
+};
+
+#endif // hifi_Joystick_h
diff --git a/libraries/input-plugins/src/input-plugins/StandardController.cpp b/libraries/input-plugins/src/input-plugins/StandardController.cpp
index 988714a962..5460e22c96 100644
--- a/libraries/input-plugins/src/input-plugins/StandardController.cpp
+++ b/libraries/input-plugins/src/input-plugins/StandardController.cpp
@@ -1,121 +1,121 @@
-//
-//  StandardController.cpp
-//  input-plugins/src/input-plugins
-//
-//  Created by Brad Hefta-Gaub on 2015-10-11.
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include <limits>
-
-#include <glm/glm.hpp>
-
-#include "StandardController.h"
-
-const float CONTROLLER_THRESHOLD = 0.3f;
-
-StandardController::~StandardController() {
-}
-
-void StandardController::update(float deltaTime, bool jointsCaptured) {
-}
-
-void StandardController::focusOutEvent() {
-    _axisStateMap.clear();
-    _buttonPressedMap.clear();
-};
-
-void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getStandardDeviceID();
-    
-    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
-    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
-        // Buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "A"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "B"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "X"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Y"));
-
-        // DPad
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "DU"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "DD"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "DL"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "DR"));
-
-        // Bumpers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "LB"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "RB"));
-
-        // Stick press
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "LS"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "RS"));
-
-        // Center buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::START), "Start"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Back"));
-
-        // Analog sticks
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LY), "LY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LX), "LX"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RY), "RY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RX), "RX"));
-
-        // Triggers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "LT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "RT"));
-
-        // Poses
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LeftPose), "LeftPose"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RightPose), "RightPose"));
-
-        // Aliases, PlayStation style names
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "R2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "L3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "R3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Select"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "Cross"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "Circle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "Square"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Triangle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "Right"));
-
-
-        return availableInputs;
-    };
-
-    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
-
-    mapper.registerStandardDevice(proxy);
-}
-
-void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
-}
-
-UserInputMapper::Input StandardController::makeInput(Controllers::StandardButtonChannel button) {
-    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
-}
-
-UserInputMapper::Input StandardController::makeInput(Controllers::StandardAxisChannel axis) {
-    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
-}
-
-UserInputMapper::Input StandardController::makeInput(Controllers::StandardPoseChannel pose) {
-    return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
-}
+//
+//  StandardController.cpp
+//  input-plugins/src/input-plugins
+//
+//  Created by Brad Hefta-Gaub on 2015-10-11.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <limits>
+
+#include <glm/glm.hpp>
+
+#include "StandardController.h"
+
+const float CONTROLLER_THRESHOLD = 0.3f;
+
+StandardController::~StandardController() {
+}
+
+void StandardController::update(float deltaTime, bool jointsCaptured) {
+}
+
+void StandardController::focusOutEvent() {
+    _axisStateMap.clear();
+    _buttonPressedMap.clear();
+};
+
+void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
+    // Grab the current free device ID
+    _deviceID = mapper.getStandardDeviceID();
+    
+    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
+    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
+    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
+    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
+        QVector<UserInputMapper::InputPair> availableInputs;
+        // Buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
+
+        // DPad
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
+
+        // Bumpers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
+
+        // Stick press
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
+
+        // Center buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
+
+        // Analog sticks
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
+
+        // Triggers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
+
+        // Poses
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT), "LeftPose"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT), "RightPose"));
+
+        // Aliases, PlayStation style names
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
+
+
+        return availableInputs;
+    };
+
+    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
+        mapper.removeAllInputChannelsForDevice(_deviceID);
+        this->assignDefaultInputMapping(mapper);
+        return true;
+    };
+
+    mapper.registerStandardDevice(proxy);
+}
+
+void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
+}
+
+UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) {
+    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
+}
+
+UserInputMapper::Input StandardController::makeInput(controller::StandardAxisChannel axis) {
+    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
+}
+
+UserInputMapper::Input StandardController::makeInput(controller::StandardPoseChannel pose) {
+    return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
+}
diff --git a/libraries/input-plugins/src/input-plugins/StandardController.h b/libraries/input-plugins/src/input-plugins/StandardController.h
index fa660e15b8..ad1329d5ed 100644
--- a/libraries/input-plugins/src/input-plugins/StandardController.h
+++ b/libraries/input-plugins/src/input-plugins/StandardController.h
@@ -1,48 +1,48 @@
-//
-//  StandardController.h
-//  input-plugins/src/input-plugins
-//
-//  Created by Brad Hefta-Gaub on 2015-10-11.
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#ifndef hifi_StandardController_h
-#define hifi_StandardController_h
-
-#include <qobject.h>
-#include <qvector.h>
-
-#include "InputDevice.h"
-
-#include "StandardControls.h"
-
-typedef std::shared_ptr<StandardController> StandardControllerPointer;
-
-class StandardController : public QObject, public InputDevice {
-    Q_OBJECT
-    Q_PROPERTY(QString name READ getName)
-
-public:
-
-    const QString& getName() const { return _name; }
-
-    // Device functions
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
-    virtual void update(float deltaTime, bool jointsCaptured) override;
-    virtual void focusOutEvent() override;
-    
-    StandardController() : InputDevice("Standard") {}
-    ~StandardController();
-    
-    UserInputMapper::Input makeInput(Controllers::StandardButtonChannel button);
-    UserInputMapper::Input makeInput(Controllers::StandardAxisChannel axis);
-    UserInputMapper::Input makeInput(Controllers::StandardPoseChannel pose);
-
-private:
-};
-
-#endif // hifi_StandardController_h
+//
+//  StandardController.h
+//  input-plugins/src/input-plugins
+//
+//  Created by Brad Hefta-Gaub on 2015-10-11.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_StandardController_h
+#define hifi_StandardController_h
+
+#include <qobject.h>
+#include <qvector.h>
+
+#include "InputDevice.h"
+
+#include "StandardControls.h"
+
+typedef std::shared_ptr<StandardController> StandardControllerPointer;
+
+class StandardController : public QObject, public InputDevice {
+    Q_OBJECT
+    Q_PROPERTY(QString name READ getName)
+
+public:
+
+    const QString& getName() const { return _name; }
+
+    // Device functions
+    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
+    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
+    virtual void focusOutEvent() override;
+    
+    StandardController() : InputDevice("Standard") {}
+    ~StandardController();
+    
+    UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
+    UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
+    UserInputMapper::Input makeInput(controller::StandardPoseChannel pose);
+
+private:
+};
+
+#endif // hifi_StandardController_h
diff --git a/libraries/input-plugins/src/input-plugins/StandardControls.h b/libraries/input-plugins/src/input-plugins/StandardControls.h
index 9b79bbdae1..e5943ff780 100644
--- a/libraries/input-plugins/src/input-plugins/StandardControls.h
+++ b/libraries/input-plugins/src/input-plugins/StandardControls.h
@@ -1,55 +1,59 @@
-//
-//  Created by Bradley Austin Davis 2015/10/09
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-#pragma once
-
-namespace Controllers {
-
-    // Needs to match order and values of SDL_GameControllerButton
-    enum StandardButtonChannel {
-        // Button quad
-        A = 0,
-        B,
-        X,
-        Y,
-        // Center buttons
-        BACK,
-        GUIDE,
-        START,
-        // Stick press
-        LS,
-        RS,
-        // Bumper press
-        LB,
-        RB,
-        // DPad
-        DU,
-        DD,
-        DL,
-        DR
-    };
-
-    // Needs to match order and values of SDL_GameControllerAxis
-    enum StandardAxisChannel {
-        // Left Analog stick
-        LX = 0,
-        LY,
-        // Right Analog stick
-        RX,
-        RY,
-        // Triggers
-        LT,
-        RT
-    };
-
-    // No correlation to SDL
-    enum StandardPoseChannel {
-        LeftPose = 0,
-        RightPose
-    };
-
-}
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#pragma once
+
+namespace controller {
+
+    // Needs to match order and values of SDL_GameControllerButton
+    enum StandardButtonChannel {
+        // Button quad
+        A = 0,
+        B,
+        X,
+        Y,
+        // Center buttons
+        BACK,
+        GUIDE,
+        START,
+        // Stick press
+        LS,
+        RS,
+        // Bumper press
+        LB,
+        RB,
+        // DPad
+        DU,
+        DD,
+        DL,
+        DR,
+        NUM_STANDARD_BUTTONS
+    };
+
+    // Needs to match order and values of SDL_GameControllerAxis
+    enum StandardAxisChannel {
+        // Left Analog stick
+        LX = 0,
+        LY,
+        // Right Analog stick
+        RX,
+        RY,
+        // Triggers
+        LT,
+        RT,
+        NUM_STANDARD_AXES
+    };
+
+    // No correlation to SDL
+    enum StandardPoseChannel {
+        LEFT = 0,
+        RIGHT,
+        HEAD,
+        NUM_STANDARD_POSES
+    };
+
+}

From 0063f9ae1d9e10fce4ef4e25fe5e9cf477c42340 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 14 Oct 2015 15:16:54 -0700
Subject: [PATCH 027/301] Merging old and new controller interfaces

---
 interface/CMakeLists.txt                      |   5 +-
 interface/src/Application.cpp                 |   6 +-
 interface/src/Application.h                   |   2 +-
 interface/src/devices/3DConnexionClient.h     |   2 +-
 .../ControllerScriptingInterface.cpp          | 140 ++--
 .../scripting/ControllerScriptingInterface.h  | 135 ++--
 interface/src/ui/ApplicationCompositor.cpp    |   2 +-
 libraries/controllers/CMakeLists.txt          |   2 +-
 .../controllers/src/controllers/Endpoint.h    |   2 +-
 .../src/controllers}/InputDevice.cpp          |   0
 .../src/controllers}/InputDevice.h            |   0
 .../NewControllerScriptingInterface.h         |  89 ---
 ...ngInterface.cpp => ScriptingInterface.cpp} | 123 ++-
 .../src/controllers/ScriptingInterface.h      | 138 ++++
 .../src/controllers}/StandardController.cpp   | 242 +++---
 .../src/controllers}/StandardController.h     |  96 +--
 .../src/controllers}/StandardControls.h       | 118 +--
 .../src/controllers}/UserInputMapper.cpp      | 736 +++++++++---------
 .../src/controllers}/UserInputMapper.h        |  56 +-
 .../controllers/impl/MappingBuilderProxy.cpp  |   2 +-
 .../controllers/impl/MappingBuilderProxy.h    |   8 +-
 .../controllers/impl/RouteBuilderProxy.cpp    |   2 +-
 .../src/controllers/impl/RouteBuilderProxy.h  |   8 +-
 libraries/entities-renderer/CMakeLists.txt    |   2 +-
 libraries/input-plugins/CMakeLists.txt        |   2 +-
 .../src/input-plugins/InputPlugin.cpp         |   2 +-
 .../src/input-plugins/Joystick.cpp            |   7 +-
 .../src/input-plugins/Joystick.h              |   4 +-
 .../src/input-plugins/KeyboardMouseDevice.h   |   2 +-
 .../src/input-plugins/SDL2Manager.h           |   4 +-
 .../src/input-plugins/SixenseManager.h        |   3 +-
 .../src/input-plugins/ViveControllerManager.h |   2 +-
 libraries/script-engine/CMakeLists.txt        |   2 +-
 .../AbstractControllerScriptingInterface.h    | 125 ---
 .../src/AbstractScriptingServicesInterface.h  |   7 +-
 libraries/script-engine/src/ScriptEngine.cpp  |  21 +-
 libraries/script-engine/src/ScriptEngine.h    |   7 +-
 tests/controllers/qml/content.qml             |  43 +-
 .../controllers/qml/controls/AnalogButton.qml |   2 +-
 .../controllers/qml/controls/AnalogStick.qml  |   4 +-
 .../qml/controls/ScrollingGraph.qml           |   2 +-
 .../controllers/qml/controls/ToggleButton.qml |   2 +-
 tests/controllers/src/main.cpp                |  30 +-
 43 files changed, 1086 insertions(+), 1101 deletions(-)
 rename libraries/{input-plugins/src/input-plugins => controllers/src/controllers}/InputDevice.cpp (100%)
 rename libraries/{input-plugins/src/input-plugins => controllers/src/controllers}/InputDevice.h (100%)
 delete mode 100644 libraries/controllers/src/controllers/NewControllerScriptingInterface.h
 rename libraries/controllers/src/controllers/{NewControllerScriptingInterface.cpp => ScriptingInterface.cpp} (77%)
 create mode 100644 libraries/controllers/src/controllers/ScriptingInterface.h
 rename libraries/{input-plugins/src/input-plugins => controllers/src/controllers}/StandardController.cpp (98%)
 rename libraries/{input-plugins/src/input-plugins => controllers/src/controllers}/StandardController.h (96%)
 rename libraries/{input-plugins/src/input-plugins => controllers/src/controllers}/StandardControls.h (95%)
 rename libraries/{input-plugins/src/input-plugins => controllers/src/controllers}/UserInputMapper.cpp (93%)
 mode change 100755 => 100644
 rename libraries/{input-plugins/src/input-plugins => controllers/src/controllers}/UserInputMapper.h (96%)
 mode change 100755 => 100644
 delete mode 100644 libraries/script-engine/src/AbstractControllerScriptingInterface.h

diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index 95de0649ad..43db834c3c 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -98,9 +98,8 @@ endif()
 # link required hifi libraries
 link_hifi_libraries(shared octree environment gpu procedural  model render fbx networking model-networking entities avatars 
                     audio audio-client animation script-engine physics 
-                    render-utils entities-renderer ui auto-updater 
-                    plugins display-plugins input-plugins
-                    controllers)
+                    render-utils entities-renderer ui auto-updater
+                    controllers plugins display-plugins input-plugins )
 
 target_bullet()
 target_glew()
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index e0e5003830..77f353a3ff 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -60,7 +60,7 @@
 #include <InfoView.h>
 #include <input-plugins/InputPlugin.h>
 #include <input-plugins/Joystick.h> // this should probably be removed
-#include <input-plugins/UserInputMapper.h>
+#include <controllers/UserInputMapper.h>
 #include <LogHandler.h>
 #include <MainWindow.h>
 #include <MessageDialog.h>
@@ -614,7 +614,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
 
     // Setup the userInputMapper with the actions
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    connect(userInputMapper.data(), &UserInputMapper::actionEvent, &_controllerScriptingInterface, &AbstractControllerScriptingInterface::actionEvent);
+    connect(userInputMapper.data(), &UserInputMapper::actionEvent, &_controllerScriptingInterface, &ControllerScriptingInterface::actionEvent);
     connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
         if (state) {
             switch (action) {
@@ -2708,7 +2708,7 @@ void Application::update(float deltaTime) {
     }
 
     // Dispatch input events
-    _controllerScriptingInterface.updateInputControllers();
+    _controllerScriptingInterface.update();
 
     // Transfer the user inputs to the driveKeys
     myAvatar->clearDriveKeys();
diff --git a/interface/src/Application.h b/interface/src/Application.h
index dc714ad82a..61421c34d6 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -161,7 +161,7 @@ public:
 
     ToolWindow* getToolWindow() { return _toolWindow ; }
 
-    virtual AbstractControllerScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; }
+    virtual controller::ScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; }
     virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine);
 
     QImage renderAvatarBillboard(RenderArgs* renderArgs);
diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h
index cdf8e1e2a1..bddb86a857 100755
--- a/interface/src/devices/3DConnexionClient.h
+++ b/interface/src/devices/3DConnexionClient.h
@@ -13,7 +13,7 @@
 
 #include <QObject>
 #include <QLibrary>
-#include <input-plugins/UserInputMapper.h>
+#include <controllers/UserInputMapper.h>
 
 #include "InterfaceLogging.h"
 
diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp
index 54aa72da6b..1a212fbea9 100644
--- a/interface/src/scripting/ControllerScriptingInterface.cpp
+++ b/interface/src/scripting/ControllerScriptingInterface.cpp
@@ -9,21 +9,19 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
+#include "ControllerScriptingInterface.h"
+
 #include <avatar/AvatarManager.h>
 #include <avatar/MyAvatar.h>
 #include <HandData.h>
 #include <HFBackEvent.h>
 
-#include <controllers/NewControllerScriptingInterface.h>
-
 #include "Application.h"
 #include "devices/MotionTracker.h"
-#include "ControllerScriptingInterface.h"
 
 // TODO: this needs to be removed, as well as any related controller-specific information
 #include <input-plugins/SixenseManager.h>
 
-
 ControllerScriptingInterface::ControllerScriptingInterface() :
     _mouseCaptured(false),
     _touchCaptured(false),
@@ -34,7 +32,6 @@ ControllerScriptingInterface::ControllerScriptingInterface() :
 }
 
 ControllerScriptingInterface::~ControllerScriptingInterface() {
-    delete _newControllerScriptingInterface;
 }
 
 
@@ -126,13 +123,6 @@ void ControllerScriptingInterface::registerControllerTypes(ScriptEngine* engine)
     qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue);
     qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
     qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
-
-    wireUpControllers(engine);
-
-    // hack in the new controller scripting interface...
-    _newControllerScriptingInterface = new controller::NewControllerScriptingInterface();
-    engine->registerGlobalObject("NewControllers", _newControllerScriptingInterface);
-
 }
 
 void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
@@ -192,6 +182,7 @@ const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const
     return NULL;
 }
 
+/*
 bool ControllerScriptingInterface::isPrimaryButtonPressed() const {
     const PalmData* primaryPalm = getPrimaryPalm();
     if (primaryPalm) {
@@ -345,6 +336,7 @@ glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex
     }
     return glm::vec3(0); // bad index
 }
+*/
 
 bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const {
     return isKeyCaptured(KeyEvent(*event));
@@ -395,96 +387,49 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
     return qApp->getUiSize();
 }
 
-QString ControllerScriptingInterface::sanatizeName(const QString& name) {
-    QString cleanName { name };
-    cleanName.remove(QRegularExpression{"[\\(\\)\\.\\s]"});
-    return cleanName;
-}
-
-void ControllerScriptingInterface::wireUpControllers(ScriptEngine* engine) {
-
-    // Controller.Standard.*
-    auto standardDevice = DependencyManager::get<UserInputMapper>()->getStandardDevice();
-    if (standardDevice) {
-        auto deviceName = sanatizeName(standardDevice->getName());
-        auto deviceInputs = standardDevice->getAvailabeInputs();
-        for (const auto& inputMapping : deviceInputs) {
-            auto input = inputMapping.first;
-            auto inputName = sanatizeName(inputMapping.second);
-            QString deviceInputName{ "Controller." + deviceName + "." + inputName };
-            engine->registerValue(deviceInputName, input.getID());
-        }
-    }
-
-    // Controller.Hardware.*
-    auto devices = DependencyManager::get<UserInputMapper>()->getDevices();
-    for(const auto& deviceMapping : devices) {
-        auto device = deviceMapping.second.get();
-        auto deviceName = sanatizeName(device->getName());
-        auto deviceInputs = device->getAvailabeInputs();
-        for (const auto& inputMapping : deviceInputs) {
-            auto input = inputMapping.first;
-            auto inputName = sanatizeName(inputMapping.second);
-            QString deviceInputName { "Controller.Hardware." + deviceName + "." + inputName };
-            engine->registerValue(deviceInputName, input.getID());
-        }
-    }
-
-    // Controller.Actions.*
-    auto actionNames = DependencyManager::get<UserInputMapper>()->getActionNames();
-    int actionNumber = 0;
-    for (const auto& actionName : actionNames) {
-        QString safeActionName { "Controller.Actions." + sanatizeName(actionName) };
-        engine->registerValue(safeActionName, actionNumber);
-        actionNumber++;
-    }
-}
-
-AbstractInputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
+controller::InputController::Pointer ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
     // This is where we retreive the Device Tracker category and then the sub tracker within it
-    //TODO C++11 auto icIt = _inputControllers.find(0);
-    InputControllerMap::iterator icIt = _inputControllers.find(0);
-
+    auto icIt = _inputControllers.find(0);
     if (icIt != _inputControllers.end()) {
         return (*icIt).second;
-    } else {
+    } 
 
-        // Look for device
-        DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString());
-        if (deviceID < 0) {
-            deviceID = 0;
-        }
-        // TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion)
-        // in the near future we need to change that to a real mapping between the devices and the deviceName
-        // ALso we need to expand the spec so we can fall back on  the "default" controller per categories
 
-        if (deviceID >= 0) {
-            // TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices
-            MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID));
-            if (motionTracker) {
-                MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString());
-                if (trackerID >= 0) {
-                    AbstractInputController* inputController = new InputController(deviceID, trackerID, this);
+    // Look for device
+    DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString());
+    if (deviceID < 0) {
+        deviceID = 0;
+    }
+    // TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion)
+    // in the near future we need to change that to a real mapping between the devices and the deviceName
+    // ALso we need to expand the spec so we can fall back on  the "default" controller per categories
 
-                    _inputControllers.insert(InputControllerMap::value_type(inputController->getKey(), inputController));
-
-                    return inputController;
-                }
+    if (deviceID >= 0) {
+        // TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices
+        MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID));
+        if (motionTracker) {
+            MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString());
+            if (trackerID >= 0) {
+                controller::InputController::Pointer inputController = std::make_shared<InputController>(deviceID, trackerID, this);
+                controller::InputController::Key key = inputController->getKey();
+                _inputControllers.insert(InputControllerMap::value_type(inputController->getKey(), inputController));
+                return inputController;
             }
         }
-
-        return 0;
     }
+
+    return controller::InputController::Pointer();
 }
 
-void ControllerScriptingInterface::releaseInputController(AbstractInputController* input) {
+void ControllerScriptingInterface::releaseInputController(controller::InputController::Pointer input) {
     _inputControllers.erase(input->getKey());
 }
 
-void ControllerScriptingInterface::updateInputControllers() {
-    //TODO C++11 for (auto it = _inputControllers.begin(); it != _inputControllers.end(); it++) {
-    for (InputControllerMap::iterator it = _inputControllers.begin(); it != _inputControllers.end(); it++) {
-        (*it).second->update();
+void ControllerScriptingInterface::update() {
+    controller::ScriptingInterface::update();
+
+    for (auto entry : _inputControllers) {
+        entry.second->update();
     }
 }
 
@@ -545,7 +490,6 @@ QVector<QString> ControllerScriptingInterface::getActionNames() const {
 }
 
 InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
-    AbstractInputController(),
     _deviceTrackerId(deviceTrackerId),
     _subTrackerId(subTrackerId),
     _isActive(false)
@@ -568,7 +512,7 @@ void InputController::update() {
                 joint->getLocFrame().getRotation(_eventCache.locRotation);
 
                 _isActive = true;
-                emit spatialEvent(_eventCache);
+                //emit spatialEvent(_eventCache);
             }
         }
     }
@@ -580,3 +524,19 @@ const unsigned int INPUTCONTROLLER_KEY_DEVICE_MASK = 16;
 InputController::Key InputController::getKey() const {
     return (((_deviceTrackerId & INPUTCONTROLLER_KEY_DEVICE_MASK) << INPUTCONTROLLER_KEY_DEVICE_OFFSET) | _subTrackerId);
 }
+
+
+void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
+void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }
+
+void ControllerScriptingInterface::emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); }
+void ControllerScriptingInterface::emitMousePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mousePressEvent(MouseEvent(*event, deviceID)); }
+void ControllerScriptingInterface::emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); }
+void ControllerScriptingInterface::emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); }
+
+void ControllerScriptingInterface::emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }
+void ControllerScriptingInterface::emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); }
+void ControllerScriptingInterface::emitTouchUpdateEvent(const TouchEvent& event) { emit touchUpdateEvent(event); }
+
+void ControllerScriptingInterface::emitWheelEvent(QWheelEvent* event) { emit wheelEvent(*event); }
+
diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h
index dfe87043cd..652bd640b1 100644
--- a/interface/src/scripting/ControllerScriptingInterface.h
+++ b/interface/src/scripting/ControllerScriptingInterface.h
@@ -14,15 +14,20 @@
 
 #include <QtCore/QObject>
 
-#include <input-plugins/UserInputMapper.h>
+#include <controllers/UserInputMapper.h>
+#include <controllers/ScriptingInterface.h>
+
+#include <HFActionEvent.h>
+#include <KeyEvent.h>
+#include <MouseEvent.h>
+#include <SpatialEvent.h>
+#include <TouchEvent.h>
+#include <WheelEvent.h>
+class ScriptEngine;
 
-#include <AbstractControllerScriptingInterface.h>
 class PalmData;
-namespace controller {
-    class NewControllerScriptingInterface;
-}
 
-class InputController : public  AbstractInputController {
+class InputController : public  controller::InputController {
     Q_OBJECT
 
 public:
@@ -53,30 +58,53 @@ signals:
  
 
 /// handles scripting of input controller commands from JS
-class ControllerScriptingInterface : public AbstractControllerScriptingInterface {
+class ControllerScriptingInterface : public controller::ScriptingInterface {
     Q_OBJECT
 
+
 public:    
     ControllerScriptingInterface();
     ~ControllerScriptingInterface();
 
+    Q_INVOKABLE QVector<UserInputMapper::Action> getAllActions();
+
+    Q_INVOKABLE bool addInputChannel(UserInputMapper::InputChannel inputChannel);
+    Q_INVOKABLE bool removeInputChannel(UserInputMapper::InputChannel inputChannel);
+    Q_INVOKABLE QVector<UserInputMapper::InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
+
+    Q_INVOKABLE QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
+    Q_INVOKABLE QVector<UserInputMapper::InputChannel> getAllInputsForDevice(unsigned int device);
+
+    Q_INVOKABLE QString getDeviceName(unsigned int device);
+
+    Q_INVOKABLE float getActionValue(int action);
+
+    Q_INVOKABLE void resetDevice(unsigned int device);
+    Q_INVOKABLE void resetAllDeviceBindings();
+    Q_INVOKABLE int findDevice(QString name);
+    Q_INVOKABLE QVector<QString> getDeviceNames();
+
+    Q_INVOKABLE int findAction(QString actionName);
+    Q_INVOKABLE QVector<QString> getActionNames() const;
+
+
     virtual void registerControllerTypes(ScriptEngine* engine);
     
-    void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
-    void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }
+    void emitKeyPressEvent(QKeyEvent* event);
+    void emitKeyReleaseEvent(QKeyEvent* event);
     
     void handleMetaEvent(HFMetaEvent* event);
 
-    void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); }
-    void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); }
-    void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); }
-    void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); }
+    void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0);
+    void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0); 
+    void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0);
+    void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0);
 
-    void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }
-    void emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); }
-    void emitTouchUpdateEvent(const TouchEvent& event) { emit touchUpdateEvent(event); }
+    void emitTouchBeginEvent(const TouchEvent& event);
+    void emitTouchEndEvent(const TouchEvent& event); 
+    void emitTouchUpdateEvent(const TouchEvent& event);
     
-    void emitWheelEvent(QWheelEvent* event) { emit wheelEvent(*event); }
+    void emitWheelEvent(QWheelEvent* event);
 
     bool isKeyCaptured(QKeyEvent* event) const;
     bool isKeyCaptured(const KeyEvent& event) const;
@@ -86,48 +114,10 @@ public:
     bool areActionsCaptured() const { return _actionsCaptured; }
     bool isJoystickCaptured(int joystickIndex) const;
 
-    void updateInputControllers();
+    virtual void update() override;
 
 public slots:
-    Q_INVOKABLE virtual QVector<UserInputMapper::Action> getAllActions();
-    
-    Q_INVOKABLE virtual bool addInputChannel(UserInputMapper::InputChannel inputChannel);
-    Q_INVOKABLE virtual bool removeInputChannel(UserInputMapper::InputChannel inputChannel);
-    Q_INVOKABLE virtual QVector<UserInputMapper::InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
-    
-    Q_INVOKABLE virtual QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
-    Q_INVOKABLE virtual QVector<UserInputMapper::InputChannel> getAllInputsForDevice(unsigned int device);
-    
-    Q_INVOKABLE virtual QString getDeviceName(unsigned int device);
-    
-    Q_INVOKABLE virtual float getActionValue(int action);
 
-    Q_INVOKABLE virtual void resetDevice(unsigned int device);
-    Q_INVOKABLE virtual void resetAllDeviceBindings();
-    Q_INVOKABLE virtual int findDevice(QString name);
-    Q_INVOKABLE virtual QVector<QString> getDeviceNames();
-    
-    Q_INVOKABLE virtual int findAction(QString actionName);
-    Q_INVOKABLE virtual QVector<QString> getActionNames() const;
-
-    virtual bool isPrimaryButtonPressed() const;
-    virtual glm::vec2 getPrimaryJoystickPosition() const;
-
-    virtual int getNumberOfButtons() const;
-    virtual bool isButtonPressed(int buttonIndex) const;
-
-    virtual int getNumberOfTriggers() const;
-    virtual float getTriggerValue(int triggerIndex) const;
-
-    virtual int getNumberOfJoysticks() const;
-    virtual glm::vec2 getJoystickPosition(int joystickIndex) const;
-
-    virtual int getNumberOfSpatialControls() const;
-    virtual glm::vec3 getSpatialControlPosition(int controlIndex) const;
-    virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const;
-    virtual glm::vec3 getSpatialControlNormal(int controlIndex) const;
-    virtual glm::quat getSpatialControlRawRotation(int controlIndex) const;
-    virtual glm::vec3 getSpatialControlRawAngularVelocity(int controlIndex) const;
     virtual void captureKeyEvents(const KeyEvent& event);
     virtual void releaseKeyEvents(const KeyEvent& event);
 
@@ -149,9 +139,31 @@ public slots:
     virtual glm::vec2 getViewportDimensions() const;
 
     /// Factory to create an InputController
-    virtual AbstractInputController* createInputController(const QString& deviceName, const QString& tracker);
+    virtual controller::InputController::Pointer createInputController(const QString& deviceName, const QString& tracker);
+    virtual void releaseInputController(controller::InputController::Pointer input);
 
-    virtual void releaseInputController(AbstractInputController* input);
+signals:
+    void keyPressEvent(const KeyEvent& event);
+    void keyReleaseEvent(const KeyEvent& event);
+
+    void actionStartEvent(const HFActionEvent& event);
+    void actionEndEvent(const HFActionEvent& event);
+
+    void backStartEvent();
+    void backEndEvent();
+
+    void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0);
+    void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
+    void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
+    void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0);
+
+    void touchBeginEvent(const TouchEvent& event);
+    void touchEndEvent(const TouchEvent& event);
+    void touchUpdateEvent(const TouchEvent& event);
+
+    void wheelEvent(const WheelEvent& event);
+
+    void actionEvent(int action, float state);
 
 private:
     QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript
@@ -168,12 +180,9 @@ private:
     QMultiMap<int,KeyEvent> _capturedKeys;
     QSet<int> _capturedJoysticks;
 
-    typedef std::map< AbstractInputController::Key, AbstractInputController* > InputControllerMap;
+    using InputKey = controller::InputController::Key;
+    using InputControllerMap = std::map<InputKey, controller::InputController::Pointer>;
     InputControllerMap _inputControllers;
-
-    void wireUpControllers(ScriptEngine* engine);
-
-    controller::NewControllerScriptingInterface* _newControllerScriptingInterface = nullptr;
 };
 
 const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip
diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp
index 4e5dd0da0c..4fc2f3ddb4 100644
--- a/interface/src/ui/ApplicationCompositor.cpp
+++ b/interface/src/ui/ApplicationCompositor.cpp
@@ -27,7 +27,7 @@
 
 #include "Application.h"
 #include <input-plugins/SixenseManager.h> // TODO: any references to sixense should be removed here
-#include <input-plugins/InputDevice.h>
+#include <controllers/InputDevice.h>
 
 
 // Used to animate the magnification windows
diff --git a/libraries/controllers/CMakeLists.txt b/libraries/controllers/CMakeLists.txt
index fbabbe1463..5beffce461 100644
--- a/libraries/controllers/CMakeLists.txt
+++ b/libraries/controllers/CMakeLists.txt
@@ -4,7 +4,7 @@ set(TARGET_NAME controllers)
 setup_hifi_library(Script)
 
 # use setup_hifi_library macro to setup our project and link appropriate Qt modules
-link_hifi_libraries(shared plugins input-plugins)
+link_hifi_libraries(shared)
 
 GroupSources("src/controllers")
 
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index bea33517f5..5c6e6c028b 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -14,7 +14,7 @@
 #include <memory>
 #include <functional>
 
-#include <input-plugins/UserInputMapper.h>
+#include "UserInputMapper.h"
 
 class QScriptValue;
 
diff --git a/libraries/input-plugins/src/input-plugins/InputDevice.cpp b/libraries/controllers/src/controllers/InputDevice.cpp
similarity index 100%
rename from libraries/input-plugins/src/input-plugins/InputDevice.cpp
rename to libraries/controllers/src/controllers/InputDevice.cpp
diff --git a/libraries/input-plugins/src/input-plugins/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h
similarity index 100%
rename from libraries/input-plugins/src/input-plugins/InputDevice.h
rename to libraries/controllers/src/controllers/InputDevice.h
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
deleted file mode 100644
index 659c8bfd05..0000000000
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
+++ /dev/null
@@ -1,89 +0,0 @@
-//
-//  Created by Bradley Austin Davis 2015/10/09
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#pragma once
-#ifndef hifi_Controllers_NewControllerScriptingInterface_h
-#define hifi_Controllers_NewControllerScriptingInterface_h
-
-#include <unordered_map>
-#include <unordered_set>
-#include <map>
-#include <set>
-
-#include <QtCore/QObject>
-#include <QtCore/QVariant>
-
-#include <QtQml/QJSValue>
-#include <QtScript/QScriptValue>
-
-#include <input-plugins/UserInputMapper.h>
-
-#include "Mapping.h"
-
-class QScriptValue;
-
-namespace controller {
-    class NewControllerScriptingInterface : public QObject {
-        Q_OBJECT
-        Q_PROPERTY(QVariantMap Hardware READ getHardware CONSTANT FINAL)
-        Q_PROPERTY(QVariantMap Actions READ getActions CONSTANT FINAL)
-        Q_PROPERTY(QVariantMap Standard READ getStandard CONSTANT FINAL)
-
-    public:
-        NewControllerScriptingInterface();
-        Q_INVOKABLE float getValue(const int& source);
-
-        Q_INVOKABLE void update();
-        Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
-        Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
-        Q_INVOKABLE void disableMapping(const QString& mappingName) {
-            enableMapping(mappingName, false);
-        }
-
-
-        const QVariantMap& getHardware() { return _hardware; }
-        const QVariantMap& getActions() { return _actions; }
-        const QVariantMap& getStandard() { return _standard; }
-
-    private:
-
-        // FIXME move to unordered set / map
-        using MappingMap = std::map<QString, Mapping::Pointer>;
-        using MappingStack = std::list<Mapping::Pointer>;
-        using InputToEndpointMap = std::map<UserInputMapper::Input, Endpoint::Pointer>;
-        using EndpointSet = std::unordered_set<Endpoint::Pointer>;
-        using ValueMap = std::map<Endpoint::Pointer, float>;
-        using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
-        using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
-
-        void update(Mapping::Pointer& mapping, EndpointSet& consumed);
-        float getValue(const Endpoint::Pointer& endpoint);
-        Endpoint::Pointer endpointFor(const QJSValue& endpoint);
-        Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
-        Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint);
-        Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
-
-        friend class MappingBuilderProxy;
-        friend class RouteBuilderProxy;
-    private:
-        uint16_t _nextFunctionId;
-        InputToEndpointMap _endpoints;
-        EndpointPairMap _compositeEndpoints;
-
-        ValueMap _overrideValues;
-        MappingMap _mappingsByName;
-        MappingStack _activeMappings;
-
-        QVariantMap _hardware;
-        QVariantMap _actions;
-        QVariantMap _standard;
-    };
-}
-
-
-#endif
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
similarity index 77%
rename from libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
rename to libraries/controllers/src/controllers/ScriptingInterface.cpp
index 4bc5b9eeb5..9d2cdfd2de 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -5,7 +5,7 @@
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
-#include "NewControllerScriptingInterface.h"
+#include "ScriptingInterface.h"
 
 #include <mutex>
 #include <set>
@@ -14,19 +14,15 @@
 
 #include <GLMHelpers.h>
 #include <DependencyManager.h>
-#include <input-plugins/UserInputMapper.h>
-#include <input-plugins/InputPlugin.h>
-#include <input-plugins/KeyboardMouseDevice.h>
-#include <plugins/PluginManager.h>
 
 #include "impl/MappingBuilderProxy.h"
 #include "Logging.h"
+#include "InputDevice.h"
 
 static const uint16_t ACTIONS_DEVICE = UserInputMapper::Input::INVALID_DEVICE - (uint16_t)1;
 
 namespace controller {
 
-
     class VirtualEndpoint : public Endpoint {
     public:
         VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input(-1))
@@ -97,18 +93,15 @@ namespace controller {
         Endpoint::Pointer _second;
     };
 
-    QString sanatizeName(const QString& name) {
-        QString cleanName{ name };
-        cleanName.remove(QRegularExpression{ "[\\(\\)\\.\\s]" });
-        return cleanName;
-    }
+
+    QRegularExpression ScriptingInterface::SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" };
 
     QVariantMap createDeviceMap(const UserInputMapper::DeviceProxy* device) {
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
         QVariantMap deviceMap;
         for (const auto& inputMapping : device->getAvailabeInputs()) {
             const auto& input = inputMapping.first;
-            const auto inputName = sanatizeName(inputMapping.second);
+            const auto inputName = QString(inputMapping.second).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
             qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType()
                 << QString::number(input.getID(), 16) << ": " << inputName;
             deviceMap.insert(inputName, input.getID());
@@ -116,12 +109,12 @@ namespace controller {
         return deviceMap;
     }
 
-    NewControllerScriptingInterface::NewControllerScriptingInterface() {
+    ScriptingInterface::ScriptingInterface() {
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
         auto devices = userInputMapper->getDevices();
         for (const auto& deviceMapping : devices) {
             auto device = deviceMapping.second.get();
-            auto deviceName = sanatizeName(device->getName());
+            auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
             qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
             // Expose the IDs to JS
             _hardware.insert(deviceName, createDeviceMap(device));
@@ -164,7 +157,8 @@ namespace controller {
             UserInputMapper::Input actionInput(ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
             qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16);
             // Expose the IDs to JS
-            _actions.insert(sanatizeName(actionName), actionInput.getID());
+            QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
+            _actions.insert(cleanActionName, actionInput.getID());
 
             // Create the endpoints
             // FIXME action endpoints need to accumulate values, and have them cleared at each frame
@@ -172,7 +166,7 @@ namespace controller {
         }
     }
 
-    QObject* NewControllerScriptingInterface::newMapping(const QString& mappingName) {
+    QObject* ScriptingInterface::newMapping(const QString& mappingName) {
         if (_mappingsByName.count(mappingName)) {
             qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
         }
@@ -182,7 +176,7 @@ namespace controller {
         return new MappingBuilderProxy(*this, mapping);
     }
 
-    void NewControllerScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
+    void ScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
         auto iterator = _mappingsByName.find(mappingName);
         if (_mappingsByName.end() == iterator) {
             qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName;
@@ -202,7 +196,7 @@ namespace controller {
         }
     }
 
-    float NewControllerScriptingInterface::getValue(const int& source) {
+    float ScriptingInterface::getValue(const int& source) const {
         // return (sin(secTimestampNow()) + 1.0f) / 2.0f;
         UserInputMapper::Input input(source);
         auto iterator = _endpoints.find(input);
@@ -214,7 +208,7 @@ namespace controller {
         return getValue(endpoint);
     }
 
-    float NewControllerScriptingInterface::getValue(const Endpoint::Pointer& endpoint) {
+    float ScriptingInterface::getValue(const Endpoint::Pointer& endpoint) const {
         auto valuesIterator = _overrideValues.find(endpoint);
         if (_overrideValues.end() != valuesIterator) {
             return valuesIterator->second;
@@ -223,19 +217,20 @@ namespace controller {
         return endpoint->value();
     }
 
-        
-    void NewControllerScriptingInterface::update() {
-        static float last = secTimestampNow();
-        float now = secTimestampNow();
-        float delta = now - last;
-        last = now;
+    float ScriptingInterface::getButtonValue(StandardButtonChannel source, uint16_t device) const {
+        return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::BUTTON).getID());
+    }
 
-        foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
-            inputPlugin->pluginUpdate(delta, false);
-        }
+    float ScriptingInterface::getAxisValue(StandardAxisChannel source, uint16_t device) const {
+        return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID());
+    }
 
+    glm::mat4 ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
+        return glm::mat4();
+    }
+
+    void ScriptingInterface::update() {
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        userInputMapper->update(delta);
 
         _overrideValues.clear();
         EndpointSet readEndpoints;
@@ -295,9 +290,7 @@ namespace controller {
         }
     }
 
-
-
-    Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const QJSValue& endpoint) {
+    Endpoint::Pointer ScriptingInterface::endpointFor(const QJSValue& endpoint) {
         if (endpoint.isNumber()) {
             return endpointFor(UserInputMapper::Input(endpoint.toInt()));
         }
@@ -311,7 +304,7 @@ namespace controller {
         return Endpoint::Pointer();
     }
 
-    Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const QScriptValue& endpoint) {
+    Endpoint::Pointer ScriptingInterface::endpointFor(const QScriptValue& endpoint) {
         if (endpoint.isNumber()) {
             return endpointFor(UserInputMapper::Input(endpoint.toInt32()));
         }
@@ -325,7 +318,7 @@ namespace controller {
         return Endpoint::Pointer();
     }
 
-    Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) {
+    Endpoint::Pointer ScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) {
         auto iterator = _endpoints.find(inputId);
         if (_endpoints.end() == iterator) {
             qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
@@ -334,7 +327,7 @@ namespace controller {
         return iterator->second;
     }
 
-    Endpoint::Pointer NewControllerScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) {
+    Endpoint::Pointer ScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) {
         EndpointPair pair(first, second);
         Endpoint::Pointer result;
         auto iterator = _compositeEndpoints.find(pair);
@@ -347,6 +340,66 @@ namespace controller {
         return result;
     }
 
+    bool ScriptingInterface::isPrimaryButtonPressed() const {
+        return isButtonPressed(StandardButtonChannel::A);
+    }
+        
+    glm::vec2 ScriptingInterface::getPrimaryJoystickPosition() const {
+        return getJoystickPosition(0);
+    }
+
+    int ScriptingInterface::getNumberOfButtons() const {
+        return StandardButtonChannel::NUM_STANDARD_BUTTONS;
+    }
+
+    bool ScriptingInterface::isButtonPressed(int buttonIndex) const {
+        return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0 ? false : true;
+    }
+
+    int ScriptingInterface::getNumberOfTriggers() const {
+        return 2;
+    }
+
+    float ScriptingInterface::getTriggerValue(int triggerIndex) const {
+        return getAxisValue(triggerIndex == 0 ? StandardAxisChannel::LT : StandardAxisChannel::RT);
+    }
+
+    int ScriptingInterface::getNumberOfJoysticks() const {
+        return 2;
+    }
+
+    glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const {
+        StandardAxisChannel xid = StandardAxisChannel::LX; 
+        StandardAxisChannel yid = StandardAxisChannel::LY;
+        if (joystickIndex != 0) {
+            xid = StandardAxisChannel::RX;
+            yid = StandardAxisChannel::RY;
+        }
+        vec2 result;
+        result.x = getAxisValue(xid);
+        result.y = getAxisValue(yid);
+        return result;
+    }
+
+    int ScriptingInterface::getNumberOfSpatialControls() const {
+        return 2;
+    }
+
+    glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const {
+        return vec3();
+    }
+
+    glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
+        return vec3();
+    }
+
+    glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const {
+        return vec3();
+    }
+    
+    glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
+        return quat();
+    }
 } // namespace controllers
 
 //var mapping = Controller.newMapping();
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
new file mode 100644
index 0000000000..043e06a67f
--- /dev/null
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -0,0 +1,138 @@
+//
+//  AbstractControllerScriptingInterface.h
+//  libraries/script-engine/src
+//
+//  Created by Brad Hefta-Gaub on 12/17/13.
+//  Copyright 2013 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_AbstractControllerScriptingInterface_h
+#define hifi_AbstractControllerScriptingInterface_h
+
+#include <unordered_map>
+#include <unordered_set>
+#include <map>
+#include <set>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/quaternion.hpp>
+
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+
+#include <QtQml/QJSValue>
+#include <QtScript/QScriptValue>
+
+#include "UserInputMapper.h"
+#include "StandardControls.h"
+#include "Mapping.h"
+
+namespace controller {
+    class InputController : public QObject {
+        Q_OBJECT
+
+    public:
+        using Key = unsigned int;
+        using Pointer = std::shared_ptr<InputController>;
+
+        virtual void update() = 0;
+        virtual Key getKey() const = 0;
+
+    public slots:
+        virtual bool isActive() const = 0;
+        virtual glm::vec3 getAbsTranslation() const = 0;
+        virtual glm::quat getAbsRotation() const = 0;
+        virtual glm::vec3 getLocTranslation() const = 0;
+        virtual glm::quat getLocRotation() const = 0;
+
+    signals:
+        //void spatialEvent(const SpatialEvent& event);
+    };
+
+    /// handles scripting of input controller commands from JS
+    class ScriptingInterface : public QObject {
+        Q_OBJECT
+        Q_PROPERTY(QVariantMap Hardware READ getHardware CONSTANT FINAL)
+        Q_PROPERTY(QVariantMap Actions READ getActions CONSTANT FINAL)
+        Q_PROPERTY(QVariantMap Standard READ getStandard CONSTANT FINAL)
+
+    public:
+        ScriptingInterface();
+
+        Q_INVOKABLE float getValue(const int& source) const;
+        Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
+        Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const;
+        Q_INVOKABLE glm::mat4 getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
+        Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
+        Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
+        Q_INVOKABLE void disableMapping(const QString& mappingName) {
+            enableMapping(mappingName, false);
+        }
+
+        Q_INVOKABLE bool isPrimaryButtonPressed() const;
+        Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const;
+
+        Q_INVOKABLE int getNumberOfButtons() const;
+        Q_INVOKABLE bool isButtonPressed(int buttonIndex) const;
+
+        Q_INVOKABLE int getNumberOfTriggers() const;
+        Q_INVOKABLE float getTriggerValue(int triggerIndex) const;
+
+        Q_INVOKABLE int getNumberOfJoysticks() const;
+        Q_INVOKABLE glm::vec2 getJoystickPosition(int joystickIndex) const;
+
+        Q_INVOKABLE int getNumberOfSpatialControls() const;
+        Q_INVOKABLE glm::vec3 getSpatialControlPosition(int controlIndex) const;
+        Q_INVOKABLE glm::vec3 getSpatialControlVelocity(int controlIndex) const;
+        Q_INVOKABLE glm::vec3 getSpatialControlNormal(int controlIndex) const;
+        Q_INVOKABLE glm::quat getSpatialControlRawRotation(int controlIndex) const;
+
+        Q_INVOKABLE const QVariantMap& getHardware() { return _hardware; }
+        Q_INVOKABLE const QVariantMap& getActions() { return _actions; }
+        Q_INVOKABLE const QVariantMap& getStandard() { return _standard; }
+
+        static QRegularExpression SANITIZE_NAME_EXPRESSION;
+
+    public slots:
+        virtual void update();
+        //virtual void registerControllerTypes(ScriptEngine* engine) = 0;
+
+    private:
+        friend class MappingBuilderProxy;
+        friend class RouteBuilderProxy;
+
+        // FIXME move to unordered set / map
+        using MappingMap = std::map<QString, Mapping::Pointer>;
+        using MappingStack = std::list<Mapping::Pointer>;
+        using InputToEndpointMap = std::map<UserInputMapper::Input, Endpoint::Pointer>;
+        using EndpointSet = std::unordered_set<Endpoint::Pointer>;
+        using ValueMap = std::map<Endpoint::Pointer, float>;
+        using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
+        using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
+
+        void update(Mapping::Pointer& mapping, EndpointSet& consumed);
+        float getValue(const Endpoint::Pointer& endpoint) const;
+        Endpoint::Pointer endpointFor(const QJSValue& endpoint);
+        Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
+        Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint);
+        Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
+
+        QVariantMap _hardware;
+        QVariantMap _actions;
+        QVariantMap _standard;
+
+        InputToEndpointMap _endpoints;
+        EndpointPairMap _compositeEndpoints;
+
+        ValueMap _overrideValues;
+        MappingMap _mappingsByName;
+        MappingStack _activeMappings;
+    };
+}
+
+
+#endif // hifi_AbstractControllerScriptingInterface_h
diff --git a/libraries/input-plugins/src/input-plugins/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
similarity index 98%
rename from libraries/input-plugins/src/input-plugins/StandardController.cpp
rename to libraries/controllers/src/controllers/StandardController.cpp
index 5460e22c96..9c423eded2 100644
--- a/libraries/input-plugins/src/input-plugins/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -1,121 +1,121 @@
-//
-//  StandardController.cpp
-//  input-plugins/src/input-plugins
-//
-//  Created by Brad Hefta-Gaub on 2015-10-11.
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include <limits>
-
-#include <glm/glm.hpp>
-
-#include "StandardController.h"
-
-const float CONTROLLER_THRESHOLD = 0.3f;
-
-StandardController::~StandardController() {
-}
-
-void StandardController::update(float deltaTime, bool jointsCaptured) {
-}
-
-void StandardController::focusOutEvent() {
-    _axisStateMap.clear();
-    _buttonPressedMap.clear();
-};
-
-void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getStandardDeviceID();
-    
-    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
-    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
-        // Buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
-
-        // DPad
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
-
-        // Bumpers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
-
-        // Stick press
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
-
-        // Center buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
-
-        // Analog sticks
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
-
-        // Triggers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
-
-        // Poses
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT), "LeftPose"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT), "RightPose"));
-
-        // Aliases, PlayStation style names
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
-
-
-        return availableInputs;
-    };
-
-    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
-
-    mapper.registerStandardDevice(proxy);
-}
-
-void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
-}
-
-UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) {
-    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
-}
-
-UserInputMapper::Input StandardController::makeInput(controller::StandardAxisChannel axis) {
-    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
-}
-
-UserInputMapper::Input StandardController::makeInput(controller::StandardPoseChannel pose) {
-    return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
-}
+//
+//  StandardController.cpp
+//  input-plugins/src/input-plugins
+//
+//  Created by Brad Hefta-Gaub on 2015-10-11.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <limits>
+
+#include <glm/glm.hpp>
+
+#include "StandardController.h"
+
+const float CONTROLLER_THRESHOLD = 0.3f;
+
+StandardController::~StandardController() {
+}
+
+void StandardController::update(float deltaTime, bool jointsCaptured) {
+}
+
+void StandardController::focusOutEvent() {
+    _axisStateMap.clear();
+    _buttonPressedMap.clear();
+};
+
+void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
+    // Grab the current free device ID
+    _deviceID = mapper.getStandardDeviceID();
+    
+    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
+    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
+    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
+    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
+        QVector<UserInputMapper::InputPair> availableInputs;
+        // Buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
+
+        // DPad
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
+
+        // Bumpers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
+
+        // Stick press
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
+
+        // Center buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
+
+        // Analog sticks
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
+
+        // Triggers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
+
+        // Poses
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT), "LeftPose"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT), "RightPose"));
+
+        // Aliases, PlayStation style names
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
+
+
+        return availableInputs;
+    };
+
+    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
+        mapper.removeAllInputChannelsForDevice(_deviceID);
+        this->assignDefaultInputMapping(mapper);
+        return true;
+    };
+
+    mapper.registerStandardDevice(proxy);
+}
+
+void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
+}
+
+UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) {
+    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
+}
+
+UserInputMapper::Input StandardController::makeInput(controller::StandardAxisChannel axis) {
+    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
+}
+
+UserInputMapper::Input StandardController::makeInput(controller::StandardPoseChannel pose) {
+    return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
+}
diff --git a/libraries/input-plugins/src/input-plugins/StandardController.h b/libraries/controllers/src/controllers/StandardController.h
similarity index 96%
rename from libraries/input-plugins/src/input-plugins/StandardController.h
rename to libraries/controllers/src/controllers/StandardController.h
index ad1329d5ed..c393af80f4 100644
--- a/libraries/input-plugins/src/input-plugins/StandardController.h
+++ b/libraries/controllers/src/controllers/StandardController.h
@@ -1,48 +1,48 @@
-//
-//  StandardController.h
-//  input-plugins/src/input-plugins
-//
-//  Created by Brad Hefta-Gaub on 2015-10-11.
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#ifndef hifi_StandardController_h
-#define hifi_StandardController_h
-
-#include <qobject.h>
-#include <qvector.h>
-
-#include "InputDevice.h"
-
-#include "StandardControls.h"
-
-typedef std::shared_ptr<StandardController> StandardControllerPointer;
-
-class StandardController : public QObject, public InputDevice {
-    Q_OBJECT
-    Q_PROPERTY(QString name READ getName)
-
-public:
-
-    const QString& getName() const { return _name; }
-
-    // Device functions
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
-    virtual void update(float deltaTime, bool jointsCaptured) override;
-    virtual void focusOutEvent() override;
-    
-    StandardController() : InputDevice("Standard") {}
-    ~StandardController();
-    
-    UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
-    UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
-    UserInputMapper::Input makeInput(controller::StandardPoseChannel pose);
-
-private:
-};
-
-#endif // hifi_StandardController_h
+//
+//  StandardController.h
+//  input-plugins/src/input-plugins
+//
+//  Created by Brad Hefta-Gaub on 2015-10-11.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_StandardController_h
+#define hifi_StandardController_h
+
+#include <qobject.h>
+#include <qvector.h>
+
+#include "InputDevice.h"
+
+#include "StandardControls.h"
+
+typedef std::shared_ptr<StandardController> StandardControllerPointer;
+
+class StandardController : public QObject, public InputDevice {
+    Q_OBJECT
+    Q_PROPERTY(QString name READ getName)
+
+public:
+
+    const QString& getName() const { return _name; }
+
+    // Device functions
+    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
+    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
+    virtual void focusOutEvent() override;
+    
+    StandardController() : InputDevice("Standard") {}
+    ~StandardController();
+    
+    UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
+    UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
+    UserInputMapper::Input makeInput(controller::StandardPoseChannel pose);
+
+private:
+};
+
+#endif // hifi_StandardController_h
diff --git a/libraries/input-plugins/src/input-plugins/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h
similarity index 95%
rename from libraries/input-plugins/src/input-plugins/StandardControls.h
rename to libraries/controllers/src/controllers/StandardControls.h
index e5943ff780..505b4f85c7 100644
--- a/libraries/input-plugins/src/input-plugins/StandardControls.h
+++ b/libraries/controllers/src/controllers/StandardControls.h
@@ -1,59 +1,59 @@
-//
-//  Created by Bradley Austin Davis 2015/10/09
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-#pragma once
-
-namespace controller {
-
-    // Needs to match order and values of SDL_GameControllerButton
-    enum StandardButtonChannel {
-        // Button quad
-        A = 0,
-        B,
-        X,
-        Y,
-        // Center buttons
-        BACK,
-        GUIDE,
-        START,
-        // Stick press
-        LS,
-        RS,
-        // Bumper press
-        LB,
-        RB,
-        // DPad
-        DU,
-        DD,
-        DL,
-        DR,
-        NUM_STANDARD_BUTTONS
-    };
-
-    // Needs to match order and values of SDL_GameControllerAxis
-    enum StandardAxisChannel {
-        // Left Analog stick
-        LX = 0,
-        LY,
-        // Right Analog stick
-        RX,
-        RY,
-        // Triggers
-        LT,
-        RT,
-        NUM_STANDARD_AXES
-    };
-
-    // No correlation to SDL
-    enum StandardPoseChannel {
-        LEFT = 0,
-        RIGHT,
-        HEAD,
-        NUM_STANDARD_POSES
-    };
-
-}
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#pragma once
+
+namespace controller {
+
+    // Needs to match order and values of SDL_GameControllerButton
+    enum StandardButtonChannel {
+        // Button quad
+        A = 0,
+        B,
+        X,
+        Y,
+        // Center buttons
+        BACK,
+        GUIDE,
+        START,
+        // Stick press
+        LS,
+        RS,
+        // Bumper press
+        LB,
+        RB,
+        // DPad
+        DU,
+        DD,
+        DL,
+        DR,
+        NUM_STANDARD_BUTTONS
+    };
+
+    // Needs to match order and values of SDL_GameControllerAxis
+    enum StandardAxisChannel {
+        // Left Analog stick
+        LX = 0,
+        LY,
+        // Right Analog stick
+        RX,
+        RY,
+        // Triggers
+        LT,
+        RT,
+        NUM_STANDARD_AXES
+    };
+
+    // No correlation to SDL
+    enum StandardPoseChannel {
+        LEFT = 0,
+        RIGHT,
+        HEAD,
+        NUM_STANDARD_POSES
+    };
+
+}
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
old mode 100755
new mode 100644
similarity index 93%
rename from libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
rename to libraries/controllers/src/controllers/UserInputMapper.cpp
index c29acc09af..8fc44ebf5b
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -1,368 +1,368 @@
-//
-//  UserInputMapper.cpp
-//  input-plugins/src/input-plugins
-//
-//  Created by Sam Gateau on 4/27/15.
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include "UserInputMapper.h"
-#include "StandardController.h"
-
-const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX);
-const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
-const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
-const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
-
-// Default contruct allocate the poutput size with the current hardcoded action channels
-UserInputMapper::UserInputMapper() {
-    registerStandardDevice();
-    assignDefaulActionScales();
-    createActionNames();
-}
-
-UserInputMapper::~UserInputMapper() {
-}
-
-
-bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
-    proxy->_name += " (" + QString::number(deviceID) + ")";
-    _registeredDevices[deviceID] = proxy;
-    return true;
-}
-
-UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
-    auto device = _registeredDevices.find(input.getDevice());
-    if (device != _registeredDevices.end()) {
-        return (device->second);
-    } else {
-        return DeviceProxy::Pointer();
-    }
-}
-
-QString UserInputMapper::getDeviceName(uint16 deviceID) { 
-    if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
-        return _registeredDevices[deviceID]->_name;
-    }
-    return QString("unknown");
-}
-
-
-void UserInputMapper::resetAllDeviceBindings() {
-    for (auto device : _registeredDevices) {
-        device.second->resetDeviceBindings();
-    }
-}
-
-void UserInputMapper::resetDevice(uint16 deviceID) {
-    auto device = _registeredDevices.find(deviceID);
-    if (device != _registeredDevices.end()) {
-        device->second->resetDeviceBindings();
-    }
-}
-
-int UserInputMapper::findDevice(QString name) {
-    for (auto device : _registeredDevices) {
-        if (device.second->_name.split(" (")[0] == name) {
-            return device.first;
-        }
-    }
-    return 0;
-}
-
-QVector<QString> UserInputMapper::getDeviceNames() {
-    QVector<QString> result;
-    for (auto device : _registeredDevices) {
-        QString deviceName = device.second->_name.split(" (")[0];
-        result << deviceName;
-    }
-    return result;
-}
-
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
-    return addInputChannel(action, input, Input(), scale);
-}
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
-    // Check that the device is registered
-    if (!getDeviceProxy(input)) {
-        qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
-        return false;
-    }
-    
-    auto inputChannel = InputChannel(input, modifier, action, scale);
-
-    // Insert or replace the input to modifiers
-    if (inputChannel.hasModifier()) {
-        auto& modifiers = _inputToModifiersMap[input.getID()];
-        modifiers.push_back(inputChannel._modifier);
-        std::sort(modifiers.begin(), modifiers.end());
-    }
-
-    // Now update the action To Inputs side of things
-    _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
-
-    return true;
-}
-
-int UserInputMapper::addInputChannels(const InputChannels& channels) {
-    int nbAdded = 0;
-    for (auto& channel : channels) {
-        nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
-    }
-    return nbAdded;
-}
-
-bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
-    // Remove from Input to Modifiers map
-    if (inputChannel.hasModifier()) {
-        _inputToModifiersMap.erase(inputChannel._input.getID());
-    }
-    
-    // Remove from Action to Inputs map
-    std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
-    ret = _actionToInputsMap.equal_range(inputChannel._action);
-    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
-        if (it->second == inputChannel) {
-            _actionToInputsMap.erase(it);
-            return true;
-        }
-    }
-    
-    return false;
-}
-
-void UserInputMapper::removeAllInputChannels() {
-    _inputToModifiersMap.clear();
-    _actionToInputsMap.clear();
-}
-
-void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
-    QVector<InputChannel> channels = getAllInputsForDevice(device);
-    for (auto& channel : channels) {
-        removeInputChannel(channel);
-    }
-}
-
-void UserInputMapper::removeDevice(int device) {
-    removeAllInputChannelsForDevice((uint16) device);
-    _registeredDevices.erase(device);
-}
-
-int UserInputMapper::getInputChannels(InputChannels& channels) const {
-    for (auto& channel : _actionToInputsMap) {
-        channels.push_back(channel.second);
-    }
-
-    return _actionToInputsMap.size();
-}
-
-QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
-    InputChannels allChannels;
-    getInputChannels(allChannels);
-    
-    QVector<InputChannel> channels;
-    for (InputChannel inputChannel : allChannels) {
-        if (inputChannel._input._device == device) {
-            channels.push_back(inputChannel);
-        }
-    }
-    
-    return channels;
-}
-
-void UserInputMapper::update(float deltaTime) {
-
-    // Reset the axis state for next loop
-    for (auto& channel : _actionStates) {
-        channel = 0.0f;
-    }
-    
-    for (auto& channel : _poseStates) {
-        channel = PoseValue();
-    }
-
-    int currentTimestamp = 0;
-
-    for (auto& channelInput : _actionToInputsMap) {
-        auto& inputMapping = channelInput.second;
-        auto& inputID = inputMapping._input;
-        bool enabled = true;
-        
-        // Check if this input channel has modifiers and collect the possibilities
-        auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
-        if (modifiersIt != _inputToModifiersMap.end()) {
-            Modifiers validModifiers;
-            bool isActiveModifier = false;
-            for (auto& modifier : modifiersIt->second) {
-                auto deviceProxy = getDeviceProxy(modifier);
-                if (deviceProxy->getButton(modifier, currentTimestamp)) {
-                    validModifiers.push_back(modifier);
-                    isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
-                }
-            }
-            enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
-        }
-
-        // if enabled: default input or all modifiers on
-        if (enabled) {
-            auto deviceProxy = getDeviceProxy(inputID);
-            switch (inputMapping._input.getType()) {
-                case ChannelType::BUTTON: {
-                    _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
-                    break;
-                }
-                case ChannelType::AXIS: {
-                    _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
-                    break;
-                }
-                case ChannelType::POSE: {
-                    if (!_poseStates[channelInput.first].isValid()) {
-                        _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
-                    }
-                    break;
-                }
-                default: {
-                    break; //silence please
-                }
-            }
-        } else{
-            // Channel input not enabled
-            enabled = false;
-        }
-    }
-
-    // Scale all the channel step with the scale
-    static const float EPSILON =  0.01f;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        _actionStates[i] *= _actionScales[i];
-        // Emit only on change, and emit when moving back to 0
-        if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
-            _lastActionStates[i] = _actionStates[i];
-            emit actionEvent(i, _actionStates[i]);
-        }
-        // TODO: emit signal for pose changes
-    }
-}
-
-QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
-    QVector<Action> actions;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        actions.append(Action(i));
-    }
-    return actions;
-}
-
-QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
-    QVector<InputChannel> inputChannels;
-    std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
-    ret = _actionToInputsMap.equal_range(action);
-    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
-        inputChannels.append(it->second);
-    }
-    return inputChannels;
-}
-
-int UserInputMapper::findAction(const QString& actionName) const {
-    auto actions = getAllActions();
-    for (auto action : actions) {
-        if (getActionName(action) == actionName) {
-            return action;
-        }
-    }
-    // If the action isn't found, return -1
-    return -1;
-}
-
-QVector<QString> UserInputMapper::getActionNames() const {
-    QVector<QString> result;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        result << _actionNames[i];
-    }
-    return result;
-}
-
-void UserInputMapper::assignDefaulActionScales() {
-    _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit
-    _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit
-    _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit
-    _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit
-    _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit
-    _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit
-    _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit
-    _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit
-    _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit
-    _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
-    _actionScales[BOOM_IN] = 0.5f; // .5m per unit
-    _actionScales[BOOM_OUT] = 0.5f; // .5m per unit
-    _actionScales[LEFT_HAND] = 1.0f; // default
-    _actionScales[RIGHT_HAND] = 1.0f; // default
-    _actionScales[LEFT_HAND_CLICK] = 1.0f; // on
-    _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
-    _actionStates[SHIFT] = 1.0f; // on
-    _actionStates[ACTION1] = 1.0f; // default
-    _actionStates[ACTION2] = 1.0f; // default
-    _actionStates[TranslateX] = 1.0f; // default
-    _actionStates[TranslateY] = 1.0f; // default
-    _actionStates[TranslateZ] = 1.0f; // default
-    _actionStates[Roll] = 1.0f; // default
-    _actionStates[Pitch] = 1.0f; // default
-    _actionStates[Yaw] = 1.0f; // default
-}
-
-// This is only necessary as long as the actions are hardcoded
-// Eventually you can just add the string when you add the action
-void UserInputMapper::createActionNames() {
-    _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
-    _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
-    _actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
-    _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
-    _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
-    _actionNames[VERTICAL_UP] = "VERTICAL_UP";
-    _actionNames[YAW_LEFT] = "YAW_LEFT";
-    _actionNames[YAW_RIGHT] = "YAW_RIGHT";
-    _actionNames[PITCH_DOWN] = "PITCH_DOWN";
-    _actionNames[PITCH_UP] = "PITCH_UP";
-    _actionNames[BOOM_IN] = "BOOM_IN";
-    _actionNames[BOOM_OUT] = "BOOM_OUT";
-    _actionNames[LEFT_HAND] = "LEFT_HAND";
-    _actionNames[RIGHT_HAND] = "RIGHT_HAND";
-    _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
-    _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
-    _actionNames[SHIFT] = "SHIFT";
-    _actionNames[ACTION1] = "ACTION1";
-    _actionNames[ACTION2] = "ACTION2";
-    _actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
-    _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
-    _actionNames[TranslateX] = "TranslateX";
-    _actionNames[TranslateY] = "TranslateY";
-    _actionNames[TranslateZ] = "TranslateZ";
-    _actionNames[Roll] = "Roll";
-    _actionNames[Pitch] = "Pitch";
-    _actionNames[Yaw] = "Yaw";
-}
-
-void UserInputMapper::registerStandardDevice() {
-    _standardController = std::make_shared<StandardController>();
-    _standardController->registerToUserInputMapper(*this);
-}
-
-float UserInputMapper::DeviceProxy::getValue(const Input& input, int timestamp) const {
-    switch (input.getType()) {
-        case UserInputMapper::ChannelType::BUTTON:
-            return getButton(input, timestamp) ? 1.0f : 0.0f;
-
-        case UserInputMapper::ChannelType::AXIS:
-            return getAxis(input, timestamp);
-
-        case UserInputMapper::ChannelType::POSE:
-            return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
-
-        default:
-            return 0.0f;
-    }
-}
+//
+//  UserInputMapper.cpp
+//  input-plugins/src/input-plugins
+//
+//  Created by Sam Gateau on 4/27/15.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "UserInputMapper.h"
+#include "StandardController.h"
+
+const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX);
+const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
+const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
+const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
+
+// Default contruct allocate the poutput size with the current hardcoded action channels
+UserInputMapper::UserInputMapper() {
+    registerStandardDevice();
+    assignDefaulActionScales();
+    createActionNames();
+}
+
+UserInputMapper::~UserInputMapper() {
+}
+
+
+bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
+    proxy->_name += " (" + QString::number(deviceID) + ")";
+    _registeredDevices[deviceID] = proxy;
+    return true;
+}
+
+UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
+    auto device = _registeredDevices.find(input.getDevice());
+    if (device != _registeredDevices.end()) {
+        return (device->second);
+    } else {
+        return DeviceProxy::Pointer();
+    }
+}
+
+QString UserInputMapper::getDeviceName(uint16 deviceID) { 
+    if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
+        return _registeredDevices[deviceID]->_name;
+    }
+    return QString("unknown");
+}
+
+
+void UserInputMapper::resetAllDeviceBindings() {
+    for (auto device : _registeredDevices) {
+        device.second->resetDeviceBindings();
+    }
+}
+
+void UserInputMapper::resetDevice(uint16 deviceID) {
+    auto device = _registeredDevices.find(deviceID);
+    if (device != _registeredDevices.end()) {
+        device->second->resetDeviceBindings();
+    }
+}
+
+int UserInputMapper::findDevice(QString name) {
+    for (auto device : _registeredDevices) {
+        if (device.second->_name.split(" (")[0] == name) {
+            return device.first;
+        }
+    }
+    return 0;
+}
+
+QVector<QString> UserInputMapper::getDeviceNames() {
+    QVector<QString> result;
+    for (auto device : _registeredDevices) {
+        QString deviceName = device.second->_name.split(" (")[0];
+        result << deviceName;
+    }
+    return result;
+}
+
+
+bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
+    return addInputChannel(action, input, Input(), scale);
+}
+
+bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
+    // Check that the device is registered
+    if (!getDeviceProxy(input)) {
+        qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
+        return false;
+    }
+    
+    auto inputChannel = InputChannel(input, modifier, action, scale);
+
+    // Insert or replace the input to modifiers
+    if (inputChannel.hasModifier()) {
+        auto& modifiers = _inputToModifiersMap[input.getID()];
+        modifiers.push_back(inputChannel._modifier);
+        std::sort(modifiers.begin(), modifiers.end());
+    }
+
+    // Now update the action To Inputs side of things
+    _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
+
+    return true;
+}
+
+int UserInputMapper::addInputChannels(const InputChannels& channels) {
+    int nbAdded = 0;
+    for (auto& channel : channels) {
+        nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
+    }
+    return nbAdded;
+}
+
+bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
+    // Remove from Input to Modifiers map
+    if (inputChannel.hasModifier()) {
+        _inputToModifiersMap.erase(inputChannel._input.getID());
+    }
+    
+    // Remove from Action to Inputs map
+    std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
+    ret = _actionToInputsMap.equal_range(inputChannel._action);
+    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
+        if (it->second == inputChannel) {
+            _actionToInputsMap.erase(it);
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+void UserInputMapper::removeAllInputChannels() {
+    _inputToModifiersMap.clear();
+    _actionToInputsMap.clear();
+}
+
+void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
+    QVector<InputChannel> channels = getAllInputsForDevice(device);
+    for (auto& channel : channels) {
+        removeInputChannel(channel);
+    }
+}
+
+void UserInputMapper::removeDevice(int device) {
+    removeAllInputChannelsForDevice((uint16) device);
+    _registeredDevices.erase(device);
+}
+
+int UserInputMapper::getInputChannels(InputChannels& channels) const {
+    for (auto& channel : _actionToInputsMap) {
+        channels.push_back(channel.second);
+    }
+
+    return _actionToInputsMap.size();
+}
+
+QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
+    InputChannels allChannels;
+    getInputChannels(allChannels);
+    
+    QVector<InputChannel> channels;
+    for (InputChannel inputChannel : allChannels) {
+        if (inputChannel._input._device == device) {
+            channels.push_back(inputChannel);
+        }
+    }
+    
+    return channels;
+}
+
+void UserInputMapper::update(float deltaTime) {
+
+    // Reset the axis state for next loop
+    for (auto& channel : _actionStates) {
+        channel = 0.0f;
+    }
+    
+    for (auto& channel : _poseStates) {
+        channel = PoseValue();
+    }
+
+    int currentTimestamp = 0;
+
+    for (auto& channelInput : _actionToInputsMap) {
+        auto& inputMapping = channelInput.second;
+        auto& inputID = inputMapping._input;
+        bool enabled = true;
+        
+        // Check if this input channel has modifiers and collect the possibilities
+        auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
+        if (modifiersIt != _inputToModifiersMap.end()) {
+            Modifiers validModifiers;
+            bool isActiveModifier = false;
+            for (auto& modifier : modifiersIt->second) {
+                auto deviceProxy = getDeviceProxy(modifier);
+                if (deviceProxy->getButton(modifier, currentTimestamp)) {
+                    validModifiers.push_back(modifier);
+                    isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
+                }
+            }
+            enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
+        }
+
+        // if enabled: default input or all modifiers on
+        if (enabled) {
+            auto deviceProxy = getDeviceProxy(inputID);
+            switch (inputMapping._input.getType()) {
+                case ChannelType::BUTTON: {
+                    _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
+                    break;
+                }
+                case ChannelType::AXIS: {
+                    _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
+                    break;
+                }
+                case ChannelType::POSE: {
+                    if (!_poseStates[channelInput.first].isValid()) {
+                        _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
+                    }
+                    break;
+                }
+                default: {
+                    break; //silence please
+                }
+            }
+        } else{
+            // Channel input not enabled
+            enabled = false;
+        }
+    }
+
+    // Scale all the channel step with the scale
+    static const float EPSILON =  0.01f;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        _actionStates[i] *= _actionScales[i];
+        // Emit only on change, and emit when moving back to 0
+        if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
+            _lastActionStates[i] = _actionStates[i];
+            emit actionEvent(i, _actionStates[i]);
+        }
+        // TODO: emit signal for pose changes
+    }
+}
+
+QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
+    QVector<Action> actions;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        actions.append(Action(i));
+    }
+    return actions;
+}
+
+QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
+    QVector<InputChannel> inputChannels;
+    std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
+    ret = _actionToInputsMap.equal_range(action);
+    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
+        inputChannels.append(it->second);
+    }
+    return inputChannels;
+}
+
+int UserInputMapper::findAction(const QString& actionName) const {
+    auto actions = getAllActions();
+    for (auto action : actions) {
+        if (getActionName(action) == actionName) {
+            return action;
+        }
+    }
+    // If the action isn't found, return -1
+    return -1;
+}
+
+QVector<QString> UserInputMapper::getActionNames() const {
+    QVector<QString> result;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        result << _actionNames[i];
+    }
+    return result;
+}
+
+void UserInputMapper::assignDefaulActionScales() {
+    _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit
+    _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit
+    _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit
+    _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit
+    _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit
+    _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit
+    _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit
+    _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit
+    _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit
+    _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
+    _actionScales[BOOM_IN] = 0.5f; // .5m per unit
+    _actionScales[BOOM_OUT] = 0.5f; // .5m per unit
+    _actionScales[LEFT_HAND] = 1.0f; // default
+    _actionScales[RIGHT_HAND] = 1.0f; // default
+    _actionScales[LEFT_HAND_CLICK] = 1.0f; // on
+    _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
+    _actionStates[SHIFT] = 1.0f; // on
+    _actionStates[ACTION1] = 1.0f; // default
+    _actionStates[ACTION2] = 1.0f; // default
+    _actionStates[TRANSLATE_X] = 1.0f; // default
+    _actionStates[TRANSLATE_Y] = 1.0f; // default
+    _actionStates[TRANSLATE_Z] = 1.0f; // default
+    _actionStates[ROLL] = 1.0f; // default
+    _actionStates[PITCH] = 1.0f; // default
+    _actionStates[YAW] = 1.0f; // default
+}
+
+// This is only necessary as long as the actions are hardcoded
+// Eventually you can just add the string when you add the action
+void UserInputMapper::createActionNames() {
+    _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
+    _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
+    _actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
+    _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
+    _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
+    _actionNames[VERTICAL_UP] = "VERTICAL_UP";
+    _actionNames[YAW_LEFT] = "YAW_LEFT";
+    _actionNames[YAW_RIGHT] = "YAW_RIGHT";
+    _actionNames[PITCH_DOWN] = "PITCH_DOWN";
+    _actionNames[PITCH_UP] = "PITCH_UP";
+    _actionNames[BOOM_IN] = "BOOM_IN";
+    _actionNames[BOOM_OUT] = "BOOM_OUT";
+    _actionNames[LEFT_HAND] = "LEFT_HAND";
+    _actionNames[RIGHT_HAND] = "RIGHT_HAND";
+    _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
+    _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
+    _actionNames[SHIFT] = "SHIFT";
+    _actionNames[ACTION1] = "ACTION1";
+    _actionNames[ACTION2] = "ACTION2";
+    _actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
+    _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
+    _actionNames[TRANSLATE_X] = "TranslateX";
+    _actionNames[TRANSLATE_Y] = "TranslateY";
+    _actionNames[TRANSLATE_Z] = "TranslateZ";
+    _actionNames[ROLL] = "Roll";
+    _actionNames[PITCH] = "Pitch";
+    _actionNames[YAW] = "Yaw";
+}
+
+void UserInputMapper::registerStandardDevice() {
+    _standardController = std::make_shared<StandardController>();
+    _standardController->registerToUserInputMapper(*this);
+}
+
+float UserInputMapper::DeviceProxy::getValue(const Input& input, int timestamp) const {
+    switch (input.getType()) {
+        case UserInputMapper::ChannelType::BUTTON:
+            return getButton(input, timestamp) ? 1.0f : 0.0f;
+
+        case UserInputMapper::ChannelType::AXIS:
+            return getAxis(input, timestamp);
+
+        case UserInputMapper::ChannelType::POSE:
+            return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
+
+        default:
+            return 0.0f;
+    }
+}
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
old mode 100755
new mode 100644
similarity index 96%
rename from libraries/input-plugins/src/input-plugins/UserInputMapper.h
rename to libraries/controllers/src/controllers/UserInputMapper.h
index 304e74e8cc..2a42dfa1aa
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -146,44 +146,52 @@ public:
     // Actions are the output channels of the Mapper, that's what the InputChannel map to
     // For now the Actions are hardcoded, this is bad, but we will fix that in the near future
     enum Action {
-        LONGITUDINAL_BACKWARD = 0,
-        LONGITUDINAL_FORWARD,
+        TRANSLATE_X = 0,
+        TRANSLATE_Y,
+        TRANSLATE_Z,
+        ROTATE_X, PITCH = ROTATE_X,
+        ROTATE_Y, YAW = ROTATE_Y,
+        ROTATE_Z, ROLL = ROTATE_Z,
 
-        LATERAL_LEFT,
-        LATERAL_RIGHT,
+        TRANSLATE_CAMERA_Z,
 
-        VERTICAL_DOWN,
-        VERTICAL_UP,
-
-        YAW_LEFT,
-        YAW_RIGHT,
- 
-        PITCH_DOWN,
-        PITCH_UP,
- 
-        BOOM_IN,
-        BOOM_OUT,
-        
         LEFT_HAND,
         RIGHT_HAND,
 
         LEFT_HAND_CLICK,
         RIGHT_HAND_CLICK,
 
-        SHIFT,
-        
         ACTION1,
         ACTION2,
 
         CONTEXT_MENU,
         TOGGLE_MUTE,
 
-        TranslateX,
-        TranslateY,
-        TranslateZ,
-        Roll,
-        Pitch,
-        Yaw,
+        SHIFT,
+
+        // Biseced aliases for TRANSLATE_Z
+        LONGITUDINAL_BACKWARD,
+        LONGITUDINAL_FORWARD,
+
+        // Biseced aliases for TRANSLATE_X
+        LATERAL_LEFT,
+        LATERAL_RIGHT,
+
+        // Biseced aliases for TRANSLATE_Y
+        VERTICAL_DOWN,
+        VERTICAL_UP,
+
+        // Biseced aliases for ROTATE_Y
+        YAW_LEFT,
+        YAW_RIGHT,
+ 
+        // Biseced aliases for ROTATE_X
+        PITCH_DOWN,
+        PITCH_UP,
+
+        // Biseced aliases for TRANSLATE_CAMERA_Z
+        BOOM_IN,
+        BOOM_OUT,
 
         NUM_ACTIONS,
     };
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index a826b4fd4d..1e889f2dda 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -12,7 +12,7 @@
 #include <QtCore/QDebug>
 
 #include "RouteBuilderProxy.h"
-#include "../NewControllerScriptingInterface.h"
+#include "../ScriptingInterface.h"
 #include "../Logging.h"
 
 namespace controller {
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index 70495a9cfe..024faa7a4a 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -20,12 +20,14 @@ class QScriptValue;
 
 namespace controller {
 
-class NewControllerScriptingInterface;
+class ScriptingInterface;
 
+// TODO migrate functionality to a MappingBuilder class and make the proxy defer to that 
+// (for easier use in both C++ and JS)
 class MappingBuilderProxy : public QObject {
     Q_OBJECT
 public:
-    MappingBuilderProxy(NewControllerScriptingInterface& parent, Mapping::Pointer mapping)
+    MappingBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping)
         : _parent(parent), _mapping(mapping) { }
 
     Q_INVOKABLE QObject* from(const QJSValue& source);
@@ -38,7 +40,7 @@ protected:
     QObject* from(const Endpoint::Pointer& source);
 
     friend class RouteBuilderProxy;
-    NewControllerScriptingInterface& _parent;
+    ScriptingInterface& _parent;
     Mapping::Pointer _mapping;
 };
 
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index e6b67e9ca6..50c3b534d1 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -12,7 +12,7 @@
 #include <GLMHelpers.h>
 
 #include "MappingBuilderProxy.h"
-#include "../NewControllerScriptingInterface.h"
+#include "../ScriptingInterface.h"
 #include "../Logging.h"
 
 namespace controller {
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 63cd106edb..d7cf024468 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -19,12 +19,14 @@ class QScriptValue;
 
 namespace controller {
 
-class NewControllerScriptingInterface;
+class ScriptingInterface;
 
+// TODO migrate functionality to a RouteBuilder class and make the proxy defer to that 
+// (for easier use in both C++ and JS)
 class RouteBuilderProxy : public QObject {
         Q_OBJECT
     public:
-        RouteBuilderProxy(NewControllerScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route)
+        RouteBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route)
             : _parent(parent), _mapping(mapping), _route(route) { }
 
         Q_INVOKABLE void to(const QJSValue& destination);
@@ -47,7 +49,7 @@ class RouteBuilderProxy : public QObject {
         Mapping::Pointer _mapping;
         Route::Pointer _route;
 
-        NewControllerScriptingInterface& _parent;
+        ScriptingInterface& _parent;
     };
 
 }
diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt
index bb90c04c95..4f2a525f07 100644
--- a/libraries/entities-renderer/CMakeLists.txt
+++ b/libraries/entities-renderer/CMakeLists.txt
@@ -1,7 +1,7 @@
 set(TARGET_NAME entities-renderer)
 AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
 setup_hifi_library(Widgets Network Script)
-link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)
+link_hifi_libraries(shared gpu procedural model model-networking script-engine controllers render render-utils)
 
 target_bullet()
 
diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt
index 094a697012..4c33b2517a 100644
--- a/libraries/input-plugins/CMakeLists.txt
+++ b/libraries/input-plugins/CMakeLists.txt
@@ -1,6 +1,6 @@
 set(TARGET_NAME input-plugins)
 setup_hifi_library()
-link_hifi_libraries(shared plugins gpu render-utils)
+link_hifi_libraries(shared plugins controllers)
 
 GroupSources("src/input-plugins")
 
diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
index 2b16d905f5..b52dd3f658 100644
--- a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
+++ b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
@@ -22,7 +22,7 @@ InputPluginList getInputPlugins() {
     InputPlugin* PLUGIN_POOL[] = {
         new KeyboardMouseDevice(),
         new SDL2Manager(),
-        new SixenseManager(),
+        //new SixenseManager(),
         //new ViveControllerManager(),
         nullptr
     };
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index 684b9e80d5..e7a0124deb 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -9,13 +9,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include <limits>
-
-#include <glm/glm.hpp>
-
 #include "Joystick.h"
 
-#include "StandardControls.h"
+#include <limits>
+#include <glm/glm.hpp>
 
 const float CONTROLLER_THRESHOLD = 0.3f;
 
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h
index 2a7a11d230..c6537acafe 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.h
+++ b/libraries/input-plugins/src/input-plugins/Joystick.h
@@ -20,8 +20,8 @@
 #undef main
 #endif
 
-#include "InputDevice.h"
-#include "StandardControls.h"
+#include <controllers/InputDevice.h>
+#include <controllers/StandardControls.h>
 
 class Joystick : public QObject, public InputDevice {
     Q_OBJECT
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
index e8a6131387..3c935cab26 100644
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
@@ -16,7 +16,7 @@
 
 #include <QtCore/QPoint>
 
-#include "InputDevice.h"
+#include <controllers/InputDevice.h>
 #include "InputPlugin.h"
 
 class QTouchEvent;
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.h b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
index 23e3ee059f..fec6972591 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.h
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
@@ -16,9 +16,9 @@
 #include <SDL.h>
 #endif
 
-#include "InputPlugin.h"
-#include "UserInputMapper.h"
+#include <controllers/UserInputMapper.h>
 
+#include "InputPlugin.h"
 #include "Joystick.h"
 
 class SDL2Manager : public InputPlugin {
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index 9fa7f84a86..53ee7f3c29 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -24,8 +24,9 @@
 
 #endif
 
+#include <controllers/InputDevice.h>
+
 #include "InputPlugin.h"
-#include "InputDevice.h"
 
 class QLibrary;
 
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
index 5cae8daaf4..bcc27d07ae 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
@@ -19,7 +19,7 @@
 
 #include <model/Geometry.h>
 #include <gpu/Texture.h>
-#include "InputDevice.h"
+#include <controllers/InputDevice.h>
 #include "InputPlugin.h"
 #include <RenderArgs.h>
 #include <render/Scene.h>
diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt
index cfe0afd220..5e3d135034 100644
--- a/libraries/script-engine/CMakeLists.txt
+++ b/libraries/script-engine/CMakeLists.txt
@@ -1,3 +1,3 @@
 set(TARGET_NAME script-engine)
 setup_hifi_library(Gui Network Script WebSockets Widgets)
-link_hifi_libraries(shared networking octree gpu procedural model model-networking fbx entities animation audio physics)
+link_hifi_libraries(shared networking octree gpu procedural model model-networking fbx entities controllers animation audio physics)
diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h
deleted file mode 100644
index d6a6b51b62..0000000000
--- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h
+++ /dev/null
@@ -1,125 +0,0 @@
-//
-//  AbstractControllerScriptingInterface.h
-//  libraries/script-engine/src
-//
-//  Created by Brad Hefta-Gaub on 12/17/13.
-//  Copyright 2013 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#ifndef hifi_AbstractControllerScriptingInterface_h
-#define hifi_AbstractControllerScriptingInterface_h
-
-#include <QtCore/QObject>
-
-#include <glm/glm.hpp>
-#include <glm/gtc/quaternion.hpp>
-
-#include "HFActionEvent.h"
-#include "KeyEvent.h"
-#include "MouseEvent.h"
-#include "SpatialEvent.h"
-#include "TouchEvent.h"
-#include "WheelEvent.h"
-
-class ScriptEngine;
-
-class AbstractInputController : public QObject {
-    Q_OBJECT
-
-public:
-    typedef unsigned int Key;
-
-    virtual void update() = 0;
-
-    virtual Key getKey() const = 0;
-
-public slots:
-
-    virtual bool isActive() const = 0;
-    virtual glm::vec3 getAbsTranslation() const = 0;
-    virtual glm::quat getAbsRotation() const = 0;
-    virtual glm::vec3 getLocTranslation() const = 0;
-    virtual glm::quat getLocRotation() const = 0;
-
-signals:
-    void spatialEvent(const SpatialEvent& event);
-
-};
-
-/// handles scripting of input controller commands from JS
-class AbstractControllerScriptingInterface : public QObject {
-    Q_OBJECT
-
-public slots:
-    virtual void registerControllerTypes(ScriptEngine* engine) = 0;
-    
-    virtual bool isPrimaryButtonPressed() const = 0;
-    virtual glm::vec2 getPrimaryJoystickPosition() const = 0;
-
-    virtual int getNumberOfButtons() const = 0;
-    virtual bool isButtonPressed(int buttonIndex) const = 0;
-
-    virtual int getNumberOfTriggers() const = 0;
-    virtual float getTriggerValue(int triggerIndex) const = 0;
-
-    virtual int getNumberOfJoysticks() const = 0;
-    virtual glm::vec2 getJoystickPosition(int joystickIndex) const = 0;
-
-    virtual int getNumberOfSpatialControls() const = 0;
-    virtual glm::vec3 getSpatialControlPosition(int controlIndex) const = 0;
-    virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const = 0;
-    virtual glm::vec3 getSpatialControlNormal(int controlIndex) const = 0;
-    virtual glm::quat getSpatialControlRawRotation(int controlIndex) const = 0;
-
-    virtual void captureKeyEvents(const KeyEvent& event) = 0;
-    virtual void releaseKeyEvents(const KeyEvent& event) = 0;
-
-    virtual void captureMouseEvents() = 0;
-    virtual void releaseMouseEvents() = 0;
-
-    virtual void captureTouchEvents() = 0;
-    virtual void releaseTouchEvents() = 0;
-
-    virtual void captureWheelEvents() = 0;
-    virtual void releaseWheelEvents() = 0;
-    
-    virtual void captureActionEvents() = 0;
-    virtual void releaseActionEvents() = 0;
-
-    virtual void captureJoystick(int joystickIndex) = 0;
-    virtual void releaseJoystick(int joystickIndex) = 0;
-
-    virtual glm::vec2 getViewportDimensions() const = 0;
-
-
-    virtual AbstractInputController* createInputController( const QString& category, const QString& tracker ) = 0;
-
-signals:
-    void keyPressEvent(const KeyEvent& event);
-    void keyReleaseEvent(const KeyEvent& event);
-    
-    void actionStartEvent(const HFActionEvent& event);
-    void actionEndEvent(const HFActionEvent& event);
-    
-    void backStartEvent();
-    void backEndEvent();
-
-    void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0);
-    void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
-    void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
-    void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0);
-
-    void touchBeginEvent(const TouchEvent& event);
-    void touchEndEvent(const TouchEvent& event);
-    void touchUpdateEvent(const TouchEvent& event);
-    
-    void wheelEvent(const WheelEvent& event);
-    
-    void actionEvent(int action, float state);
-
-};
-
-#endif // hifi_AbstractControllerScriptingInterface_h
diff --git a/libraries/script-engine/src/AbstractScriptingServicesInterface.h b/libraries/script-engine/src/AbstractScriptingServicesInterface.h
index 9d24531b60..565a415f63 100644
--- a/libraries/script-engine/src/AbstractScriptingServicesInterface.h
+++ b/libraries/script-engine/src/AbstractScriptingServicesInterface.h
@@ -12,7 +12,10 @@
 #ifndef hifi_AbstractScriptingServicesInterface_h
 #define hifi_AbstractScriptingServicesInterface_h
 
-class AbstractControllerScriptingInterface;
+namespace controller {
+    class ScriptingInterface;
+}
+
 class Transform;
 class ScriptEngine;
 class QThread;
@@ -22,7 +25,7 @@ class AbstractScriptingServicesInterface {
 public:
     
     /// Returns the controller interface for the application
-    virtual AbstractControllerScriptingInterface* getControllerScriptingInterface() = 0;
+    virtual controller::ScriptingInterface* getControllerScriptingInterface() = 0;
 
     /// Registers application specific services with a script engine.
     virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) = 0;
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 76590f266b..40d4d664ce 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -76,16 +76,16 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) {
     out = qobject_cast<AvatarData*>(object.toQObject());
 }
 
-QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) {
+
+QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) {
     return engine->newQObject(in);
 }
 
-void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputController* &out) {
-    out = qobject_cast<AbstractInputController*>(object.toQObject());
+void inputControllerFromScriptValue(const QScriptValue &object, controller::InputController* &out) {
+    out = qobject_cast<controller::InputController*>(object.toQObject());
 }
 
-ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
-            AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) :
+ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, controller::ScriptingInterface* controllerScriptingInterface, bool wantSignals) :
 
     _scriptContents(scriptContents),
     _isFinished(false),
@@ -93,7 +93,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
     _isInitialized(false),
     _timerFunctionMap(),
     _wantSignals(wantSignals),
-    _controllerScriptingInterface(controllerScriptingInterface),
     _fileNameString(fileNameString),
     _quatLibrary(),
     _vec3Library(),
@@ -301,7 +300,7 @@ void ScriptEngine::init() {
     globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue);
 
     qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue);
-    qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue);
+    //qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue);
     qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue);
     qScriptRegisterMetaType(this, animationDetailsToScriptValue, animationDetailsFromScriptValue);
     qScriptRegisterMetaType(this, webSocketToScriptValue, webSocketFromScriptValue);
@@ -310,7 +309,7 @@ void ScriptEngine::init() {
 
     registerGlobalObject("Script", this);
     registerGlobalObject("Audio", &AudioScriptingInterface::getInstance());
-    registerGlobalObject("Controller", _controllerScriptingInterface);
+//    registerGlobalObject("Controller", _controllerScriptingInterface);
     registerGlobalObject("Entities", entityScriptingInterface.data());
     registerGlobalObject("Quat", &_quatLibrary);
     registerGlobalObject("Vec3", &_vec3Library);
@@ -320,9 +319,9 @@ void ScriptEngine::init() {
     // constants
     globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
 
-    if (_controllerScriptingInterface) {
-        _controllerScriptingInterface->registerControllerTypes(this);
-    }
+    //if (_controllerScriptingInterface) {
+    //    _controllerScriptingInterface->registerControllerTypes(this);
+    //}
 
 
 }
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index 1d3986143a..0108899571 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -26,8 +26,10 @@
 #include <LimitedNodeList.h>
 #include <EntityItemID.h>
 #include <EntitiesScriptEngineProvider.h>
+#include <controllers/ScriptingInterface.h>
 
-#include "AbstractControllerScriptingInterface.h"
+
+#include "MouseEvent.h"
 #include "ArrayBufferClass.h"
 #include "AudioScriptingInterface.h"
 #include "Quat.h"
@@ -53,7 +55,7 @@ class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScr
 public:
     ScriptEngine(const QString& scriptContents = NO_SCRIPT,
                  const QString& fileNameString = QString(""),
-                 AbstractControllerScriptingInterface* controllerScriptingInterface = NULL,
+                 controller::ScriptingInterface* controllerScriptingInterface = nullptr,
                  bool wantSignals = true);
 
     ~ScriptEngine();
@@ -182,7 +184,6 @@ private:
     QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot);
     void stopTimer(QTimer* timer);
 
-    AbstractControllerScriptingInterface* _controllerScriptingInterface;
     QString _fileNameString;
     Quat _quatLibrary;
     Vec3 _vec3Library;
diff --git a/tests/controllers/qml/content.qml b/tests/controllers/qml/content.qml
index 41d623a389..5f9bbd455e 100644
--- a/tests/controllers/qml/content.qml
+++ b/tests/controllers/qml/content.qml
@@ -8,17 +8,17 @@ import "./controls"
 
 Column {
     id: root
-    property var actions: NewControllers.Actions
-    property var standard: NewControllers.Standard
+    property var actions: Controllers.Actions
+    property var standard: Controllers.Standard
     property var testMapping: null
     property var xbox: null
 
 
     Component.onCompleted: {
         var patt = /^X360Controller/;
-        for (var prop in NewControllers.Hardware) {
+        for (var prop in Controllers.Hardware) {
             if(patt.test(prop)) {
-                root.xbox = NewControllers.Hardware[prop]
+                root.xbox = Controllers.Hardware[prop]
                 break
             }
         }
@@ -29,7 +29,7 @@ Column {
     Timer {
         interval: 50; running: true; repeat: true
         onTriggered: {
-            NewControllers.update();
+            Controllers.update();
         }
     }
 
@@ -38,7 +38,7 @@ Column {
         Button {
             text: "Default Mapping"
             onClicked: {
-                var mapping = NewControllers.newMapping("Default");
+                var mapping = Controllers.newMapping("Default");
                 mapping.from(xbox.A).to(standard.A);
                 mapping.from(xbox.B).to(standard.B);
                 mapping.from(xbox.X).to(standard.X);
@@ -59,7 +59,7 @@ Column {
                 mapping.from(xbox.RX).to(standard.RX);
                 mapping.from(xbox.LT).to(standard.LT);
                 mapping.from(xbox.RT).to(standard.RT);
-                NewControllers.enableMapping("Default");
+                Controllers.enableMapping("Default");
                 enabled = false;
                 text = "Built"
             }
@@ -68,16 +68,35 @@ Column {
         Button {
             text: "Build Mapping"
             onClicked: {
-                var mapping = NewControllers.newMapping();
+                var mapping = Controllers.newMapping();
                 // Inverting a value
                 mapping.from(xbox.RY).invert().to(standard.RY);
                 // Assigning a value from a function
                 mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
                 // Constrainting a value to -1, 0, or 1, with a deadzone
                 mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
-                mapping.join(standard.LB, standard.RB).pulse(0.5).to(actions.Yaw);
+                // change join to makeAxis
+                mapping.join(standard.LB, standard.RB).to(actions.Yaw);
                 mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
                 mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
+
+                // mapping.modifier(keyboard.Ctrl).scale(2.0)
+
+//                mapping.from(keyboard.A).to(actions.TranslateLeft)
+//                mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
+//                mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
+
+//                // First loopbacks
+//                // Then non-loopbacks by constraint level (number of inputs)
+//                mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
+
+//                mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
+
+
+//                mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
+
+
+//                mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
                 testMapping = mapping;
                 enabled = false
                 text = "Built"
@@ -105,7 +124,7 @@ Column {
     Row {
         spacing: 8
         ScrollingGraph {
-            controlId: NewControllers.Actions.Yaw
+            controlId: Controllers.Actions.Yaw
             label: "Yaw"
             min: -3.0
             max: 3.0
@@ -113,7 +132,7 @@ Column {
         }
 
         ScrollingGraph {
-            controlId: NewControllers.Actions.YAW_LEFT
+            controlId: Controllers.Actions.YAW_LEFT
             label: "Yaw Left"
             min: -3.0
             max: 3.0
@@ -121,7 +140,7 @@ Column {
         }
 
         ScrollingGraph {
-            controlId: NewControllers.Actions.YAW_RIGHT
+            controlId: Controllers.Actions.YAW_RIGHT
             label: "Yaw Right"
             min: -3.0
             max: 3.0
diff --git a/tests/controllers/qml/controls/AnalogButton.qml b/tests/controllers/qml/controls/AnalogButton.qml
index 26f91458ac..141c131063 100644
--- a/tests/controllers/qml/controls/AnalogButton.qml
+++ b/tests/controllers/qml/controls/AnalogButton.qml
@@ -13,7 +13,7 @@ Item {
     property color color: 'black'
 
     function update() {
-        value = NewControllers.getValue(controlId);
+        value = Controllers.getValue(controlId);
         canvas.requestPaint();
     }
 
diff --git a/tests/controllers/qml/controls/AnalogStick.qml b/tests/controllers/qml/controls/AnalogStick.qml
index 8860aea49c..5d011411c9 100644
--- a/tests/controllers/qml/controls/AnalogStick.qml
+++ b/tests/controllers/qml/controls/AnalogStick.qml
@@ -15,8 +15,8 @@ Item {
 
     function update() {
         value = Qt.vector2d(
-            NewControllers.getValue(controlIds[0]),
-            NewControllers.getValue(controlIds[1])
+            Controllers.getValue(controlIds[0]),
+            Controllers.getValue(controlIds[1])
         );
         canvas.requestPaint();
     }
diff --git a/tests/controllers/qml/controls/ScrollingGraph.qml b/tests/controllers/qml/controls/ScrollingGraph.qml
index 69f919aaf1..471d142d27 100644
--- a/tests/controllers/qml/controls/ScrollingGraph.qml
+++ b/tests/controllers/qml/controls/ScrollingGraph.qml
@@ -22,7 +22,7 @@ Item {
     property string label: ""
 
     function update() {
-        value = NewControllers.getValue(controlId);
+        value = Controllers.getValue(controlId);
         canvas.requestPaint();
     }
 
diff --git a/tests/controllers/qml/controls/ToggleButton.qml b/tests/controllers/qml/controls/ToggleButton.qml
index 9ef54f5971..46a7b4bdfd 100644
--- a/tests/controllers/qml/controls/ToggleButton.qml
+++ b/tests/controllers/qml/controls/ToggleButton.qml
@@ -15,7 +15,7 @@ Item {
     Timer {
         interval: 50; running: true; repeat: true
         onTriggered: {
-            root.value = NewControllers.getValue(root.controlId);
+            root.value = Controllers.getValue(root.controlId);
             canvas.requestPaint();
         }
     }
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index 7182862ff1..3a45195439 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -38,10 +38,10 @@
 #include <plugins/PluginManager.h>
 #include <input-plugins/InputPlugin.h>
 #include <input-plugins/KeyboardMouseDevice.h>
-#include <controllers/NewControllerScriptingInterface.h>
+#include <controllers/ScriptingInterface.h>
 
 #include <DependencyManager.h>
-#include <input-plugins/UserInputMapper.h>
+#include <controllers/UserInputMapper.h>
 
 const QString& getQmlDir() {
     static QString dir;
@@ -87,6 +87,22 @@ int main(int argc, char** argv) {
     }
 
 
+    QTimer timer;
+    QObject::connect(&timer, &QTimer::timeout, [] {
+        static float last = secTimestampNow();
+        float now = secTimestampNow();
+        float delta = now - last;
+        last = now;
+
+        foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
+            inputPlugin->pluginUpdate(delta, false);
+        }
+
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        userInputMapper->update(delta);
+    });
+    timer.start(50);
+
     {
         DependencyManager::set<UserInputMapper>();
         foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
@@ -98,17 +114,9 @@ int main(int argc, char** argv) {
                 keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
             }
         }
-
-
         //new PluginContainerProxy();
         auto rootContext = engine.rootContext();
-
-        auto controllers = new NewControllerScriptingInterface();
-        rootContext->setContextProperty("NewControllers", controllers);
-        QVariantMap map;
-        map.insert("Hardware", controllers->property("Hardware"));
-        map.insert("Actions", controllers->property("Actions"));
-        rootContext->setContextProperty("ControllerIds", map);
+        rootContext->setContextProperty("Controllers", new ScriptingInterface());
     }
     engine.load(getQmlDir() + "main.qml");
     app.exec();

From 4107f4ea9f877d971c1e6a94dbfebc22cf737bb9 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 14 Oct 2015 15:32:10 -0700
Subject: [PATCH 028/301] guard sixense from updating before activated

---
 libraries/input-plugins/src/input-plugins/SixenseManager.cpp | 5 +++++
 libraries/input-plugins/src/input-plugins/SixenseManager.h   | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index e7a4feedd8..a20fe5fc4c 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -122,6 +122,7 @@ void SixenseManager::activate() {
 #endif
     loadSettings();
     sixenseInit();
+    _activated = true;
 #endif
 }
 
@@ -138,6 +139,7 @@ void SixenseManager::deactivate() {
 #endif
 
     sixenseExit();
+    _activated = false;
 
 #ifdef __APPLE__
     delete _sixenseLibrary;
@@ -157,6 +159,9 @@ void SixenseManager::setSixenseFilter(bool filter) {
 }
 
 void SixenseManager::update(float deltaTime, bool jointsCaptured) {
+    if (!_activated) {
+        return;
+    }
 #ifdef HAVE_SIXENSE
     _buttonPressedMap.clear();
 
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index 9fa7f84a86..ae843cf2c8 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -117,6 +117,9 @@ private:
 
     static const QString NAME;
     static const QString HYDRA_ID_STRING;
+
+    bool _activated = false;
+
 };
 
 #endif // hifi_SixenseManager_h

From e39219c2b5a7e2d52b4de105d736c90015998255 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 14 Oct 2015 16:51:52 -0700
Subject: [PATCH 029/301] Fixes and PR comments

---
 .../scripts/controllerScriptingExamples.js    | 38 +++++++++++++------
 examples/mouseLook.js                         |  2 +-
 .../ControllerScriptingInterface.cpp          | 19 +++++++++-
 .../scripting/ControllerScriptingInterface.h  |  2 +-
 .../src/controllers/ScriptingInterface.cpp    | 10 +++--
 .../src/controllers/ScriptingInterface.h      |  2 +-
 .../src/controllers/StandardControls.h        |  5 +++
 .../src/input-plugins/InputPlugin.cpp         |  4 +-
 libraries/script-engine/src/ScriptEngine.cpp  | 15 ++++----
 libraries/script-engine/src/ScriptEngine.h    |  1 +
 10 files changed, 69 insertions(+), 29 deletions(-)

diff --git a/examples/example/scripts/controllerScriptingExamples.js b/examples/example/scripts/controllerScriptingExamples.js
index e678ff26eb..b3dc92029d 100644
--- a/examples/example/scripts/controllerScriptingExamples.js
+++ b/examples/example/scripts/controllerScriptingExamples.js
@@ -11,6 +11,16 @@
 
 // Assumes you only have the default keyboard connected
 
+function findAction(name) {
+    var actions = Controller.getAllActions();
+    for (var i = 0; i < actions.length; i++) {
+        if (actions[i].actionName == name) {
+            return i;
+        }
+    }
+    // If the action isn't found, it will default to the first available action
+    return 0;
+}
 
 
 var hydra = Controller.Hardware.Hydra2;
@@ -46,44 +56,48 @@ Controller.resetAllDeviceBindings();
 // Query all actions
 print("All Actions: \n" + Controller.getAllActions());
 
+var actionId = findAction("YAW_LEFT")
+
+print("Yaw Left action ID: " + actionId)
+
 // Each action stores:
 // action: int representation of enum
-print("Action 5 int: \n" + Controller.getAllActions()[5].action);
+print("Action int: \n" + Controller.getAllActions()[actionId].action);
 
 // actionName: string representation of enum
-print("Action 5 name: \n" + Controller.getAllActions()[5].actionName);
+print("Action name: \n" + Controller.getAllActions()[actionId].actionName);
 
 // inputChannels: list of all inputchannels that control that action
-print("Action 5 input channels: \n" + Controller.getAllActions()[5].inputChannels + "\n");
+print("Action input channels: \n" + Controller.getAllActions()[actionId].inputChannels + "\n");
 
 
 // Each input channel stores:
 // action: Action that this InputChannel maps to
-print("Input channel action: \n" + Controller.getAllActions()[5].inputChannels[0].action);
+print("Input channel action: \n" + Controller.getAllActions()[actionId].inputChannels[0].action);
 
 // scale: sensitivity of input
-print("Input channel scale: \n" + Controller.getAllActions()[5].inputChannels[0].scale);
+print("Input channel scale: \n" + Controller.getAllActions()[actionId].inputChannels[0].scale);
 
 // input and modifier: Inputs
-print("Input channel input and modifier: \n" + Controller.getAllActions()[5].inputChannels[0].input + "\n" + Controller.getAllActions()[5].inputChannels[0].modifier + "\n");
+print("Input channel input and modifier: \n" + Controller.getAllActions()[actionId].inputChannels[0].input + "\n" + Controller.getAllActions()[actionId].inputChannels[0].modifier + "\n");
 
 
 // Each Input stores:
 // device: device of input
-print("Input device: \n" + Controller.getAllActions()[5].inputChannels[0].input.device);
+print("Input device: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.device);
 
 // channel: channel of input
-print("Input channel: \n" + Controller.getAllActions()[5].inputChannels[0].input.channel);
+print("Input channel: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.channel);
 
 // type: type of input (Unknown, Button, Axis, Joint)
-print("Input type: \n" + Controller.getAllActions()[5].inputChannels[0].input.type);
+print("Input type: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.type);
 
 // id: id of input
-print("Input id: \n" + Controller.getAllActions()[5].inputChannels[0].input.id + "\n");
+print("Input id: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.id + "\n");
 
 
 // You can get the name of a device from its id
-print("Device 1 name: \n" + Controller.getDeviceName(Controller.getAllActions()[5].inputChannels[0].input.id));
+print("Device 1 name: \n" + Controller.getDeviceName(Controller.getAllActions()[actionId].inputChannels[0].input.id));
 
 // You can also get all of a devices input channels
 print("Device 1's input channels: \n" + Controller.getAllInputsForDevice(1) + "\n");
@@ -119,7 +133,7 @@ for (i = 0; i < availableInputs.length; i++) {
 
 // You can modify key bindings by using these avaiable inputs
 // This will replace e (up) with 6
-var e = Controller.getAllActions()[5].inputChannels[0];
+var e = Controller.getAllActions()[actionId].inputChannels[0];
 Controller.removeInputChannel(e);
 e.input = availableInputs[6].input;
 Controller.addInputChannel(e);
\ No newline at end of file
diff --git a/examples/mouseLook.js b/examples/mouseLook.js
index 880ec138c4..81bc9d2813 100644
--- a/examples/mouseLook.js
+++ b/examples/mouseLook.js
@@ -38,7 +38,7 @@ var mouseLook = (function () {
         keyboardID = 0;
 
     function onKeyPressEvent(event) {
-        if (event.text == 'M') {
+        if (event.text == 'm') {
             active = !active;
             updateMapping();
         }
diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp
index 1a212fbea9..f1f7b08587 100644
--- a/interface/src/scripting/ControllerScriptingInterface.cpp
+++ b/interface/src/scripting/ControllerScriptingInterface.cpp
@@ -15,6 +15,7 @@
 #include <avatar/MyAvatar.h>
 #include <HandData.h>
 #include <HFBackEvent.h>
+#include <plugins/PluginManager.h>
 
 #include "Application.h"
 #include "devices/MotionTracker.h"
@@ -115,7 +116,7 @@ void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::Input
     inputPair.second = QString(object.property("inputName").toVariant().toString());
 }
 
-void ControllerScriptingInterface::registerControllerTypes(ScriptEngine* engine) {
+void ControllerScriptingInterface::registerControllerTypes(QScriptEngine* engine) {
     qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
     qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputChannel> >(engine);
     qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
@@ -426,11 +427,25 @@ void ControllerScriptingInterface::releaseInputController(controller::InputContr
 }
 
 void ControllerScriptingInterface::update() {
-    controller::ScriptingInterface::update();
+    static float last = secTimestampNow();
+    float now = secTimestampNow();
+    float delta = now - last;
+    last = now;
+
+    for(auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
+        if (inputPlugin->isActive()) {
+            inputPlugin->pluginUpdate(delta, false);
+        }
+    }
+
+    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    userInputMapper->update(delta);
 
     for (auto entry : _inputControllers) {
         entry.second->update();
     }
+
+    controller::ScriptingInterface::update();
 }
 
 QVector<UserInputMapper::Action> ControllerScriptingInterface::getAllActions() {
diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h
index 652bd640b1..25d9a523d3 100644
--- a/interface/src/scripting/ControllerScriptingInterface.h
+++ b/interface/src/scripting/ControllerScriptingInterface.h
@@ -88,7 +88,7 @@ public:
     Q_INVOKABLE QVector<QString> getActionNames() const;
 
 
-    virtual void registerControllerTypes(ScriptEngine* engine);
+    virtual void registerControllerTypes(QScriptEngine* engine);
     
     void emitKeyPressEvent(QKeyEvent* event);
     void emitKeyReleaseEvent(QKeyEvent* event);
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 9d2cdfd2de..a843775dcc 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -357,7 +357,7 @@ namespace controller {
     }
 
     int ScriptingInterface::getNumberOfTriggers() const {
-        return 2;
+        return StandardCounts::TRIGGERS;
     }
 
     float ScriptingInterface::getTriggerValue(int triggerIndex) const {
@@ -365,7 +365,7 @@ namespace controller {
     }
 
     int ScriptingInterface::getNumberOfJoysticks() const {
-        return 2;
+        return StandardCounts::ANALOG_STICKS;
     }
 
     glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const {
@@ -382,22 +382,26 @@ namespace controller {
     }
 
     int ScriptingInterface::getNumberOfSpatialControls() const {
-        return 2;
+        return StandardCounts::POSES;
     }
 
     glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const {
+        // FIXME extract the position from the standard pose
         return vec3();
     }
 
     glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
+        // FIXME extract the velocity from the standard pose
         return vec3();
     }
 
     glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const {
+        // FIXME extract the normal from the standard pose
         return vec3();
     }
     
     glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
+        // FIXME extract the rotation from the standard pose
         return quat();
     }
 } // namespace controllers
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index 043e06a67f..0e0e38e055 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -99,7 +99,7 @@ namespace controller {
 
     public slots:
         virtual void update();
-        //virtual void registerControllerTypes(ScriptEngine* engine) = 0;
+        virtual void registerControllerTypes(QScriptEngine* engine) = 0;
 
     private:
         friend class MappingBuilderProxy;
diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h
index 505b4f85c7..0990e34224 100644
--- a/libraries/controllers/src/controllers/StandardControls.h
+++ b/libraries/controllers/src/controllers/StandardControls.h
@@ -56,4 +56,9 @@ namespace controller {
         NUM_STANDARD_POSES
     };
 
+    enum StandardCounts {
+        TRIGGERS = 2,
+        ANALOG_STICKS = 2,
+        POSES = 2, // FIXME 3?  if we want to expose the head?
+    };
 }
diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
index b52dd3f658..227bd12e1b 100644
--- a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
+++ b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
@@ -22,8 +22,8 @@ InputPluginList getInputPlugins() {
     InputPlugin* PLUGIN_POOL[] = {
         new KeyboardMouseDevice(),
         new SDL2Manager(),
-        //new SixenseManager(),
-        //new ViveControllerManager(),
+        new SixenseManager(),
+        new ViveControllerManager(),
         nullptr
     };
 
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 40d4d664ce..494f038a61 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -76,7 +76,6 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) {
     out = qobject_cast<AvatarData*>(object.toQObject());
 }
 
-
 QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) {
     return engine->newQObject(in);
 }
@@ -85,7 +84,8 @@ void inputControllerFromScriptValue(const QScriptValue &object, controller::Inpu
     out = qobject_cast<controller::InputController*>(object.toQObject());
 }
 
-ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, controller::ScriptingInterface* controllerScriptingInterface, bool wantSignals) :
+ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
+    controller::ScriptingInterface* controllerScriptingInterface, bool wantSignals) :
 
     _scriptContents(scriptContents),
     _isFinished(false),
@@ -93,6 +93,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
     _isInitialized(false),
     _timerFunctionMap(),
     _wantSignals(wantSignals),
+    _controllerScriptingInterface(controllerScriptingInterface), 
     _fileNameString(fileNameString),
     _quatLibrary(),
     _vec3Library(),
@@ -300,7 +301,7 @@ void ScriptEngine::init() {
     globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue);
 
     qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue);
-    //qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue);
+    qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue);
     qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue);
     qScriptRegisterMetaType(this, animationDetailsToScriptValue, animationDetailsFromScriptValue);
     qScriptRegisterMetaType(this, webSocketToScriptValue, webSocketFromScriptValue);
@@ -309,7 +310,7 @@ void ScriptEngine::init() {
 
     registerGlobalObject("Script", this);
     registerGlobalObject("Audio", &AudioScriptingInterface::getInstance());
-//    registerGlobalObject("Controller", _controllerScriptingInterface);
+    registerGlobalObject("Controller", _controllerScriptingInterface);
     registerGlobalObject("Entities", entityScriptingInterface.data());
     registerGlobalObject("Quat", &_quatLibrary);
     registerGlobalObject("Vec3", &_vec3Library);
@@ -319,9 +320,9 @@ void ScriptEngine::init() {
     // constants
     globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
 
-    //if (_controllerScriptingInterface) {
-    //    _controllerScriptingInterface->registerControllerTypes(this);
-    //}
+    if (_controllerScriptingInterface) {
+        _controllerScriptingInterface->registerControllerTypes(this);
+    }
 
 
 }
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index 0108899571..642159339e 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -184,6 +184,7 @@ private:
     QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot);
     void stopTimer(QTimer* timer);
 
+    controller::ScriptingInterface* _controllerScriptingInterface;
     QString _fileNameString;
     Quat _quatLibrary;
     Vec3 _vec3Library;

From 10df0f2d8c097889c32789a37ea2467eedd74e86 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 14 Oct 2015 17:07:10 -0700
Subject: [PATCH 030/301] Fix broken assignment-client build

---
 assignment-client/CMakeLists.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt
index e543b3aa21..5b92dfba99 100644
--- a/assignment-client/CMakeLists.txt
+++ b/assignment-client/CMakeLists.txt
@@ -1,12 +1,12 @@
 set(TARGET_NAME assignment-client)
 
-setup_hifi_project(Core Gui Network Script Widgets WebSockets)
+setup_hifi_project(Core Gui Network Script Quick Widgets WebSockets)
 
 # link in the shared libraries
 link_hifi_libraries( 
   audio avatars octree environment gpu model fbx entities 
   networking animation shared script-engine embedded-webserver
-  physics
+  controllers physics
 )
 
 include_application_version()

From 195045a4ec8a29c11ef65a1cecf433bcca756c98 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 14 Oct 2015 17:20:30 -0700
Subject: [PATCH 031/301] Next time remember to hit build all before commiting

---
 tests/controllers/src/main.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index 3a45195439..2056e34551 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -79,6 +79,12 @@ public:
     virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr;  }
 };
 
+class MyControllerScriptingInterface : public controller::ScriptingInterface {
+public:
+    virtual void registerControllerTypes(QScriptEngine* engine) {};
+};
+
+
 int main(int argc, char** argv) {
     QGuiApplication app(argc, argv);
     QQmlApplicationEngine engine;
@@ -116,7 +122,7 @@ int main(int argc, char** argv) {
         }
         //new PluginContainerProxy();
         auto rootContext = engine.rootContext();
-        rootContext->setContextProperty("Controllers", new ScriptingInterface());
+        rootContext->setContextProperty("Controllers", new MyControllerScriptingInterface());
     }
     engine.load(getQmlDir() + "main.qml");
     app.exec();

From 12e103c90c03c707c9c13601166e06ee99d17fb2 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 14 Oct 2015 17:41:39 -0700
Subject: [PATCH 032/301] Get json creating the mappings from js

---
 examples/controllers/controllerMappings.js    |  71 ++++++++
 .../controllers/src/controllers/Filter.cpp    |  46 ++++-
 .../controllers/src/controllers/Filter.h      | 157 +++++++++---------
 .../NewControllerScriptingInterface.cpp       |  35 +++-
 .../NewControllerScriptingInterface.h         |   1 +
 .../controllers/impl/RouteBuilderProxy.cpp    |  28 +---
 .../src/input-plugins/UserInputMapper.cpp     |  46 ++++-
 .../src/input-plugins/UserInputMapper.h       |   5 +-
 8 files changed, 275 insertions(+), 114 deletions(-)
 create mode 100644 examples/controllers/controllerMappings.js

diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js
new file mode 100644
index 0000000000..45383886c2
--- /dev/null
+++ b/examples/controllers/controllerMappings.js
@@ -0,0 +1,71 @@
+
+//
+//  controllerScriptingExamples.js
+//  examples
+//
+//  Created by Sam Gondelman on 6/2/15
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+// Assumes you only have the default keyboard connected
+
+myFirstMapping = function() {
+return {
+    "name": "example mapping from Standard to actions",
+    "channels": [ {
+            "from": "Keyboard.A",
+            "filters": [ {
+                    "type": "clamp",
+                    "params": [0, 1],
+                }
+            ],
+            "to": "Actions.LONGITUDINAL_FORWARD",
+        }, {
+            "from": "Keyboard.Left",
+            "filters": [ {
+                    "type": "clamp",
+                    "params": [0, 1],
+                }, {
+                    "type": "invert"
+                }
+            ],
+            "to": "Actions.LONGITUDINAL_BACKWARD",
+        }, {
+            "from": "Keyboard.C",
+            "filters": [ {
+                    "type": "scale",
+                    "params": [2.0],
+                }
+            ],
+            "to": "Actions.Yaw",
+        }, {
+            "from": "Keyboard.B",
+            "to": "Actions.Yaw"
+        }
+    ]
+}
+}
+
+
+//Script.include('mapping-test0.json');
+var myFirstMappingJSON = myFirstMapping();
+print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
+
+var mapping = NewControllers.parseMapping(JSON.stringify(myFirstMappingJSON));
+
+Object.keys(Controller.Standard).forEach(function (input) {
+    print("Controller.Standard." + input + ":" + Controller.Standard[input]);
+});
+
+Object.keys(Controller.Hardware).forEach(function (deviceName) {
+    Object.keys(Controller.Hardware[deviceName]).forEach(function (input) {
+        print("Controller.Hardware." + deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]);
+    });
+});
+
+Object.keys(Controller.Actions).forEach(function (actionName) {
+    print("Controller.Actions." + actionName + ":" + Controller.Actions[actionName]);
+});
diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
index b7175f1716..3e1079b984 100644
--- a/libraries/controllers/src/controllers/Filter.cpp
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -44,7 +44,7 @@ Filter::Pointer Filter::parse(const QJsonObject& json) {
     return Filter::Pointer();
 }
 
-Filter::Factory::ClassEntry<ScaleFilter> ScaleFilter::_factoryEntry;
+ScaleFilter::FactoryEntryBuilder ScaleFilter::_factoryEntryBuilder;
 
 bool ScaleFilter::parseParameters(const QJsonArray& parameters) {
     if (parameters.size() > 1) {
@@ -53,7 +53,39 @@ bool ScaleFilter::parseParameters(const QJsonArray& parameters) {
     return true;
 }
 
-Filter::Factory::ClassEntry<PulseFilter> PulseFilter::_factoryEntry;
+InvertFilter::FactoryEntryBuilder InvertFilter::_factoryEntryBuilder;
+
+
+ClampFilter::FactoryEntryBuilder ClampFilter::_factoryEntryBuilder;
+
+bool ClampFilter::parseParameters(const QJsonArray& parameters) {
+    if (parameters.size() > 1) {
+        _min = parameters[0].toDouble();
+    }
+    if (parameters.size() > 2) {
+        _max = parameters[1].toDouble();
+    }
+    return true;
+}
+
+DeadZoneFilter::FactoryEntryBuilder DeadZoneFilter::_factoryEntryBuilder;
+
+float DeadZoneFilter::apply(float value) const {
+    float scale = 1.0f / (1.0f - _min);
+    if (abs(value) < _min) {
+        return 0.0f;
+    }
+    return (value - _min) * scale;
+}
+
+bool DeadZoneFilter::parseParameters(const QJsonArray& parameters) {
+    if (parameters.size() > 1) {
+        _min = parameters[0].toDouble();
+    }
+    return true;
+}
+
+PulseFilter::FactoryEntryBuilder PulseFilter::_factoryEntryBuilder;
 
 
 float PulseFilter::apply(float value) const {
@@ -72,5 +104,13 @@ float PulseFilter::apply(float value) const {
 }
 
 bool PulseFilter::parseParameters(const QJsonArray& parameters) {
-    return false;
+    if (parameters.size() > 1) {
+        _interval = parameters[0].toDouble();
+    }
+    return true;
 }
+
+ConstrainToIntegerFilter::FactoryEntryBuilder ConstrainToIntegerFilter::_factoryEntryBuilder;
+
+ConstrainToPositiveIntegerFilter::FactoryEntryBuilder ConstrainToPositiveIntegerFilter::_factoryEntryBuilder;
+
diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h
index 4d21966731..4d8c483b08 100644
--- a/libraries/controllers/src/controllers/Filter.h
+++ b/libraries/controllers/src/controllers/Filter.h
@@ -16,6 +16,8 @@
 #include <functional>
 #include <map>
 
+#include <GLMHelpers.h>
+
 #include <QtCore/QEasingCurve>
 
 class QJsonObject;
@@ -23,40 +25,7 @@ class QJsonArray;
 
 
 namespace controller {
-    /*
-    template <class T> class Factory {
-    public:
 
-    template <class T> class Entry {
-    public:
-    virtual T* create() = 0;
-    };
-
-    template <class T, class S> class DefaultEntry{
-    public:
-    T* create() { return new S(); }
-    };
-
-    using EntryMap = std::map<std::string, std::unique_ptr<Entry<T>>>;
-
-    void registerEntry(const std::string& name, std::unique_ptr<Entry<T>>& entry) {
-    if (entry) {
-    _entries[name] = entry;
-    }
-    }
-
-    T* create(const std::string& name) const {
-    auto& entryIt = _entries.find(name);
-    if (entryIt != _entries.end()) {
-    return (*entryIt).second->create();
-    }
-    return nullptr;
-    }
-
-    protected:
-    EntryMap _entries;
-    };
-    */
     // Encapsulates part of a filter chain
     class Filter {
     public:
@@ -67,36 +36,40 @@ namespace controller {
         using Lambda = std::function<float(float)>;
 
         // Factory features
-        virtual bool parseParameters(const QJsonArray& parameters) = 0;
+        virtual bool parseParameters(const QJsonArray& parameters) { return true; }
 
         class Factory {
         public:
 
             class Entry {
             public:
-                virtual Filter* create() = 0;
-                virtual const std::string& getName() const = 0;
+                virtual Filter* create() const = 0;
+                virtual const char* getName() const = 0;
 
-                Entry() = default;
-                virtual ~Entry() = default;
+                Entry() {};
+                virtual ~Entry() {};
             };
 
-            template <class T, std::string name> class ClassEntry {
+            template <class T> class ClassEntry : public Entry {
             public:
-                Filter* create() override { return (Filter*) new T(); }
-                const std::string& getName() const override {
-                    return _name
-                };
+                virtual Filter* create() const { return (Filter*) new T(); }
+                virtual const char* getName() const {  return T::getName(); };
 
-                ClassEntry() : _name(name) {};
+                ClassEntry() {};
                 virtual ~ClassEntry() = default;
 
-                const std::string _name;
+                class Builder {
+                public:
+                    Builder() {
+                        std::shared_ptr<Entry> classEntry(new ClassEntry<T>());
+                        Filter::getFactory().registerEntry(classEntry);
+                    }
+                };
             };
 
             using EntryMap = std::map<std::string, std::shared_ptr<Entry>>;
 
-            void registerEntry(const std::shared_ptr<Entry>& entry) {
+            void registerEntry(std::shared_ptr<Entry>& entry) {
                 if (entry) {
                     _entries.insert(EntryMap::value_type(entry->getName(), entry));
                 }
@@ -122,8 +95,9 @@ namespace controller {
 }
 
 #define REGISTER_FILTER_CLASS(classEntry, className) \
-    using FactoryEntry = Filter::Factory::ClassEntry<classEntry, className>;\
-    static FactoryEntry _factoryEntry;
+    static const char* getName() { return className; } \
+    using FactoryEntryBuilder = Filter::Factory::ClassEntry<classEntry>::Builder;\
+    static FactoryEntryBuilder _factoryEntryBuilder;
 
 namespace controller {
 
@@ -150,6 +124,7 @@ namespace controller {
    
     class ScaleFilter : public Filter {
     public:
+        REGISTER_FILTER_CLASS(ScaleFilter, "scale");
         ScaleFilter() {}
         ScaleFilter(float scale): _scale(scale) {}
 
@@ -158,38 +133,48 @@ namespace controller {
         }
         virtual bool parseParameters(const QJsonArray& parameters);
 
-     //   static Filter::Factory::ClassEntry<ScaleFilter, "scale"> _factoryEntry;
-        REGISTER_FILTER_CLASS(ScaleFilter, "scale");
     private:
         float _scale = 1.0f;
     };
 
-    //class AbstractRangeFilter : public Filter {
-    //public:
-    //    RangeFilter(float min, float max) : _min(min), _max(max) {}
+    class InvertFilter : public ScaleFilter {
+    public:
+        REGISTER_FILTER_CLASS(InvertFilter, "invert");
+        InvertFilter() : ScaleFilter(-1.0f) {}
+        
+        virtual bool parseParameters(const QJsonArray& parameters) { return true; }
 
-    //protected:
-    //    const float _min;
-    //    const float _max;
-    //};
+    private:
+    };
 
-    ///*
-    //* Constrains will emit the input value on the first call, and every *interval* seconds, otherwise returns 0
-    //*/
-    //class PulseFilter : public Filter {
-    //public:
-    //    PulseFilter(float interval);
-    //    virtual float apply(float value) const override;
+    class ClampFilter : public Filter {
+    public:
+        REGISTER_FILTER_CLASS(ClampFilter, "clamp");
+        ClampFilter(float min = 0.0, float max = 1.0) : _min(min), _max(max) {};
 
-    //private:
-    //    float _lastEmitTime{ -std::numeric_limits<float>::max() };
-    //    const float _interval;
-    //};
+        virtual float apply(float value) const override {
+            return glm::clamp(value, _min, _max);
+        }
+        virtual bool parseParameters(const QJsonArray& parameters) override;
+    protected:
+        float _min = 0.0f;
+        float _max = 1.0f;
+    };
 
+    class DeadZoneFilter : public Filter {
+    public:
+        REGISTER_FILTER_CLASS(DeadZoneFilter, "deadZone");
+        DeadZoneFilter(float min = 0.0) : _min(min) {};
+
+        virtual float apply(float value) const override;
+        virtual bool parseParameters(const QJsonArray& parameters) override;
+    protected:
+        float _min = 0.0f;
+    };
 
     class PulseFilter : public Filter {
     public:
-        REGISTER_FILTER_CLASS(PulseFilter);
+        REGISTER_FILTER_CLASS(PulseFilter, "pulse");
         PulseFilter() {}
         PulseFilter(float interval) : _interval(interval) {}
 
@@ -199,15 +184,31 @@ namespace controller {
         virtual bool parseParameters(const QJsonArray& parameters);
 
     private:
-        mutable float _lastEmitTime{ -std::numeric_limits<float>::max() };
+        mutable float _lastEmitTime{ -::std::numeric_limits<float>::max() };
         float _interval = 1.0f;
     };
 
-    ////class DeadzoneFilter : public AbstractRangeFilter {
-    ////public:
-    ////    DeadzoneFilter(float min, float max = 1.0f);
-    ////    virtual float apply(float newValue, float oldValue) override;
-    ////};
+    class ConstrainToIntegerFilter : public Filter {
+    public:
+        REGISTER_FILTER_CLASS(ConstrainToIntegerFilter, "constrainToInteger");
+        ConstrainToIntegerFilter() {};
+
+        virtual float apply(float value) const override {
+            return glm::sign(value);
+        }
+    protected:
+    };
+
+    class ConstrainToPositiveIntegerFilter : public Filter {
+    public:
+        REGISTER_FILTER_CLASS(ConstrainToPositiveIntegerFilter, "constrainToPositiveInteger");
+        ConstrainToPositiveIntegerFilter() {};
+
+        virtual float apply(float value) const override {
+            return (value <= 0.0f) ? 0.0f : 1.0f;
+        }
+    protected:
+    };
 
     //class EasingFilter : public Filter {
     //public:
@@ -236,12 +237,6 @@ namespace controller {
     //    const float _exponent;
     //};
 
-    //class ClampFilter : public RangeFilter {
-    //public:
-    //    ClampFilter(float min = 0.0, float max = 1.0) : RangeFilter(min, max) {};
-    //    virtual float apply(float value) const override;
-    //};
-
     //class AbsFilter : public Filter {
     //public:
     //    virtual float apply(float value) const override;
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
index c80e5fc721..baeae55128 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp
@@ -12,6 +12,9 @@
 
 #include <QtCore/QRegularExpression>
 
+#include <QJsonDocument>
+#include <QJsonObject>
+
 #include <GLMHelpers.h>
 #include <DependencyManager.h>
 #include <input-plugins/UserInputMapper.h>
@@ -22,8 +25,6 @@
 #include "impl/MappingBuilderProxy.h"
 #include "Logging.h"
 
-static const uint16_t ACTIONS_DEVICE = UserInputMapper::Input::INVALID_DEVICE - (uint16_t)1;
-
 namespace controller {
 
 
@@ -161,7 +162,7 @@ namespace controller {
         int actionNumber = 0;
         qCDebug(controllers) << "Setting up standard actions";
         for (const auto& actionName : actionNames) {
-            UserInputMapper::Input actionInput(ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
+            UserInputMapper::Input actionInput(UserInputMapper::Input::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
             qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16);
             // Expose the IDs to JS
             _actions.insert(sanatizeName(actionName), actionInput.getID());
@@ -182,6 +183,34 @@ namespace controller {
         return new MappingBuilderProxy(*this, mapping);
     }
 
+    QObject* NewControllerScriptingInterface::parseMapping(const QString& json) {
+
+        QJsonObject obj;
+        QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
+        // check validity of the document
+        if (!doc.isNull()) {
+            if (doc.isObject()) {
+                obj = doc.object();
+
+                auto mapping = std::make_shared<Mapping>("default");
+                auto mappingBuilder = new MappingBuilderProxy(*this, mapping);
+
+                mappingBuilder->parse(obj);
+
+                _mappingsByName[mapping->_name] = mapping;
+
+            } else {
+                qDebug() << "Mapping json Document is not an object" << endl;
+            }
+        } else {
+            qDebug() << "Invalid JSON...\n" << json << endl;
+        }
+
+        return nullptr;
+    }
+    
+    Q_INVOKABLE QObject* newMapping(const QJsonObject& json);
+
     void NewControllerScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
         auto iterator = _mappingsByName.find(mappingName);
         if (_mappingsByName.end() == iterator) {
diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
index bdc291bc03..784b8cf5bd 100644
--- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
+++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h
@@ -40,6 +40,7 @@ namespace controller {
 
         Q_INVOKABLE void update();
         Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
+        Q_INVOKABLE QObject* parseMapping(const QString& json);
         Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
         Q_INVOKABLE void disableMapping(const QString& mappingName) {
             enableMapping(mappingName, false);
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index d606b52608..38efcfdb00 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -57,9 +57,7 @@ QObject* RouteBuilderProxy::filter(const QScriptValue& expression) {
 
 
 QObject* RouteBuilderProxy::clamp(float min, float max) {
-    addFilter([=](float value) {
-        return glm::clamp(value, min, max);
-    });
+    addFilter(Filter::Pointer(new ClampFilter(min, max)));
     return this;
 }
 
@@ -69,40 +67,28 @@ QObject* RouteBuilderProxy::scale(float multiplier) {
 }
 
 QObject* RouteBuilderProxy::invert() {
-    return scale(-1.0f);
+    addFilter(Filter::Pointer(new InvertFilter()));
+    return this;
 }
 
 QObject* RouteBuilderProxy::deadZone(float min) {
-    assert(min < 1.0f);
-    float scale = 1.0f / (1.0f - min);
-    addFilter([=](float value) {
-        if (abs(value) < min) {
-            return 0.0f;
-        }
-        return (value - min) * scale;
-    });
-
+    addFilter(Filter::Pointer(new DeadZoneFilter(min)));
     return this;
 }
 
 QObject* RouteBuilderProxy::constrainToInteger() {
-    addFilter([=](float value) {
-        return glm::sign(value);
-    });
+    addFilter(Filter::Pointer(new ConstrainToIntegerFilter()));
     return this;
 }
 
 QObject* RouteBuilderProxy::constrainToPositiveInteger() {
-    addFilter([=](float value) {
-        return (value <= 0.0f) ? 0.0f : 1.0f;
-    });
+    addFilter(Filter::Pointer(new ConstrainToPositiveIntegerFilter()));
     return this;
 }
 
 
 QObject* RouteBuilderProxy::pulse(float interval) {
-    Filter::Pointer filter = std::make_shared<PulseFilter>(interval);
-    addFilter(filter);
+    addFilter(Filter::Pointer(new PulseFilter(interval)));
     return this;
 }
 
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
index 325dc5dfe7..0f797e9ad0 100755
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
+++ b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
@@ -12,10 +12,15 @@
 #include "UserInputMapper.h"
 #include "StandardController.h"
 
+#include <QLoggingCategory>
+Q_DECLARE_LOGGING_CATEGORY(userInputMapper)
+Q_LOGGING_CATEGORY(userInputMapper, "hifi.userInputMapper")
+
 const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX);
 const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
 const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
-const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
+const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
+const uint16_t UserInputMapper::Input::ACTIONS_DEVICE = INVALID_DEVICE - (uint16)1;
 
 // Default contruct allocate the poutput size with the current hardcoded action channels
 UserInputMapper::UserInputMapper() {
@@ -31,6 +36,7 @@ UserInputMapper::~UserInputMapper() {
 bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
     proxy->_name += " (" + QString::number(deviceID) + ")";
     _registeredDevices[deviceID] = proxy;
+    qCDebug(userInputMapper) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
     return true;
 }
 
@@ -65,12 +71,18 @@ void UserInputMapper::resetDevice(uint16 deviceID) {
 }
 
 int UserInputMapper::findDevice(QString name) const {
+    if (_standardDevice && (_standardDevice->getName() == name)) {
+        return getStandardDeviceID();
+    }
+
     for (auto device : _registeredDevices) {
         if (device.second->_name.split(" (")[0] == name) {
             return device.first;
+        } else if (device.second->_baseName == name) {
+            return device.first;
         }
     }
-    return 0;
+    return Input::INVALID_DEVICE;
 }
 
 QVector<QString> UserInputMapper::getDeviceNames() {
@@ -94,10 +106,34 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName
 
         int deviceID = findDevice(deviceName);
         if (deviceID != Input::INVALID_DEVICE) {
-         //   getAllInputsForDevice(deviceID);
+            const auto& deviceProxy = _registeredDevices.at(deviceID);
+            auto deviceInputs = deviceProxy->getAvailabeInputs();
+
+            for (auto input : deviceInputs) {
+                if (input.second == inputName) {
+                    return input.first;
+                }
+            }
+
+            qCDebug(userInputMapper) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">";
+
+        } else if (deviceName == "Actions") {
+            deviceID = Input::ACTIONS_DEVICE;
+            int actionNum = 0;
+            for (auto action : _actionNames) {
+                if (action == inputName) {
+                    return Input(Input::ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
+                }
+                actionNum++;
+            }
+
+            qCDebug(userInputMapper) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions";
+
+        } else {
+            qCDebug(userInputMapper) << "Couldn\'t find InputDevice named <" << deviceName << ">";
         }
-
-
+    } else {
+        qCDebug(userInputMapper) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
     }
 
     return Input();
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.h b/libraries/input-plugins/src/input-plugins/UserInputMapper.h
index b7b105df5e..fae77cca92 100755
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.h
+++ b/libraries/input-plugins/src/input-plugins/UserInputMapper.h
@@ -85,6 +85,7 @@ public:
         static const uint16 INVALID_DEVICE;
         static const uint16 INVALID_CHANNEL;
         static const uint16 INVALID_TYPE;
+        static const uint16 ACTIONS_DEVICE;
     };
 
 
@@ -119,9 +120,11 @@ public:
 
    class DeviceProxy {
     public:
-       DeviceProxy(QString name) { _name = name; }
+       DeviceProxy(QString name) : _baseName(name), _name(name) {}
+       const QString& getBaseName() const { return _baseName; }
        const QString& getName() const { return _name; }
 
+       QString _baseName;
        QString _name;
        ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
        AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; };

From 46e40ed032ab7a40fe6832b9b97f15f56ffd3bb4 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 14 Oct 2015 18:52:19 -0700
Subject: [PATCH 033/301] work on device names

---
 .../src/input-plugins/SixenseManager.cpp       |  9 ++++++---
 .../src/input-plugins/UserInputMapper.cpp      | 18 ++++++++++++++++--
 .../src/input-plugins/UserInputMapper.h        |  4 ++++
 3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index a20fe5fc4c..a99e04ff13 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -159,9 +159,12 @@ void SixenseManager::setSixenseFilter(bool filter) {
 }
 
 void SixenseManager::update(float deltaTime, bool jointsCaptured) {
-    if (!_activated) {
-        return;
-    }
+    // FIXME - Some of the code in update() will crash if you haven't actually activated the
+    // plugin. But we want register with the UserInputMapper if we don't call this.
+    // We need to clean this up.
+    //if (!_activated) {
+    //    return;
+    //}
 #ifdef HAVE_SIXENSE
     _buttonPressedMap.clear();
 
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
index c29acc09af..a30eac5c2a 100755
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
+++ b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
@@ -28,8 +28,22 @@ UserInputMapper::~UserInputMapper() {
 }
 
 
-bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
-    proxy->_name += " (" + QString::number(deviceID) + ")";
+int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
+    if (!_deviceCounts.contains(deviceName)) {
+        _deviceCounts[deviceName] = 0;
+    }
+    _deviceCounts[deviceName] += 1;
+
+    return _deviceCounts[deviceName];
+}
+
+bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) {
+    int numberOfType = recordDeviceOfType(proxy->_name);
+
+    if (numberOfType > 1) {
+        proxy->_name += QString::number(numberOfType);
+    }
+
     _registeredDevices[deviceID] = proxy;
     return true;
 }
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.h b/libraries/input-plugins/src/input-plugins/UserInputMapper.h
index 304e74e8cc..5a535b6a3c 100755
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.h
+++ b/libraries/input-plugins/src/input-plugins/UserInputMapper.h
@@ -133,6 +133,7 @@ public:
     };
     // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
     uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
+
     bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device);
     bool registerStandardDevice(const DeviceProxy::Pointer& device) { _standardDevice = device; return true; }
     DeviceProxy::Pointer getDeviceProxy(const Input& input);
@@ -285,6 +286,9 @@ protected:
     std::vector<PoseValue> _poseStates = std::vector<PoseValue>(NUM_ACTIONS);
 
     glm::mat4 _sensorToWorldMat;
+
+    int recordDeviceOfType(const QString& deviceName);
+    QHash<const QString&, int> _deviceCounts;
 };
 
 Q_DECLARE_METATYPE(UserInputMapper::InputPair)

From 4f8e2c9f6b30b91f2f9b2b998043ef12e0155c18 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 15 Oct 2015 13:18:04 -0700
Subject: [PATCH 034/301] Fix JSON format errors

---
 interface/resources/controllers/mapping-test0.json | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/interface/resources/controllers/mapping-test0.json b/interface/resources/controllers/mapping-test0.json
index c52b03be92..d6a1de5313 100644
--- a/interface/resources/controllers/mapping-test0.json
+++ b/interface/resources/controllers/mapping-test0.json
@@ -5,29 +5,29 @@
             "filters": [ {
                     "type": "clamp",
                     "min": 0,
-                    "max": 1,
+                    "max": 1
                 }
             ],
-            "to": "Actions.Forward",
+            "to": "Actions.Forward"
         }, {
             "from": "Standard.LY",
             "filters": [ {
                     "type": "clamp",
                     "min": -1,
-                    "max": 0,
+                    "max": 0
                 }, {
                     "type": "invert"
                 }
             ],
-            "to": "Actions.Backward",
+            "to": "Actions.Backward"
         }, {
             "from": "Standard.LX",
             "filters": [ {
                     "type": "scale",
-                    "scale": 2.0,
+                    "scale": 2.0
                 }
             ],
-            "to": "Actions.Yaw",
+            "to": "Actions.Yaw"
         }, {
             "from": "Standard.A",
             "to": "Actions.Action0"

From eff8c28a28a5c4df273538b0cf4364f3946937d6 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 15 Oct 2015 14:04:55 -0700
Subject: [PATCH 035/301] Fixing access to hardware devices

---
 .../src/controllers/ScriptingInterface.cpp    | 69 ++++++++++++-------
 .../src/controllers/ScriptingInterface.h      |  1 +
 2 files changed, 45 insertions(+), 25 deletions(-)

diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index a843775dcc..002814853f 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -111,31 +111,6 @@ namespace controller {
 
     ScriptingInterface::ScriptingInterface() {
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        auto devices = userInputMapper->getDevices();
-        for (const auto& deviceMapping : devices) {
-            auto device = deviceMapping.second.get();
-            auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
-            qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
-            // Expose the IDs to JS
-            _hardware.insert(deviceName, createDeviceMap(device));
-
-            // Create the endpoints
-            for (const auto& inputMapping : device->getAvailabeInputs()) {
-                const auto& input = inputMapping.first;
-                // Ignore aliases
-                if (_endpoints.count(input)) {
-                    continue;
-                }
-                _endpoints[input] = std::make_shared<LambdaEndpoint>([=] {
-                    auto deviceProxy = userInputMapper->getDeviceProxy(input);
-                    if (!deviceProxy) {
-                        return 0.0f;
-                    }
-                    return deviceProxy->getValue(input, 0);
-                });
-            }
-        }
-
         qCDebug(controllers) << "Setting up standard controller abstraction";
         auto standardDevice = userInputMapper->getStandardDevice();
         // Expose the IDs to JS
@@ -150,6 +125,7 @@ namespace controller {
             _endpoints[standardInput] = std::make_shared<VirtualEndpoint>(standardInput);
         }
 
+        // FIXME allow custom user actions?
         auto actionNames = userInputMapper->getActionNames();
         int actionNumber = 0;
         qCDebug(controllers) << "Setting up standard actions";
@@ -164,6 +140,8 @@ namespace controller {
             // FIXME action endpoints need to accumulate values, and have them cleared at each frame
             _endpoints[actionInput] = std::make_shared<VirtualEndpoint>();
         }
+
+        updateMaps();
     }
 
     QObject* ScriptingInterface::newMapping(const QString& mappingName) {
@@ -231,6 +209,12 @@ namespace controller {
 
     void ScriptingInterface::update() {
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        static auto deviceNames = userInputMapper->getDeviceNames();
+
+        if (deviceNames != userInputMapper->getDeviceNames()) {
+            updateMaps();
+            deviceNames = userInputMapper->getDeviceNames();
+        }
 
         _overrideValues.clear();
         EndpointSet readEndpoints;
@@ -404,6 +388,41 @@ namespace controller {
         // FIXME extract the rotation from the standard pose
         return quat();
     }
+
+    void ScriptingInterface::updateMaps() {
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        auto devices = userInputMapper->getDevices();
+        QSet<QString> foundDevices;
+        for (const auto& deviceMapping : devices) {
+            auto device = deviceMapping.second.get();
+            auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
+            qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
+            foundDevices.insert(device->getName());
+            if (_hardware.contains(deviceName)) {
+                continue;
+            }
+
+            // Expose the IDs to JS
+            _hardware.insert(deviceName, createDeviceMap(device));
+
+            // Create the endpoints
+            for (const auto& inputMapping : device->getAvailabeInputs()) {
+                const auto& input = inputMapping.first;
+                // Ignore aliases
+                if (_endpoints.count(input)) {
+                    continue;
+                }
+                _endpoints[input] = std::make_shared<LambdaEndpoint>([=] {
+                    auto deviceProxy = userInputMapper->getDeviceProxy(input);
+                    if (!deviceProxy) {
+                        return 0.0f;
+                    }
+                    return deviceProxy->getValue(input, 0);
+                });
+            }
+        }
+    }
+
 } // namespace controllers
 
 //var mapping = Controller.newMapping();
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index 0e0e38e055..d90a47cf12 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -100,6 +100,7 @@ namespace controller {
     public slots:
         virtual void update();
         virtual void registerControllerTypes(QScriptEngine* engine) = 0;
+        virtual void updateMaps();
 
     private:
         friend class MappingBuilderProxy;

From 416df1c44c7f1c181ab7fd81e66f5888a3bfb4a2 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 15 Oct 2015 14:21:08 -0700
Subject: [PATCH 036/301] Fixing the mac build

---
 libraries/controllers/src/controllers/Filter.h            | 2 +-
 .../src/controllers/impl/RouteBuilderProxy.cpp            | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h
index 4d8c483b08..876f57c97d 100644
--- a/libraries/controllers/src/controllers/Filter.h
+++ b/libraries/controllers/src/controllers/Filter.h
@@ -76,7 +76,7 @@ namespace controller {
             }
 
             Filter* create(const std::string& name) const {
-                auto& entryIt = _entries.find(name);
+                const auto& entryIt = _entries.find(name);
                 if (entryIt != _entries.end()) {
                     return (*entryIt).second->create();
                 }
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index aeef081b5f..dcf2b30f66 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -121,12 +121,12 @@ QObject* RouteBuilderProxy::filters(const QJsonValue& json) {
 }
 
 void RouteBuilderProxy::to(const QJsonValue& json) {
-    if (json.isString()) {
-
-        return to(_parent.endpointFor(_parent.inputFor(json.toString())));
+    if (json.isString()) {
+
+        return to(_parent.endpointFor(_parent.inputFor(json.toString())));
     } else if (json.isObject()) {
         // Endpoint is defined as an object, we expect a js function then
-        return to(nullptr);
+        //return to((Endpoint*) nullptr);
     }
 
 }

From 249efa383ea41d534d802426fb966a4a5b17cfe9 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 15 Oct 2015 14:49:22 -0700
Subject: [PATCH 037/301] MErging maybe finally ??????

---
 .../src/controllers/UserInputMapper.cpp       | 171 ------------------
 1 file changed, 171 deletions(-)

diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 2d03fbe58b..b62e2e0e8f 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -93,177 +93,6 @@ QVector<QString> UserInputMapper::getDeviceNames() {
 }
 
 UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
-/*=======
-
-// Default contruct allocate the poutput size with the current hardcoded action channels
-UserInputMapper::UserInputMapper() {
-    registerStandardDevice();
-    assignDefaulActionScales();
-    createActionNames();
-}
-
-UserInputMapper::~UserInputMapper() {
-}
-
-
-int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
-    if (!_deviceCounts.contains(deviceName)) {
-        _deviceCounts[deviceName] = 0;
-    }
-    _deviceCounts[deviceName] += 1;
-
-    return _deviceCounts[deviceName];
-}
-
-bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) {
-    int numberOfType = recordDeviceOfType(proxy->_name);
-
-    if (numberOfType > 1) {
-        proxy->_name += QString::number(numberOfType);
-    }
-
-    _registeredDevices[deviceID] = proxy;
-    return true;
-}
-
-UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
-    auto device = _registeredDevices.find(input.getDevice());
-    if (device != _registeredDevices.end()) {
-        return (device->second);
-    } else {
-        return DeviceProxy::Pointer();
-    }
-}
-
-QString UserInputMapper::getDeviceName(uint16 deviceID) { 
-    if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
-        return _registeredDevices[deviceID]->_name;
-    }
-    return QString("unknown");
-}
-
-
-void UserInputMapper::resetAllDeviceBindings() {
-    for (auto device : _registeredDevices) {
-        device.second->resetDeviceBindings();
-    }
-}
-
-void UserInputMapper::resetDevice(uint16 deviceID) {
-    auto device = _registeredDevices.find(deviceID);
-    if (device != _registeredDevices.end()) {
-        device->second->resetDeviceBindings();
-    }
-}
-
-int UserInputMapper::findDevice(QString name) {
-    for (auto device : _registeredDevices) {
-        if (device.second->_name.split(" (")[0] == name) {
-            return device.first;
-        }
-    }
-    return 0;
-}
-
-QVector<QString> UserInputMapper::getDeviceNames() {
-    QVector<QString> result;
-    for (auto device : _registeredDevices) {
-        QString deviceName = device.second->_name.split(" (")[0];
-        result << deviceName;
-    }
-    return result;
-}
-
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
-    return addInputChannel(action, input, Input(), scale);
-}
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
-    // Check that the device is registered
-    if (!getDeviceProxy(input)) {
-        qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
-        return false;
-    }
-    
-    auto inputChannel = InputChannel(input, modifier, action, scale);
-
-    // Insert or replace the input to modifiers
-    if (inputChannel.hasModifier()) {
-        auto& modifiers = _inputToModifiersMap[input.getID()];
-        modifiers.push_back(inputChannel._modifier);
-        std::sort(modifiers.begin(), modifiers.end());
-    }
-
-    // Now update the action To Inputs side of things
-    _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
-
-    return true;
-}
-
-int UserInputMapper::addInputChannels(const InputChannels& channels) {
-    int nbAdded = 0;
-    for (auto& channel : channels) {
-        nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
-    }
-    return nbAdded;
-}
-
-bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
-    // Remove from Input to Modifiers map
-    if (inputChannel.hasModifier()) {
-        _inputToModifiersMap.erase(inputChannel._input.getID());
-    }
-    
-    // Remove from Action to Inputs map
-    std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
-    ret = _actionToInputsMap.equal_range(inputChannel._action);
-    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
-        if (it->second == inputChannel) {
-            _actionToInputsMap.erase(it);
-            return true;
-        }
-    }
-    
-    return false;
-}
-
-void UserInputMapper::removeAllInputChannels() {
-    _inputToModifiersMap.clear();
-    _actionToInputsMap.clear();
-}
-
-void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
-    QVector<InputChannel> channels = getAllInputsForDevice(device);
-    for (auto& channel : channels) {
-        removeInputChannel(channel);
-    }
-}
-
-void UserInputMapper::removeDevice(int device) {
-    removeAllInputChannelsForDevice((uint16) device);
-    _registeredDevices.erase(device);
-}
-
-int UserInputMapper::getInputChannels(InputChannels& channels) const {
-    for (auto& channel : _actionToInputsMap) {
-        channels.push_back(channel.second);
-    }
-
-    return _actionToInputsMap.size();
-}
-
-QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
-    InputChannels allChannels;
-    getInputChannels(allChannels);
-    
-    QVector<InputChannel> channels;
-    for (InputChannel inputChannel : allChannels) {
-        if (inputChannel._input._device == device) {
-            channels.push_back(inputChannel);
-        }
-    }
->>>>>>> 80cffdb764d3faa5516c8b0eb0a49d84cc395416*/
     
     // Split the full input name as such: deviceName.inputName
     auto names = inputName.split('.');

From 1b03b6867c075a1c4b4430a0a682a8a4d9fb62aa Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 15 Oct 2015 15:01:34 -0700
Subject: [PATCH 038/301] Fixing the include file names...

---
 libraries/controllers/src/controllers/Filter.cpp             | 4 ++--
 .../controllers/src/controllers/impl/MappingBuilderProxy.cpp | 5 +++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
index 3e1079b984..43317fd62d 100644
--- a/libraries/controllers/src/controllers/Filter.cpp
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -11,8 +11,8 @@
 #include <QtCore/QObject>
 #include <QtScript/QScriptValue>
 
-#include <QJSonObject>
-#include <QJSonArray>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
 
 #include "SharedUtil.h"
 
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index b347d8b7c6..fe7a5c24af 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -11,8 +11,9 @@
 #include <QtCore/QHash>
 #include <QtCore/QDebug>
 
-#include <QJSonObject>
-#include <QJSonArray>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
 
 #include "RouteBuilderProxy.h"
 #include "../ScriptingInterface.h"

From 63ad9ae19837c2d829a42a63cb99a108d82350d8 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 15 Oct 2015 15:02:55 -0700
Subject: [PATCH 039/301] Fixing the include file names...

---
 .../controllers/src/controllers/impl/RouteBuilderProxy.cpp    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index dcf2b30f66..033e94daa0 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -9,8 +9,8 @@
 
 #include <QtCore/QDebug>
 
-#include <QJSonObject>
-#include <QJSonArray>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
 
 #include <GLMHelpers.h>
 

From 43d7fe491ec4720df6976be638a41b9620534860 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 15 Oct 2015 17:53:53 -0700
Subject: [PATCH 040/301] wiring the actions

---
 examples/controllers/controllerMappings.js    |  4 +++-
 .../src/controllers/ScriptingInterface.cpp    | 23 ++++++++++++++++++-
 .../src/controllers/UserInputMapper.h         |  2 ++
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js
index e4ef0270ab..959dc1b0ca 100644
--- a/examples/controllers/controllerMappings.js
+++ b/examples/controllers/controllerMappings.js
@@ -14,7 +14,7 @@
 
 myFirstMapping = function() {
 return {
-    "name": "example mapping from Standard to actions",
+    "name": "example",
     "channels": [ {
             "from": "Keyboard.A",
             "filters": [ {
@@ -56,6 +56,8 @@ print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
 
 var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON));
 
+Controller.enableMapping("example");
+
 Object.keys(Controller.Standard).forEach(function (input) {
     print("Controller.Standard." + input + ":" + Controller.Standard[input]);
 });
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index d0c40fe3c0..e91e627f16 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -94,6 +94,25 @@ namespace controller {
         Endpoint::Pointer _second;
     };
 
+    class ActionEndpoint : public Endpoint {
+    public:
+        ActionEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input(-1))
+            : Endpoint(id) {
+        }
+
+        virtual float value() override { return _currentValue; }
+        virtual void apply(float newValue, float oldValue, const Pointer& source) override { 
+            
+            _currentValue = newValue;
+            if (!(_id == UserInputMapper::Input::INVALID_INPUT)) {
+                auto userInputMapper = DependencyManager::get<UserInputMapper>();
+                userInputMapper->setActionState(UserInputMapper::Action(_id.getChannel()), newValue);
+            }
+        }
+
+    private:
+        float _currentValue{ 0.0f };
+    };
 
     QRegularExpression ScriptingInterface::SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" };
 
@@ -139,7 +158,8 @@ namespace controller {
 
             // Create the endpoints
             // FIXME action endpoints need to accumulate values, and have them cleared at each frame
-            _endpoints[actionInput] = std::make_shared<VirtualEndpoint>();
+           // _endpoints[actionInput] = std::make_shared<VirtualEndpoint>();
+            _endpoints[actionInput] = std::make_shared<ActionEndpoint>();
         }
 
         updateMaps();
@@ -171,6 +191,7 @@ namespace controller {
 
                 _mappingsByName[mapping->_name] = mapping;
 
+                return mappingBuilder;
             } else {
                 qDebug() << "Mapping json Document is not an object" << endl;
             }
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index c795442296..117fd163bf 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -214,6 +214,8 @@ public:
     QVector<QString> getActionNames() const;
     void assignDefaulActionScales();
 
+    void setActionState(Action action, float value) { _actionStates[action] = value; }
+
     // Add input channel to the mapper and check that all the used channels are registered.
     // Return true if theinput channel is created correctly, false either
     bool addInputChannel(Action action, const Input& input, float scale = 1.0f);

From f25cc93936229efc139bd4e5b318cb22643353b5 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Fri, 16 Oct 2015 10:48:36 -0700
Subject: [PATCH 041/301] Initial prototype of exposing anim vars to
 javascript.

---
 interface/src/avatar/MyAvatar.h            | 12 +++
 libraries/animation/src/AnimVariant.h      |  6 ++
 libraries/animation/src/AnimVariantMap.cpp | 91 ++++++++++++++++++++++
 libraries/animation/src/Rig.cpp            | 14 ++++
 libraries/animation/src/Rig.h              |  6 ++
 5 files changed, 129 insertions(+)
 create mode 100644 libraries/animation/src/AnimVariantMap.cpp

diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 02c9f53082..372c0848bb 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -106,6 +106,18 @@ public:
     Q_INVOKABLE AnimationDetails getAnimationDetailsByRole(const QString& role);
     Q_INVOKABLE AnimationDetails getAnimationDetails(const QString& url);
     void clearJointAnimationPriorities();
+    // Adds handler(animStateDictionaryIn) => animStateDictionaryOut, which will be invoked just before each animGraph state update.
+    // The handler will be called with an animStateDictionaryIn that has all those properties specified by the (possibly empty)
+    // propertiesList argument. However for debugging, if the properties argument is null, all internal animGraph state is provided.
+    // The animStateDictionaryOut can be a different object than animStateDictionaryIn. Any properties set in animStateDictionaryOut
+    // will override those of the internal animation machinery.
+    // The animStateDictionaryIn may be shared among multiple handlers, and thus may contain additional properties specified when
+    // adding one of the other handlers. While any handler may change a value in animStateDictionaryIn (or supply different values in animStateDictionaryOut)
+    // a handler must not remove properties from animStateDictionaryIn, nor change property values that it does not intend to change.
+    // It is not specified in what order multiple handlers are called.
+    Q_INVOKABLE void addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { _rig->addAnimationStateHandler(handler, propertiesList); }
+    // Removes a handler previously added by addAnimationStateHandler.
+    Q_INVOKABLE void removeAnimationStateHandler(QScriptValue handler) { _rig->removeAnimationStateHandler(handler); }
 
     // get/set avatar data
     void saveData();
diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h
index cb886cd369..b30a04e6bd 100644
--- a/libraries/animation/src/AnimVariant.h
+++ b/libraries/animation/src/AnimVariant.h
@@ -16,6 +16,7 @@
 #include <glm/gtx/quaternion.hpp>
 #include <map>
 #include <set>
+#include <QScriptValue>
 #include "AnimationLogging.h"
 
 class AnimVariant {
@@ -158,6 +159,11 @@ public:
 
     bool hasKey(const QString& key) const { return _map.find(key) != _map.end(); }
 
+    // Answer a Plain Old Javascript Object (for the given engine) all of our values set as properties.
+    QScriptValue animVariantMapToScriptValue(QScriptEngine* engine);
+    // Side-effect us with the value of object's own properties. (No inherited properties.)
+    void animVariantMapFromScriptValue(const QScriptValue& object);
+
 #ifdef NDEBUG
     void dump() const {
         qCDebug(animation) << "AnimVariantMap =";
diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
new file mode 100644
index 0000000000..f626e46c0f
--- /dev/null
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -0,0 +1,91 @@
+//
+//  AnimVariantMap.cpp
+//  library/animation
+//
+//  Created by Howard Stearns on 10/15/15.
+//  Copyright (c) 2015 High Fidelity, Inc. All rights reserved.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <QScriptEngine>
+#include <QScriptValueIterator>
+#include <RegisteredMetaTypes.h>
+#include "AnimVariant.h"
+
+QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine) {
+    QScriptValue target = engine->newObject();
+    for (auto& pair : _map) {
+        switch (pair.second.getType()) {
+            case AnimVariant::Type::Bool:
+                target.setProperty(pair.first, pair.second.getBool());
+                break;
+            case AnimVariant::Type::Int:
+                target.setProperty(pair.first, pair.second.getInt());
+                break;
+            case AnimVariant::Type::Float:
+                target.setProperty(pair.first, pair.second.getFloat());
+                break;
+            case AnimVariant::Type::String:
+                target.setProperty(pair.first, pair.second.getString());
+                break;
+            case AnimVariant::Type::Vec3:
+                target.setProperty(pair.first, vec3toScriptValue(engine, pair.second.getVec3()));
+                break;
+            case AnimVariant::Type::Quat:
+                target.setProperty(pair.first, quatToScriptValue(engine, pair.second.getQuat()));
+                break;
+            default:
+                // Note that we don't do mat4 in Javascript currently, and there's not yet a reason to start now.
+                assert("AnimVariant::Type" == "valid");
+        }
+    }
+    return target;
+}
+void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) {
+    // POTENTIAL OPTIMIZATION: cache the types we've seen. I.e, keep a dictionary mapping property names to an enumeration of types.
+    // Whenever we identify a new outbound type in animVariantMapToScriptValue above, or a new inbound type in the code that follows here,
+    // we would enter it into the dictionary. Then switch on that type here, with the code that follow being executed only if
+    // the type is not known. One problem with that is that there is no checking that two different script use the same name differently.
+    QScriptValueIterator property(source);
+    // Note: QScriptValueIterator iterates only over source's own properties. It does not follow the prototype chain.
+    while (property.hasNext()) {
+        property.next();
+        QScriptValue value = property.value();
+        if (value.isBool()) {
+            set(property.name(), value.toBool());
+            continue;
+        } else if (value.isString()) {
+            set(property.name(), value.toString());
+            continue;
+        } else if (value.isNumber()) {
+            int asInteger = value.toInt32();
+            float asFloat = value.toNumber();
+            if (asInteger == asFloat) {
+                set(property.name(), asInteger);
+            } else {
+                set(property.name(), asFloat);
+            }
+            continue;
+        } else if (value.isObject()) {
+            QScriptValue x = value.property("x");
+            if (x.isNumber()) {
+                QScriptValue y = value.property("y");
+                if (y.isNumber()) {
+                    QScriptValue z = value.property("z");
+                    if (z.isNumber()) {
+                        QScriptValue w = value.property("w");
+                        if (w.isNumber()) {
+                            set(property.name(), glm::quat(x.toNumber(), y.toNumber(), z.toNumber(), w.toNumber()));
+                        } else {
+                            set(property.name(), glm::vec3(x.toNumber(), y.toNumber(), z.toNumber()));
+                        }
+                        continue;
+                    }
+                }
+            }
+        }
+        qCWarning(animation) << "Ignoring unrecognized data" << value.toString() << "for animation property" << property.name();
+     }
+}
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 340c09060a..bf5edb6300 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -566,6 +566,20 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
             return;
         }
 
+        if (_stateHandlers.isValid()) {
+            // TODO: iterate multiple handlers, but with one shared arg.
+            // TODO: fill the properties based on the union of requested properties. (Keep all properties objs and compute new union when add/remove handler.)
+            // TODO: check QScriptEngine::hasUncaughtException()
+            // TODO: call asynchronously (through a signal on script), so that each script is single threaded, and so we never block here.
+            //       This will require inboundMaps to be kept in the list of per-handler data.
+            QScriptEngine* engine = _stateHandlers.engine();
+            QScriptValue outboundMap = _animVars.animVariantMapToScriptValue(engine);
+            QScriptValueList args;
+            args << outboundMap;
+            QScriptValue inboundMap = _stateHandlers.call(QScriptValue(), args);
+            _animVars.animVariantMapFromScriptValue(inboundMap);
+            //qCDebug(animation) << _animVars.lookup("foo", QString("not set"));
+        }
         // evaluate the animation
         AnimNode::Triggers triggersOut;
         AnimPoseVec poses = _animNode->evaluate(_animVars, deltaTime, triggersOut);
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index 6d9f7b4688..0d74c3b956 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -37,6 +37,7 @@
 #define __hifi__Rig__
 
 #include <QObject>
+#include <QScriptValue>
 
 #include "JointState.h"  // We might want to change this (later) to something that doesn't depend on gpu, fbx and model. -HRS
 
@@ -198,6 +199,8 @@ public:
     AnimNode::ConstPointer getAnimNode() const { return _animNode; }
     AnimSkeleton::ConstPointer getAnimSkeleton() const { return _animSkeleton; }
     bool disableHands {false}; // should go away with rig animation (and Rig::inverseKinematics)
+    void addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { _stateHandlers = handler; }
+    void removeAnimationStateHandler(QScriptValue handler) { _stateHandlers = QScriptValue(); }
 
     bool getModelOffset(glm::vec3& modelOffsetOut) const;
 
@@ -238,6 +241,9 @@ public:
     RigRole _state = RigRole::Idle;
     float _leftHandOverlayAlpha = 0.0f;
     float _rightHandOverlayAlpha = 0.0f;
+
+private:
+    QScriptValue _stateHandlers {};
 };
 
 #endif /* defined(__hifi__Rig__) */

From f0034844e7b5ba938b7234239f2f2683f99fd917 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 16 Oct 2015 12:24:12 -0700
Subject: [PATCH 042/301] Actions working from the Controller layer

---
 examples/controllers/controllerMappings.js    | 39 ++++++++-----------
 interface/src/Application.cpp                 |  2 +-
 .../src/controllers/ScriptingInterface.cpp    |  6 +--
 .../src/controllers/UserInputMapper.cpp       | 23 ++++++-----
 .../src/controllers/UserInputMapper.h         |  6 ++-
 5 files changed, 39 insertions(+), 37 deletions(-)

diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js
index 959dc1b0ca..1007e7bf22 100644
--- a/examples/controllers/controllerMappings.js
+++ b/examples/controllers/controllerMappings.js
@@ -15,32 +15,26 @@
 myFirstMapping = function() {
 return {
     "name": "example",
-    "channels": [ {
-            "from": "Keyboard.A",
-            "filters": [ {
-                    "type": "clamp",
-                    "params": [0, 1],
-                }
-            ],
-            "to": "Actions.LONGITUDINAL_FORWARD",
-        }, {
-            "from": "Keyboard.Left",
-            "filters": [ {
-                    "type": "clamp",
-                    "params": [0, 1],
-                }, {
-                    "type": "invert"
-                }
-            ],
-            "to": "Actions.LONGITUDINAL_BACKWARD",
-        }, {
-            "from": "Keyboard.C",
+    "channels": [
+        { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
+        { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
+
+        { "from": "Keyboard.Left", "to": "Actions.LATERAL_LEFT" },
+        { "from": "Keyboard.Right", "to": "Actions.LATERAL_RIGHT" },
+
+        { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" },
+        { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" },
+
+        { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" }, 
+        { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
+        {
+            "from": "Standard.LX",
             "filters": [ {
                     "type": "scale",
                     "params": [2.0],
                 }
             ],
-            "to": "Actions.Yaw",
+            "to": "Actions.LATERAL_LEFT",
         }, {
             "from": "Keyboard.B",
             "to": "Actions.Yaw"
@@ -57,7 +51,7 @@ print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
 var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON));
 
 Controller.enableMapping("example");
-
+/*
 Object.keys(Controller.Standard).forEach(function (input) {
     print("Controller.Standard." + input + ":" + Controller.Standard[input]);
 });
@@ -71,3 +65,4 @@ Object.keys(Controller.Hardware).forEach(function (deviceName) {
 Object.keys(Controller.Actions).forEach(function (actionName) {
     print("Controller.Actions." + actionName + ":" + Controller.Actions[actionName]);
 });
+*/
\ No newline at end of file
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 1e0c296e61..c01e89c6d9 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2692,7 +2692,7 @@ void Application::update(float deltaTime) {
     auto myAvatar = getMyAvatar();
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
-    userInputMapper->update(deltaTime);
+  //  userInputMapper->update(deltaTime);
 
     // This needs to go after userInputMapper->update() because of the keyboard
     bool jointsCaptured = false;
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index e91e627f16..a72f24e651 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -103,10 +103,10 @@ namespace controller {
         virtual float value() override { return _currentValue; }
         virtual void apply(float newValue, float oldValue, const Pointer& source) override { 
             
-            _currentValue = newValue;
+            _currentValue += newValue;
             if (!(_id == UserInputMapper::Input::INVALID_INPUT)) {
                 auto userInputMapper = DependencyManager::get<UserInputMapper>();
-                userInputMapper->setActionState(UserInputMapper::Action(_id.getChannel()), newValue);
+                userInputMapper->deltaActionState(UserInputMapper::Action(_id.getChannel()), newValue);
             }
         }
 
@@ -159,7 +159,7 @@ namespace controller {
             // Create the endpoints
             // FIXME action endpoints need to accumulate values, and have them cleared at each frame
            // _endpoints[actionInput] = std::make_shared<VirtualEndpoint>();
-            _endpoints[actionInput] = std::make_shared<ActionEndpoint>();
+            _endpoints[actionInput] = std::make_shared<ActionEndpoint>(actionInput);
         }
 
         updateMaps();
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index b62e2e0e8f..daa7c78640 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -295,7 +295,12 @@ void UserInputMapper::update(float deltaTime) {
     // Scale all the channel step with the scale
     static const float EPSILON =  0.01f;
     for (auto i = 0; i < NUM_ACTIONS; i++) {
+        if (_externalActionStates[i] != 0) {
+            _actionStates[i] += _externalActionStates[i];
+            _externalActionStates[i] = 0.0f;
+        }
         _actionStates[i] *= _actionScales[i];
+
         // Emit only on change, and emit when moving back to 0
         if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
             _lastActionStates[i] = _actionStates[i];
@@ -359,15 +364,15 @@ void UserInputMapper::assignDefaulActionScales() {
     _actionScales[RIGHT_HAND] = 1.0f; // default
     _actionScales[LEFT_HAND_CLICK] = 1.0f; // on
     _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
-    _actionStates[SHIFT] = 1.0f; // on
-    _actionStates[ACTION1] = 1.0f; // default
-    _actionStates[ACTION2] = 1.0f; // default
-    _actionStates[TRANSLATE_X] = 1.0f; // default
-    _actionStates[TRANSLATE_Y] = 1.0f; // default
-    _actionStates[TRANSLATE_Z] = 1.0f; // default
-    _actionStates[ROLL] = 1.0f; // default
-    _actionStates[PITCH] = 1.0f; // default
-    _actionStates[YAW] = 1.0f; // default
+    _actionScales[SHIFT] = 1.0f; // on
+    _actionScales[ACTION1] = 1.0f; // default
+    _actionScales[ACTION2] = 1.0f; // default
+    _actionScales[TRANSLATE_X] = 1.0f; // default
+    _actionScales[TRANSLATE_Y] = 1.0f; // default
+    _actionScales[TRANSLATE_Z] = 1.0f; // default
+    _actionScales[ROLL] = 1.0f; // default
+    _actionScales[PITCH] = 1.0f; // default
+    _actionScales[YAW] = 1.0f; // default
 }
 
 // This is only necessary as long as the actions are hardcoded
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 117fd163bf..7e0832b55a 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -138,7 +138,7 @@ public:
     uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
 
     bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device);
-    bool registerStandardDevice(const DeviceProxy::Pointer& device) { _standardDevice = device; return true; }
+    bool registerStandardDevice(const DeviceProxy::Pointer& device) { _standardDevice = device; _registeredDevices[getStandardDeviceID()] = device; return true; }
     DeviceProxy::Pointer getDeviceProxy(const Input& input);
     QString getDeviceName(uint16 deviceID);
     QVector<InputPair> getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); }
@@ -214,7 +214,8 @@ public:
     QVector<QString> getActionNames() const;
     void assignDefaulActionScales();
 
-    void setActionState(Action action, float value) { _actionStates[action] = value; }
+    void setActionState(Action action, float value) { _externalActionStates[action] = value; }
+    void deltaActionState(Action action, float delta) { _externalActionStates[action] += delta; }
 
     // Add input channel to the mapper and check that all the used channels are registered.
     // Return true if theinput channel is created correctly, false either
@@ -297,6 +298,7 @@ protected:
     ActionToInputsMap _actionToInputsMap;
  
     std::vector<float> _actionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
+    std::vector<float> _externalActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
     std::vector<float> _actionScales = std::vector<float>(NUM_ACTIONS, 1.0f);
     std::vector<float> _lastActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
     std::vector<PoseValue> _poseStates = std::vector<PoseValue>(NUM_ACTIONS);

From 0fc04ab2972083df9daabe4fae6b14b0c01c2464 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 16 Oct 2015 14:45:38 -0700
Subject: [PATCH 043/301] Fixing the review comments and setting the
 StandardDevice of USerINputMapper in the registeredDevices just like any
 other, only the ID is special

---
 .../src/controllers/ScriptingInterface.cpp         | 14 ++++++--------
 .../src/controllers/UserInputMapper.cpp            | 12 ++++++++----
 .../controllers/src/controllers/UserInputMapper.h  | 11 +++++------
 3 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index a72f24e651..abb9544892 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -26,7 +26,7 @@ namespace controller {
 
     class VirtualEndpoint : public Endpoint {
     public:
-        VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input(-1))
+        VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT)
             : Endpoint(id) {
         }
 
@@ -41,7 +41,7 @@ namespace controller {
     class JSEndpoint : public Endpoint {
     public:
         JSEndpoint(const QJSValue& callable) 
-            : Endpoint(UserInputMapper::Input(-1)), _callable(callable) {}
+            : Endpoint(UserInputMapper::Input::INVALID_INPUT), _callable(callable) {}
 
         virtual float value() {
             float result = (float)_callable.call().toNumber();;
@@ -59,7 +59,7 @@ namespace controller {
     class ScriptEndpoint : public Endpoint {
     public:
         ScriptEndpoint(const QScriptValue& callable)
-            : Endpoint(UserInputMapper::Input(-1)), _callable(callable) {
+            : Endpoint(UserInputMapper::Input::INVALID_INPUT), _callable(callable) {
         }
 
         virtual float value() {
@@ -78,7 +78,7 @@ namespace controller {
     class CompositeEndpoint : public Endpoint, Endpoint::Pair {
     public:
         CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
-            : Endpoint(UserInputMapper::Input(-1)), Pair(first, second) { }
+            : Endpoint(UserInputMapper::Input(UserInputMapper::Input::INVALID_INPUT)), Pair(first, second) { }
 
         virtual float value() {
             float result = first->value() * -1.0 + second->value();
@@ -96,7 +96,7 @@ namespace controller {
 
     class ActionEndpoint : public Endpoint {
     public:
-        ActionEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input(-1))
+        ActionEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT)
             : Endpoint(id) {
         }
 
@@ -156,9 +156,7 @@ namespace controller {
             QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
             _actions.insert(cleanActionName, actionInput.getID());
 
-            // Create the endpoints
-            // FIXME action endpoints need to accumulate values, and have them cleared at each frame
-           // _endpoints[actionInput] = std::make_shared<VirtualEndpoint>();
+            // Create the action endpoints
             _endpoints[actionInput] = std::make_shared<ActionEndpoint>(actionInput);
         }
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index daa7c78640..0d0ae7d85f 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -19,6 +19,7 @@ const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice(
 const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
 const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
 const uint16_t UserInputMapper::Input::ACTIONS_DEVICE = INVALID_DEVICE - (uint16)1;
+const uint16_t UserInputMapper::Input::STANDARD_DEVICE = 0;
 
 // Default contruct allocate the poutput size with the current hardcoded action channels
 UserInputMapper::UserInputMapper() {
@@ -38,6 +39,13 @@ bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer
     return true;
 }
 
+bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) {
+    device->_name = "Standard"; // Just to make sure
+    _registeredDevices[getStandardDeviceID()] = device;
+    return true;
+}
+
+
 UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
     auto device = _registeredDevices.find(input.getDevice());
     if (device != _registeredDevices.end()) {
@@ -69,10 +77,6 @@ void UserInputMapper::resetDevice(uint16 deviceID) {
 }
 
 int UserInputMapper::findDevice(QString name) const {
-    if (_standardDevice && (_standardDevice->getName() == name)) {
-        return getStandardDeviceID();
-    }
-
     for (auto device : _registeredDevices) {
         if (device.second->_name.split(" (")[0] == name) {
             return device.first;
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 7e0832b55a..8b466d79c9 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -86,6 +86,7 @@ public:
         static const uint16 INVALID_CHANNEL;
         static const uint16 INVALID_TYPE;
         static const uint16 ACTIONS_DEVICE;
+        static const uint16 STANDARD_DEVICE;
     };
 
 
@@ -138,7 +139,7 @@ public:
     uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
 
     bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device);
-    bool registerStandardDevice(const DeviceProxy::Pointer& device) { _standardDevice = device; _registeredDevices[getStandardDeviceID()] = device; return true; }
+    bool registerStandardDevice(const DeviceProxy::Pointer& device);
     DeviceProxy::Pointer getDeviceProxy(const Input& input);
     QString getDeviceName(uint16 deviceID);
     QVector<InputPair> getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); }
@@ -275,8 +276,8 @@ public:
     typedef std::map<int, DeviceProxy::Pointer> DevicesMap;
     DevicesMap getDevices() { return _registeredDevices; }
 
-    uint16 getStandardDeviceID() const { return _standardDeviceID; }
-    DeviceProxy::Pointer getStandardDevice() { return _standardDevice; }
+    uint16 getStandardDeviceID() const { return Input::STANDARD_DEVICE; }
+    DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
 
 signals:
     void actionEvent(int action, float state);
@@ -284,12 +285,10 @@ signals:
 
 protected:
     void registerStandardDevice();
-    uint16 _standardDeviceID = 0;
-    DeviceProxy::Pointer _standardDevice;
     StandardControllerPointer _standardController;
         
     DevicesMap _registeredDevices;
-    uint16 _nextFreeDeviceID = 1;
+    uint16 _nextFreeDeviceID = Input::STANDARD_DEVICE + 1;
 
     typedef std::map<int, Modifiers> InputToMoModifiersMap;
     InputToMoModifiersMap _inputToModifiersMap;

From 770282ad8849afdf0b5e7f87acaf89ce1f5ae54d Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Fri, 16 Oct 2015 15:22:43 -0700
Subject: [PATCH 044/301] Javascript methods to getAvatars listing and
 getAvatar from id.

---
 interface/src/avatar/AvatarManager.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h
index 277e931419..50e585d72c 100644
--- a/interface/src/avatar/AvatarManager.h
+++ b/interface/src/avatar/AvatarManager.h
@@ -51,6 +51,10 @@ public:
     
     Q_INVOKABLE void setLocalLights(const QVector<AvatarManager::LocalLight>& localLights);
     Q_INVOKABLE QVector<AvatarManager::LocalLight> getLocalLights() const;
+    // Currently, your own avatar will be included as the null avatar id.
+    Q_INVOKABLE QVector<QUuid> getAvatars() const { return _avatarHash.keys().toVector(); }
+    // Minor Bug: A bogus avatarID answers your own avatar.
+    Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID) const { return _avatarHash[avatarID].get(); }
 
     void getObjectsToDelete(VectorOfMotionStates& motionStates);
     void getObjectsToAdd(VectorOfMotionStates& motionStates);

From 6d3d29b6b7707d4d5de7ffff70285b58903866a3 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 16 Oct 2015 15:24:44 -0700
Subject: [PATCH 045/301] Adding a new mapping

---
 examples/controllers/controllerMappings.js | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js
index 1007e7bf22..c39ece4bc1 100644
--- a/examples/controllers/controllerMappings.js
+++ b/examples/controllers/controllerMappings.js
@@ -43,6 +43,15 @@ return {
 }
 }
 
+mySecondMapping = function() {
+return {
+    "name": "example2",
+    "channels": [
+        { "from": "Standard.LY", "to": "Actions.TRANSLATE_Z" },
+        { "from": "Standard.LX", "to": "Actions.YAW" },
+    ]
+}
+}
 
 //Script.include('mapping-test0.json');
 var myFirstMappingJSON = myFirstMapping();
@@ -51,6 +60,14 @@ print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
 var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON));
 
 Controller.enableMapping("example");
+
+var myFirstMappingJSON = myFirstMapping();
+print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
+
+var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON));
+
+Controller.enableMapping("example");
+
 /*
 Object.keys(Controller.Standard).forEach(function (input) {
     print("Controller.Standard." + input + ":" + Controller.Standard[input]);

From 38a967ac5493ba53940f8b768a0808d22f77b0f2 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Fri, 16 Oct 2015 16:28:11 -0700
Subject: [PATCH 046/301] Allow compiler after someone broke things.

---
 libraries/animation/src/AnimVariant.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h
index b30a04e6bd..0a91c82d80 100644
--- a/libraries/animation/src/AnimVariant.h
+++ b/libraries/animation/src/AnimVariant.h
@@ -18,6 +18,7 @@
 #include <set>
 #include <QScriptValue>
 #include "AnimationLogging.h"
+#include "StreamUtils.h"
 
 class AnimVariant {
 public:

From 1dcf03d61e7627f17389eeba635920693a79e248 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 16 Oct 2015 17:15:46 -0700
Subject: [PATCH 047/301] Put standard 'makeinput' functions on the base class

---
 .../src/controllers/InputDevice.cpp           | 25 +++++++++++++++++++
 .../controllers/src/controllers/InputDevice.h | 10 +++++++-
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/libraries/controllers/src/controllers/InputDevice.cpp b/libraries/controllers/src/controllers/InputDevice.cpp
index 351d5b6d1d..4b2376d32a 100644
--- a/libraries/controllers/src/controllers/InputDevice.cpp
+++ b/libraries/controllers/src/controllers/InputDevice.cpp
@@ -57,3 +57,28 @@ UserInputMapper::PoseValue InputDevice::getPose(int channel) const {
         return UserInputMapper::PoseValue();
     }
 }
+
+UserInputMapper::Input InputDevice::makeInput(controller::StandardButtonChannel button) {
+    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
+}
+
+UserInputMapper::Input InputDevice::makeInput(controller::StandardAxisChannel axis) {
+    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
+}
+
+UserInputMapper::Input InputDevice::makeInput(controller::StandardPoseChannel pose) {
+    return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
+}
+
+UserInputMapper::InputPair InputDevice::makePair(controller::StandardButtonChannel button, const QString& name) {
+    return UserInputMapper::InputPair(makeInput(button), name);
+}
+
+UserInputMapper::InputPair InputDevice::makePair(controller::StandardAxisChannel axis, const QString& name) {
+    return UserInputMapper::InputPair(makeInput(axis), name);
+}
+
+UserInputMapper::InputPair InputDevice::makePair(controller::StandardPoseChannel pose, const QString& name) {
+    return UserInputMapper::InputPair(makeInput(pose), name);
+}
+
diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h
index 4dbb141832..66f7addc58 100644
--- a/libraries/controllers/src/controllers/InputDevice.h
+++ b/libraries/controllers/src/controllers/InputDevice.h
@@ -11,6 +11,7 @@
 #pragma once
 
 #include "UserInputMapper.h"
+#include "StandardControls.h"
 
 // Event types for each controller
 const unsigned int CONTROLLER_0_EVENT = 1500U;
@@ -33,7 +34,7 @@ public:
     UserInputMapper::PoseValue getPose(int channel) const;
 
     virtual void registerToUserInputMapper(UserInputMapper& mapper) = 0;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) = 0;
+    virtual void assignDefaultInputMapping(UserInputMapper& mapper) {};
 
     // Update call MUST be called once per simulation loop
     // It takes care of updating the action states and deltas
@@ -49,10 +50,17 @@ public:
 
     static bool getLowVelocityFilter() { return _lowVelocityFilter; };
 
+    UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
+    UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
+    UserInputMapper::Input makeInput(controller::StandardPoseChannel pose);
+    UserInputMapper::InputPair makePair(controller::StandardButtonChannel button, const QString& name);
+    UserInputMapper::InputPair makePair(controller::StandardAxisChannel button, const QString& name);
+    UserInputMapper::InputPair makePair(controller::StandardPoseChannel button, const QString& name);
 public slots:
     static void setLowVelocityFilter(bool newLowVelocityFilter) { _lowVelocityFilter = newLowVelocityFilter; };
 
 protected:
+
     int _deviceID = 0;
 
     QString _name;

From db0fa6b8edfdd9571f68b21a3a176d0f76627ad7 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 16 Oct 2015 17:18:15 -0700
Subject: [PATCH 048/301] Update hydra mappings and test code

---
 examples/tests/controllerInterfaceTest.js     |  30 +++
 interface/resources/controllers/hydra.json    |  28 +++
 interface/resources/controllers/xbox.json     |  29 +++
 .../src/input-plugins/Joystick.cpp            |  19 --
 .../src/input-plugins/Joystick.h              |   4 -
 .../src/input-plugins/SixenseManager.cpp      | 176 +++++-------------
 .../src/input-plugins/SixenseManager.h        |  25 +--
 tests/controllers/qml/Hydra.qml               |  35 ++++
 tests/controllers/qml/Xbox.qml                |  16 +-
 tests/controllers/qml/content.qml             |  33 ++--
 .../controllers/qml/controls/AnalogStick.qml  |   5 +
 tests/controllers/qml/hydra/HydraButtons.qml  |  18 ++
 tests/controllers/qml/hydra/HydraStick.qml    |  91 +++++++++
 tests/controllers/qml/hydra/hydra.png         | Bin 0 -> 21273 bytes
 tests/controllers/src/main.cpp                |  12 +-
 15 files changed, 321 insertions(+), 200 deletions(-)
 create mode 100644 examples/tests/controllerInterfaceTest.js
 create mode 100644 interface/resources/controllers/hydra.json
 create mode 100644 interface/resources/controllers/xbox.json
 create mode 100644 tests/controllers/qml/Hydra.qml
 create mode 100644 tests/controllers/qml/hydra/HydraButtons.qml
 create mode 100644 tests/controllers/qml/hydra/HydraStick.qml
 create mode 100644 tests/controllers/qml/hydra/hydra.png

diff --git a/examples/tests/controllerInterfaceTest.js b/examples/tests/controllerInterfaceTest.js
new file mode 100644
index 0000000000..fa8cf48b9b
--- /dev/null
+++ b/examples/tests/controllerInterfaceTest.js
@@ -0,0 +1,30 @@
+ControllerTest = function() {
+
+    print("Actions");
+    for (var prop in Controller.Actions) {
+        print("\t" + prop);
+    }
+    print("Standard");
+    for (var prop in Controller.Standard) {
+        print("\t" + prop);
+    }
+    print("Hardware");
+    for (var prop in Controller.Hardware) {
+        print("\t" + prop);
+        for (var prop2 in Controller.Hardware[prop]) {
+            print("\t\t" + prop2);
+        }
+    }
+    print("Done");
+
+    var that = this;
+    Script.scriptEnding.connect(function() {
+        that.onCleanup();
+    });
+}
+
+ControllerTest.prototype.onCleanup = function() {
+}
+
+
+new ControllerTest();
\ No newline at end of file
diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json
new file mode 100644
index 0000000000..25c8db61cb
--- /dev/null
+++ b/interface/resources/controllers/hydra.json
@@ -0,0 +1,28 @@
+{
+    "name": "Hydra to Standard",
+    "channels": [
+        { "from": "Hydra.LY", "to": "Standard.LY" }, 
+        { "from": "Hydra.LX", "to": "Standard.LX" },
+        { "from": "Hydra.LT", "to": "Standard.LT" }, 
+        { "from": "Hydra.RY", "to": "Standard.RY" }, 
+        { "from": "Hydra.RX", "to": "Standard.RX" },
+        { "from": "Hydra.RT", "to": "Standard.RT" }, 
+
+        { "from": "Hydra.LB", "to": "Standard.LB" }, 
+        { "from": "Hydra.LS", "to": "Standard.LS" },
+        { "from": "Hydra.RB", "to": "Standard.RB" }, 
+        { "from": "Hydra.RS", "to": "Standard.RS" },
+
+        { "from": "Hydra.L0", "to": "Standard.Back" }, 
+        { "from": "Hydra.L1", "to": "Standard.DL" },
+        { "from": "Hydra.L2", "to": "Standard.DD" }, 
+        { "from": "Hydra.L3", "to": "Standard.DR" }, 
+        { "from": "Hydra.L4", "to": "Standard.DU" },
+
+        { "from": "Hydra.R0", "to": "Standard.Start" }, 
+        { "from": "Hydra.R1", "to": "Standard.X" },
+        { "from": "Hydra.R2", "to": "Standard.A" }, 
+        { "from": "Hydra.R3", "to": "Standard.B" }, 
+        { "from": "Hydra.R4", "to": "Standard.Y" }
+    ]
+}
diff --git a/interface/resources/controllers/xbox.json b/interface/resources/controllers/xbox.json
new file mode 100644
index 0000000000..bf96320707
--- /dev/null
+++ b/interface/resources/controllers/xbox.json
@@ -0,0 +1,29 @@
+{
+    "name": "XBox to Standard",
+    "channels": [
+        { "from": "XBox.LY", "to": "Standard.LY" }, 
+        { "from": "XBox.LX", "to": "Standard.LX" },
+        { "from": "XBox.LT", "to": "Standard.LT" }, 
+        { "from": "XBox.LB", "to": "Standard.LB" }, 
+        { "from": "XBox.LS", "to": "Standard.LS" },
+
+        { "from": "XBox.RY", "to": "Standard.RY" }, 
+        { "from": "XBox.RX", "to": "Standard.RX" },
+        { "from": "XBox.RT", "to": "Standard.RT" }, 
+        { "from": "XBox.RB", "to": "Standard.RB" }, 
+        { "from": "XBox.RS", "to": "Standard.RS" },
+
+        { "from": "XBox.Back", "to": "Standard.Back" }, 
+        { "from": "XBox.Start", "to": "Standard.Start" }, 
+        
+        { "from": "XBox.DU", "to": "Standard.DU" },
+        { "from": "XBox.DD", "to": "Standard.DD" }, 
+        { "from": "XBox.DL", "to": "Standard.DL" },
+        { "from": "XBox.DR", "to": "Standard.DR" }, 
+
+        { "from": "XBox.A", "to": "Standard.A" }, 
+        { "from": "XBox.B", "to": "Standard.B" }, 
+        { "from": "XBox.X", "to": "Standard.X" },
+        { "from": "XBox.Y", "to": "Standard.Y" }
+    ]
+}
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index e7a0124deb..aa5bbbba07 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -143,22 +143,3 @@ void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
     mapper.registerDevice(_deviceID, proxy);
 }
 
-void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
-#ifdef HAVE_SDL2
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    const float DPAD_MOVE_SPEED = 0.5f;
-    const float JOYSTICK_YAW_SPEED = 0.5f;
-    const float JOYSTICK_PITCH_SPEED = 0.25f;
-    const float BOOM_SPEED = 0.1f;
-
-#endif
-}
-
-UserInputMapper::Input Joystick::makeInput(controller::StandardButtonChannel button) {
-    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
-}
-
-UserInputMapper::Input Joystick::makeInput(controller::StandardAxisChannel axis) {
-    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
-}
-
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h
index c6537acafe..8e4cdb365f 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.h
+++ b/libraries/input-plugins/src/input-plugins/Joystick.h
@@ -37,16 +37,12 @@ public:
 
     // Device functions
     virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
     
     Joystick() : InputDevice("Joystick") {}
     ~Joystick();
     
-    UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
-    UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
-    
 #ifdef HAVE_SDL2
     Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
 #endif
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index a99e04ff13..9d3d06ecb7 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -123,6 +123,8 @@ void SixenseManager::activate() {
     loadSettings();
     sixenseInit();
     _activated = true;
+    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    registerToUserInputMapper(*userInputMapper);
 #endif
 }
 
@@ -176,23 +178,13 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
 
     if (sixenseGetNumActiveControllers() == 0) {
-        if (_hydrasConnected) {
-            qCDebug(inputplugins, "hydra disconnected");
-        }
-        _hydrasConnected = false;
-        if (_deviceID != 0) {
-            userInputMapper->removeDevice(_deviceID);
-            _deviceID = 0;
-            _poseStateMap.clear();
-        }
+        _poseStateMap.clear();
         return;
     }
 
     PerformanceTimer perfTimer("sixense");
     if (!_hydrasConnected) {
         _hydrasConnected = true;
-        registerToUserInputMapper(*userInputMapper);
-        assignDefaultInputMapping(*userInputMapper);
         UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
     }
 
@@ -226,12 +218,15 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
         // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters.
         glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]);
         position *= METERS_PER_MILLIMETER;
-
+        bool left = i == 0;
+        using namespace controller;
         // Check to see if this hand/controller is on the base
         const float CONTROLLER_AT_BASE_DISTANCE = 0.075f;
         if (glm::length(position) >= CONTROLLER_AT_BASE_DISTANCE) {
-            handleButtonEvent(data->buttons, numActiveControllers - 1);
-            handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1);
+            handleButtonEvent(data->buttons, left);
+            _axisStateMap[left ? LX : RX] = data->joystick_x;
+            _axisStateMap[left ? LY : RY] = data->joystick_y;
+            _axisStateMap[left ? LT : RT] = data->trigger;
 
             if (!jointsCaptured) {
                 //  Rotation of Palm
@@ -241,13 +236,8 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
                 _poseStateMap.clear();
             }
         } else {
-            _poseStateMap[(numActiveControllers - 1) == 0 ? LEFT_HAND : RIGHT_HAND] = UserInputMapper::PoseValue();
+            _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = UserInputMapper::PoseValue();
         }
-
-//            //  Read controller buttons and joystick into the hand
-//            palm->setControllerButtons(data->buttons);
-//            palm->setTrigger(data->trigger);
-//            palm->setJoystick(data->joystick_x, data->joystick_y);
     }
 
     if (numActiveControllers == 2) {
@@ -367,39 +357,35 @@ void SixenseManager::focusOutEvent() {
     _buttonPressedMap.clear();
 };
 
-void SixenseManager::handleAxisEvent(float stickX, float stickY, float trigger, int index) {
-    _axisStateMap[makeInput(AXIS_Y_POS, index).getChannel()] = (stickY > 0.0f) ? stickY : 0.0f;
-    _axisStateMap[makeInput(AXIS_Y_NEG, index).getChannel()] = (stickY < 0.0f) ? -stickY : 0.0f;
-    _axisStateMap[makeInput(AXIS_X_POS, index).getChannel()] = (stickX > 0.0f) ? stickX : 0.0f;
-    _axisStateMap[makeInput(AXIS_X_NEG, index).getChannel()] = (stickX < 0.0f) ? -stickX : 0.0f;
-    _axisStateMap[makeInput(BACK_TRIGGER, index).getChannel()] = trigger;
+void SixenseManager::handleAxisEvent(float stickX, float stickY, float trigger, bool left) {
 }
 
-void SixenseManager::handleButtonEvent(unsigned int buttons, int index) {
+void SixenseManager::handleButtonEvent(unsigned int buttons, bool left) {
+    using namespace controller;
     if (buttons & BUTTON_0) {
-        _buttonPressedMap.insert(makeInput(BUTTON_0, index).getChannel());
+        _buttonPressedMap.insert(left ? BACK : START);
     }
     if (buttons & BUTTON_1) {
-        _buttonPressedMap.insert(makeInput(BUTTON_1, index).getChannel());
+        _buttonPressedMap.insert(left ? DL : X);
     }
     if (buttons & BUTTON_2) {
-        _buttonPressedMap.insert(makeInput(BUTTON_2, index).getChannel());
+        _buttonPressedMap.insert(left ? DD : A);
     }
     if (buttons & BUTTON_3) {
-        _buttonPressedMap.insert(makeInput(BUTTON_3, index).getChannel());
+        _buttonPressedMap.insert(left ? DR : B);
     }
     if (buttons & BUTTON_4) {
-        _buttonPressedMap.insert(makeInput(BUTTON_4, index).getChannel());
+        _buttonPressedMap.insert(left ? DU : Y);
     }
     if (buttons & BUTTON_FWD) {
-        _buttonPressedMap.insert(makeInput(BUTTON_FWD, index).getChannel());
+        _buttonPressedMap.insert(left ? LB : RB);
     }
     if (buttons & BUTTON_TRIGGER) {
-        _buttonPressedMap.insert(makeInput(BUTTON_TRIGGER, index).getChannel());
+        _buttonPressedMap.insert(left ? LS : RS);
     }
 }
 
-void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int index) {
+void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, bool left) {
 #ifdef HAVE_SIXENSE
     // From ABOVE the sixense coordinate frame looks like this:
     //
@@ -443,7 +429,7 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int
     // In addition to Qsh each hand has pre-offset introduced by the shape of the sixense controllers
     // and how they fit into the hand in their relaxed state.  This offset is a quarter turn about
     // the sixense's z-axis, with its direction different for the two hands:
-    float sign = (index == 0) ? 1.0f : -1.0f;
+    float sign = left ? 1.0f : -1.0f;
     const glm::quat preOffset = glm::angleAxis(sign * PI / 2.0f, Vectors::UNIT_Z);
 
     // Finally, there is a post-offset (same for both hands) to get the hand's rest orientation
@@ -458,104 +444,46 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int
     // TODO: find a shortcut with fewer rotations.
     rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand;
 
-    _poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation);
+    _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = 
+        UserInputMapper::PoseValue(position, rotation);
 #endif // HAVE_SIXENSE
 }
 
 void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) {
     // Grab the current free device ID
     _deviceID = mapper.getFreeDeviceID();
-
     auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
     proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
     proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
     proxy->getPose = [this](const UserInputMapper::Input& input, int timestamp) -> UserInputMapper::PoseValue { return this->getPose(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
+    using namespace controller;
+    proxy->getAvailabeInputs = [this]() -> QVector<UserInputMapper::InputPair> {
         QVector<UserInputMapper::InputPair> availableInputs;
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_0, 0), "Left Start"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_1, 0), "Left Button 1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_2, 0), "Left Button 2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_3, 0), "Left Button 3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_4, 0), "Left Button 4"));
-
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_FWD, 0), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 0), "L2"));
-
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 0), "Left Stick Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 0), "Left Stick Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 0), "Left Stick Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 0), "Left Stick Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_TRIGGER, 0), "Left Trigger Press"));
-
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_0, 1), "Right Start"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_1, 1), "Right Button 1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_2, 1), "Right Button 2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_3, 1), "Right Button 3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_4, 1), "Right Button 4"));
-
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_FWD, 1), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 1), "R2"));
-
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 1), "Right Stick Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 1), "Right Stick Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 1), "Right Stick Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 1), "Right Stick Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_TRIGGER, 1), "Right Trigger Press"));
-
+        availableInputs.append(UserInputMapper::InputPair(makeInput(BACK), "L0"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(DL), "L1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(DD), "L2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(DR), "L3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(DU), "L4"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(LB), "LB"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(LS), "LS"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(LX), "LX"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(LY), "LY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(LT), "LT"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(START), "R0"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(X), "R1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(A), "R2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(B), "R3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(Y), "R4"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(RB), "RB"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(RS), "RS"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(RX), "RX"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(RY), "RY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(RT), "RT"));
         return availableInputs;
     };
-    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
     mapper.registerDevice(_deviceID, proxy);
 }
 
-void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    const float JOYSTICK_YAW_SPEED = 0.5f;
-    const float JOYSTICK_PITCH_SPEED = 0.25f;
-    const float BUTTON_MOVE_SPEED = 1.0f;
-    const float BOOM_SPEED = 0.1f;
-
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(AXIS_X_POS, 0), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(AXIS_X_NEG, 0), JOYSTICK_MOVE_SPEED);
-
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(AXIS_X_POS, 1), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(AXIS_X_NEG, 1), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(AXIS_Y_POS, 1), JOYSTICK_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(AXIS_Y_NEG, 1), JOYSTICK_PITCH_SPEED);
-
-    // Buttons
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_3, 0), BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_1, 0), BOOM_SPEED);
-
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(BUTTON_3, 1), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(BUTTON_1, 1), BUTTON_MOVE_SPEED);
-
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_2, 0));
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_2, 1));
-
-    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(BUTTON_4, 0));
-    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(BUTTON_4, 1));
-
-    mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
-    mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
-
-    mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0));
-    mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1));
-
-    // TODO find a mechanism to allow users to navigate the context menu via
-    mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(BUTTON_0, 0));
-    mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(BUTTON_0, 1));
-
-}
-
 // virtual
 void SixenseManager::saveSettings() const {
     Settings settings;
@@ -580,15 +508,3 @@ void SixenseManager::loadSettings() {
     }
     settings.endGroup();
 }
-
-UserInputMapper::Input SixenseManager::makeInput(unsigned int button, int index) {
-    return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON);
-}
-
-UserInputMapper::Input SixenseManager::makeInput(SixenseManager::JoystickAxisChannel axis, int index) {
-    return UserInputMapper::Input(_deviceID, axis | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::AXIS);
-}
-
-UserInputMapper::Input SixenseManager::makeInput(JointChannel joint) {
-    return UserInputMapper::Input(_deviceID, joint, UserInputMapper::ChannelType::POSE);
-}
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index 4558f5d268..2e7dd3223d 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -25,6 +25,7 @@
 #endif
 
 #include <controllers/InputDevice.h>
+#include <controllers/StandardControls.h>
 
 #include "InputPlugin.h"
 
@@ -44,19 +45,6 @@ const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
 class SixenseManager : public InputPlugin, public InputDevice {
     Q_OBJECT
 public:
-    enum JoystickAxisChannel {
-        AXIS_Y_POS = 1U << 0,
-        AXIS_Y_NEG = 1U << 3,
-        AXIS_X_POS = 1U << 4,
-        AXIS_X_NEG = 1U << 5,
-        BACK_TRIGGER = 1U << 6,
-    };
-    
-    enum JointChannel {
-        LEFT_HAND = 0,
-        RIGHT_HAND,
-    };
-
     SixenseManager();
     
     // Plugin functions
@@ -73,14 +61,9 @@ public:
 
     // Device functions
     virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
-    UserInputMapper::Input makeInput(unsigned int button, int index);
-    UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index);
-    UserInputMapper::Input makeInput(JointChannel joint);
-
     virtual void saveSettings() const override;
     virtual void loadSettings() override;
 
@@ -88,9 +71,9 @@ public slots:
     void setSixenseFilter(bool filter);
 
 private:    
-    void handleButtonEvent(unsigned int buttons, int index);
-    void handleAxisEvent(float x, float y, float trigger, int index);
-    void handlePoseEvent(glm::vec3 position, glm::quat rotation, int index);
+    void handleButtonEvent(unsigned int buttons, bool left);
+    void handleAxisEvent(float x, float y, float trigger, bool left);
+    void handlePoseEvent(glm::vec3 position, glm::quat rotation, bool left);
 
     void updateCalibration(void* controllers);
     
diff --git a/tests/controllers/qml/Hydra.qml b/tests/controllers/qml/Hydra.qml
new file mode 100644
index 0000000000..5ef47c4d83
--- /dev/null
+++ b/tests/controllers/qml/Hydra.qml
@@ -0,0 +1,35 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "./hydra"
+import "./controls"
+
+Item {
+    id: root
+    width: 480
+    height: width * 3.0 / 4.0
+    property var device
+    property real scale: width / 480
+    property real rightOffset: (width / 2) * scale
+    
+    Image {
+        anchors.fill: parent
+        source: "hydra/hydra.png"
+
+        HydraStick {
+            leftStick: true
+            scale: root.scale
+            device: root.device
+        }
+        
+        
+        HydraStick {
+            leftStick: false
+            scale: root.scale
+            device: root.device
+        }
+
+    }
+}
diff --git a/tests/controllers/qml/Xbox.qml b/tests/controllers/qml/Xbox.qml
index ae66081162..bc9acd5a43 100644
--- a/tests/controllers/qml/Xbox.qml
+++ b/tests/controllers/qml/Xbox.qml
@@ -8,14 +8,20 @@ import "./controls"
 
 Item {
     id: root
-
+    property real aspect: 300.0 / 215.0
+    width: 300
+    height: width / aspect
     property var device
-
-    property real scale: 1.0
-    width: 300 * scale
-    height: 215 * scale
+    property string label: ""
+    property real scale: width / 300.0 
     
     Image {
+        Text {
+            anchors.left: parent.left
+            anchors.top: parent.top
+            text: root.label
+            visible: root.label != ""
+        }
         anchors.fill: parent
         source: "xbox/xbox360-controller-md.png"
 
diff --git a/tests/controllers/qml/content.qml b/tests/controllers/qml/content.qml
index 5f9bbd455e..4beda82df3 100644
--- a/tests/controllers/qml/content.qml
+++ b/tests/controllers/qml/content.qml
@@ -10,16 +10,24 @@ Column {
     id: root
     property var actions: Controllers.Actions
     property var standard: Controllers.Standard
+    property var hydra: null
     property var testMapping: null
     property var xbox: null
 
 
     Component.onCompleted: {
-        var patt = /^X360Controller/;
+        var xboxRegex = /^X360Controller/;
+        var hydraRegex = /^Hydra/;
         for (var prop in Controllers.Hardware) {
-            if(patt.test(prop)) {
+            if(xboxRegex.test(prop)) {
                 root.xbox = Controllers.Hardware[prop]
-                break
+                print("found xbox")
+                continue
+            }
+            if (hydraRegex.test(prop)) {
+                root.hydra = Controllers.Hardware[prop]
+                print("found hydra")
+                continue
             }
         }
     }
@@ -79,23 +87,15 @@ Column {
                 mapping.join(standard.LB, standard.RB).to(actions.Yaw);
                 mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
                 mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
-
                 // mapping.modifier(keyboard.Ctrl).scale(2.0)
-
 //                mapping.from(keyboard.A).to(actions.TranslateLeft)
 //                mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
 //                mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
-
 //                // First loopbacks
 //                // Then non-loopbacks by constraint level (number of inputs)
 //                mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
-
 //                mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
-
-
 //                mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
-
-
 //                mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
                 testMapping = mapping;
                 enabled = false
@@ -114,12 +114,19 @@ Column {
         }
     }
 
+    Row {
+        Xbox { device: root.standard; label: "Standard"; width: 360 }
+    }
+    
     Row {
         spacing: 8
-        Xbox { device: root.xbox }
-        Xbox { device: root.standard }
+        Xbox { device: root.xbox; label: "XBox"; width: 360 }
     }
 
+    Row {
+        spacing: 8
+        Hydra { device: root.hydra; width: 360 }
+    }
 
     Row {
         spacing: 8
diff --git a/tests/controllers/qml/controls/AnalogStick.qml b/tests/controllers/qml/controls/AnalogStick.qml
index 5d011411c9..4e8ceb5736 100644
--- a/tests/controllers/qml/controls/AnalogStick.qml
+++ b/tests/controllers/qml/controls/AnalogStick.qml
@@ -8,6 +8,8 @@ Item {
     property int size: 64
     width: size
     height: size
+    property bool invertY: false
+
 
     property int halfSize: size / 2
     property var controlIds: [ 0, 0 ]
@@ -18,6 +20,9 @@ Item {
             Controllers.getValue(controlIds[0]),
             Controllers.getValue(controlIds[1])
         );
+        if (root.invertY) {
+            value.y = value.y * -1.0
+        }
         canvas.requestPaint();
     }
 
diff --git a/tests/controllers/qml/hydra/HydraButtons.qml b/tests/controllers/qml/hydra/HydraButtons.qml
new file mode 100644
index 0000000000..6c3070d2b1
--- /dev/null
+++ b/tests/controllers/qml/hydra/HydraButtons.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "./../controls"
+
+Item {
+    id: root
+    width: 72 * scale
+    height: 48 * scale
+    property var device
+    property real scale: 1.0
+    property bool leftStick: true
+    
+}
+
+
diff --git a/tests/controllers/qml/hydra/HydraStick.qml b/tests/controllers/qml/hydra/HydraStick.qml
new file mode 100644
index 0000000000..3c22789f6d
--- /dev/null
+++ b/tests/controllers/qml/hydra/HydraStick.qml
@@ -0,0 +1,91 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "./../controls"
+
+Item {
+    id: root
+    property var device
+    property real scale: 1.0
+    property bool leftStick: true
+    width: parent.width / 2; height: parent.height
+    x: leftStick ? 0 : parent.width / 2 
+
+    Text {
+        x: parent.width / 2 - width / 2; y: parent.height / 2 - height / 2
+        text: root.leftStick ? "L" : "R"
+        color: 'green'
+    }
+            
+    // Analog Stick
+    AnalogStick {
+        size: 64 * root.scale
+        x: 127 * root.scale - width / 2; y: 45 * root.scale - width / 2; z: 100
+        invertY: true
+        controlIds: [ 
+            root.leftStick ? root.device.LX : root.device.RX, 
+            root.leftStick ? root.device.LY : root.device.RY 
+        ]
+    }
+
+    // Stick press
+    ToggleButton {
+        controlId: root.leftStick ? root.device.LS : root.device.RS 
+        width: 16 * root.scale; height: 16 * root.scale
+        x: 127 * root.scale - width / 2; y: 45 * root.scale - width / 2; 
+        color: 'yellow'
+    }
+
+    // Trigger
+    AnalogButton {
+        controlId: root.leftStick ? root.device.LT : root.device.RT
+        width: 8 * root.scale ; height: 64 * root.scale 
+        y: 24 * root.scale
+        x: root.leftStick ? (48 * root.scale) : root.width - (48 * root.scale) - width / 2   
+    }
+
+    // Bumper
+    ToggleButton {
+        controlId: root.leftStick ? root.device.LB : root.device.RB
+        height: 16 * root.scale; width: 32 * root.scale 
+        x: 128 * root.scale  - width / 2; y: 24 * root.scale
+        color: 'red'
+    }
+
+    ToggleButton {
+        controlId: root.leftStick ? root.device.L0 : root.device.R0
+        height: 16 * root.scale; width: 4 * root.scale 
+        x: 128 * root.scale - width / 2; y: 109 * root.scale
+        color: 'yellow'
+    }
+
+    ToggleButton {
+        controlId: root.leftStick ? root.device.L1 : root.device.R1
+        width: 16 * root.scale; height: 16 * root.scale
+        x: 103 * root.scale  - width / 2; y: 100 * root.scale - height / 2
+        color: 'yellow'
+    }
+
+    ToggleButton {
+        controlId: root.leftStick ? root.device.L2 : root.device.R2
+        width: 16 * root.scale; height: 16 * root.scale
+        x: 148 * root.scale - width / 2; y: 100 * root.scale - height / 2
+        color: 'yellow'
+    }
+
+    ToggleButton {
+        controlId: root.leftStick ? root.device.L3 : root.device.R3
+        width: 16 * root.scale; height: 16 * root.scale
+        x: 97 * root.scale - width / 2; y: 76 * root.scale - height / 2
+        color: 'yellow'
+    }
+
+    ToggleButton {
+        controlId: root.leftStick ? root.device.L4 : root.device.R4
+        width: 16 * root.scale; height: 16 * root.scale
+        x: 155 * root.scale - width / 2; y: 76 * root.scale - height / 2
+        color: 'yellow'
+    }
+}       
diff --git a/tests/controllers/qml/hydra/hydra.png b/tests/controllers/qml/hydra/hydra.png
new file mode 100644
index 0000000000000000000000000000000000000000..a7549ab2312328ad5c1ca2636b1c2b1efb840795
GIT binary patch
literal 21273
zcma%jcQjmI)V2^M2!iM}K@6hz8l%oci6P495j}|BNz~}VAlm3HGWuwvL{CVJ-kE68
zdyD=qk>9tzKi)syyOvqAmOJ;JviGz1e$I1F#0w3T`-F6aSXfy1L8^)nEUY`fu(0mf
z5MX0rVPU;&^~A!$y7yMqz!eLNh~nn&4pv$Q4Hgy_z8gqg2_Hj9_VB@d?09zw78VN@
zNKszLYig?*l=#}fowxBswz+P8@U>g&%cRs%>zBqN<yiN-g2R9C5(_8VzN57gyu5RH
z2h{q^>Q!!p@W80*JM%hzw>B~svfWM`9ZDT7rI(foqp#^{W5PX)rqAyupZ7AZ)cbn9
zrk?+Zv9`5kV%qM}{BwFNSvrkL=%%@Yg@u(N&FP1Wg@wgGaMOBX;r~9caPDLM`}q0{
z=f4~N_q+by@PD{V&TD{0#e!JVZ3N1E_BG&~Cy(V+r2EspJQkLp>`^=oov%|!GDL7?
z)%kts@xjGerCAkM!5>;5BUxFjcWC~BuWH-RQhSeuI&}(5)IEJ@De9Uuq6I`-iF)o}
z?b71W(Zork3t))^DVC|QA!ml^LC!#QE&5eCet-!$)iQNa++vax>z5F*F#pfBZwDFo
z#K!PHLLlAhv0qysW##@dB6BW)dBag<&sDx17!k;GzrJ{>_=Di)&F{8eP0ZbCz=3>Y
zi!~m98T&Z;!J#2ynN9P3i=UN5D};nvA%U%Br#en3qMk(<OSa<~I+1UeKzvJ_1oz#h
z+iQ@|(fUi)kQMJ)M^7iGo$eU=>FH@HDJf6_F<!7q`S{LBA{%HJHui3#ah?DPMU2{s
zr2j<59O;%Wd(X|y&HeuUd$QWPNc-6Qx>=w9m(U+Sp0{mR=S|&Z8-%QL-Yc0q0VgQT
zA53}k`8Eo^a@x{bSC_&DN?;3>^va<uL)O{@V4I1tk-4hi1{CUiDN!?EKQZf~ow{Xr
zO*2rESi$cA>klz09ZlmyFaVV%z?Q`n=DTOM%Y41Ze7(<iy<eSmx!D~<-?CE&MF^``
z^U&i(P)H^d-jkKu=!t0J>Em=5Uvv9By51E<eZ4|0dtDTGRz%HfRM97rLAFH6D&zIe
z5xX((tMx7|-Wl5?b?tHYlB#)e4fqNyecGw6^=!2KYEkZL(JAoUF!D|?3mH&ROYs4-
zR$`TJXr#yc<xttc0E1*p;0G3hd>AE=B*Dwu`&20F^apk8pDxUKGp5@2`PR`}v#qvg
zIKPC54{d*53e<5P=1E<&UL0JX-L%H^`fS{s2GSn;VMAPlQpq6s!L<#o7hEL<jLY}c
z@y$ZqFw`|m4#f%vxG2CjY!K&{0SMjmn?~^k>_uf=EIk3ZtCEl)?)zL|`F=9XZoBOZ
zdD<Vv?J$AgzL@j5l-7%7=IfQXeAuX+NS~mE8co>YGw`GxQZiE`fz8O}Bg9UCjs1P9
zdPZIiqd?fIO?1TK1dT%JhyM2grLcWzG>s4qaS+R&O>4Px>cBnf@}_<8dk50m@056S
zet22t*_sUE#BK~LmnWEORO>lv+{E{3>>?*Y!z8@=&C;t38D9^3`_kzxh_vd}2WC7E
zQi{M8MIYPulZl143_XW~WgB(~fOr8=f-zP05kZjLd9~d6P)bWpRaLtL3i$Z}9v#-r
zOS1Y{L&!2OF9WYu0<X?nug?((1h}C6^4K<wymUyIJ?`sKGZKlMu5+TuDS)-?Bz6dj
zf>e66z!FqO<LpdNKtmfx6DgJ2;V||?X-$IpMn{GoP1(~W)2n6EfUAS7qQ?i4A@A|N
zTGOm*KVPkz^E)WNS}zYc8_p7?yC2!LNf7H%PTpL_bAXL;pS`^FXH}$Bg0I*jN=Q0#
zm@St#%@Sv+#@)G-2u0YO3Hj8A16nm-(pf~Wcpn-r)WHOa6-b2SP8!gcKQR~gGao*o
zHP61Y>#cDb-Mkxa^qnv8wD0=J^cq=H(@DHI5%YaroMbR9?NkO`s>7vY%lc}NyTPpe
z4oh_^)5-az2dWu`>a(Q%JS0pP11<ovS%rs6KR_RR%gh=6b9K^s{X5;srQ#meuLC0-
zyfep7R&`_#Ov{ZL_A__<teu@ds#@4TASmT>$R`6^Nfu!fDcR}Bv5Hckosx#|<GYg%
z32(VcqEIN{2WhdT58|<Ur6Qk4eUfciVK9=*tQCo;`GZ3)iTZ(y$m_@55y#lSg#HlY
z$fW!V64ZXrMQ(aNH7=P+B9LIyJ8Fk|k|j-qK<=Ewy0~i&qab>LIeIm_^}}m34X)uA
z4<M<|#&x51N?Nc&KmkF+R)h?R<O=h}FMQ^JKb4E(6@z~t?GH9P_+&G+<zec(CBo%4
zV81WDQas>6@xj9gn6nxkXPffE>c^kw0N-YlqT%0}$fatYr%$zrRog8NAJk-U0^Jx^
z`ZJ|4m)oAs^0)qR_-@Et?FC@@q~)afWX?D4SX+xW<buEvxIpl+e%TwI30NHGPj^^p
zXHaarpMzUnS2w=l&bghp|D5dZkxwQrJ&{o4H-(7YRYS~~Zqe}j3En@%vK`N|5;8I?
zjtvH{O;3CEil1gp^KW(gnyY_gk?T6~M+uGm-ec3yB)nImYZ1M6a_&5%ISj+@2xv7$
z=$1G|Xhg6oOTM;EGimlY>XEw=;N`x3CONR0h3Mm-{pCKn)9;$aV>~=<)QzLAlWC=B
z*k=j~AJ4)+j205=%q!j|3_X_trUWuH#NQqg2C+mw+J3v>%A!$Z3qCV1Z$74T8Mqxz
zu9i?O4EuAAfTL2=*~!WI5qhb|8F3cM<fVT=C_y1nO+63gH_37E9|zI}X7MxkeZm^G
zODbWE%#wG`D#tgphISEkb3Pl0y0@0M!zuiZ^P3^O<@BeMF4x0!yNu6^LxkZ0xXDDN
z8LwL3Bm`=CXck+*uFwZf;~SM}@<qe*>XnBJJblH->IJ85X4yz4Vm!>BZn3up|EA~d
z)JHJQo~hhvAm)4v1z)7fATTt4_nF%k4pN!?jI4dkFS^ZLPebtsQN!fuRDh0I)VI%E
zDOpryt=ZsW6}CPJc>yezM#p>$9r3o}(pv11J6k(G7S%i0(#HOa_CD}p={LtZV48!Y
z@<8JsWAt(b5^l*WMFeY8{w2p@P@k{QKL|x!V6%qAOU5oXH#hJ2tw_yi_6BYIvq>3E
zvj75CM@-A*mQ!H*^NH}>7Xs9aXUBaKs5Mq|d7o|)B>)y>frpOI{g-;t0#mQO;eqGV
z7>+?4fwE|vcj%jN;7685?g9L8eSyB7nVb8~b*#U=A9tJ?n1HY4Nc5Ds;)1RpPcY~E
zy#?%(wsCt4mt)zmQz?x1_2r3a;HA4{kPHWj9>ZS*Ucr-|h0q+7U!RpXp=^`Q;&+Zc
z2qXYvV*cK+OOmORuJA`yQzc?oHVC9ZN3*`LA}{(tJht@+;pE(|_3R_b?L)?Qysj@#
z0{0WMyx@9N%}<A8H=e2?1)ZND*<&33@R_7*2^dF@G}V9oxni|L)mNpq5nUY*wI6p6
zygJCjG`dH*jZG@GBk{7@tZ7yyi0&cBZlarS^W22j+f7uxn!F6WcIH*XoS^7Sv54W$
z-}9@Y1;x(+Aaafx#^p%~l(eRUn4P`-M!4JsE3d#`>qk4Qs`6a?7Hb8arxiv!(HN#%
zt-Wjiy12$HY3ca|@j_vqYo}ttvg6D0rCCOG-$4eYS0dYK8)<-9E0zJtF0EhKd$`=i
zVUe8wPV<Q$W`(76lkzRCk2oGsqGdztfTID&!dGbP_^Ps|mLjm526F<s4<UFEW=?ju
zQzvZ}B$Gd4tB7_r@H<rd>~5t7&u>`4b!t934rdNf3sg_G#HRiC4!$@A`^y+7zu@DX
zNQirVg>Mql%BGq^J^QV3%4>3O?x#d+`(x8UK%sO!{4*z{mkks`CQtVEZ5kWMpsA1n
zN;MWX);PR&v8o~mu@g5}Wx>BM8;s^3I5>RDiEM4XMmYILb<$XuNWXpGe$d2E?ENOL
zK$M?@R&Vv?tM%bG>gWU2z6{bni}h-rsKrl(EY$txZ!R;R$*QImVy>@FhK2c}C$MfU
zpClW3)x{UE*M`qbmh*&t_KhvJVY@VO2R|_gFZwgL$9pCHWonTiS2F3!AQ`%}K~RwZ
z4RP^^!koHylTzxy%vZ(6*qxU1?Ido!O*1O2zmt9X4z`cE+QM|3?0`<JeR)F3a&=1w
zt)6npXs=kAkEA!N66S@8v#JK*ulWi*2Jsa_N-D5lo7->d$AuZH7r?eW&co#{=68q9
zZxa}wSh600lI5W<_yReYVH2zwFHPcO>2i~D?Zz0(hpA(sCsQ)VOJVh88|MN1*c%Vy
z1IkvsN9|rlH_8|3SZz|~XVy{xFaGq%#V+cDBN&8lZHZ#eYcZx&uROWvx!T?f{rOO)
zBHMLw4J35=MJ!w`AtZ9dV{nE9?|WDF8^*Zc=fki?sRGI*UBaFR6gophxk5{B^=0RC
zzB@PBEVhKrF0CJ&x!$arY$2uf!ZNL}W#_!bsZL+RN2bS9VUl0vJ{}I{B>m@aGyd#;
zR`B$oG*M(<uQr#ydtC)}R1%>dhO~n}cCpRu*+$65S|S(QagIKvJ^<O=e0e<W)VkYF
z6zlS~>jn^+4nZL@sh^^lt}%g^Bd$j5VLuiN2SL-hZ>DH1)XI#PUxON(-Fsg4L+qWM
zb6&=9C4swQcfOsgCWHW$xLyy(T@ZIUFGY{oA;AUYJ<fI0jJ)?s^g#)b05ITjC}a1O
z3<zSwT0{2ex%)2_%;ok8W6uLs`C#-fA?ejbVnYuzPtOyv)>C!X{#@OG%J(^lW&PDN
z;qJ}t?J)BR8{yBRc6FGIBOiIP7a#Ogb0Y@7h?a$EhkVO<6mzk5<U=`J`9*K?1c0W^
z{qPcyWSI&nTk-LRn>M&CPa*B;>FF!%Zxaao8Y<w$ab4@>uV7L?44)h0!(#1UymFjH
z=*C&c^6}E~jhIlYW|Jp%L3VtUPo|>YbIl$)|JdY=3?b9O(E@8JJ8?p`C6~Ek_}h6$
z_;Xa~gd<I^=fjz=*7aJ0-ru4UMXy=Q?o7^Ub=D=1`Y>l?F@O6qL4TCG0Wog(F!%+y
zz_ziud3JkqeB%g;sI91AQ9i?~#o{H^v$9grqEymC=-Ss!dv4FL255g>Z7h31g8xaI
zJPNm{gC?=CWTVkG?P`I#_0P<TEWRP$Uk83da$F&j9Cy0R7YLG@3bm!mU_>!(`WK6q
z2C;lt{Pak?Ku3;=7%zBs*0{$xh^1JE%bX@b6#E?aut8^vV_mOww9Sl#CxVtx!@xGW
z=<e*LtK!GWPA?OF1NdOeJFz)0i+WM4zc?qGn(><%Ke#Q4TTdFD$MM22?dvg5;kWo{
zv1{>Iz@qXXa{+EcKviAc6J>1NJpKXJDJ89?#+I>H{HpsiY~SA*F-^<$9?ZBJ`6`U>
z>b1iZbP9dpD-cNtv0m45Uy9RQQ$s_;y^Vj}66RXU?Zs#IdwY52o-mb59+H_P<<`#;
zZtV6NbK>2dw&L9|XoOe!5bqNVPEFRD$VN+ySGEDsG9*xsQKux{=Oje97rIW<bBV3H
z_EBEngW9V|K<!zN=H})$%3DcrZs5=L&QX13s#GLr*Kr#@^XBH}TQ`o7?6dtGoPaka
zcLEY(pTV)w5x-d9c%nj;w=SEQyb>SgjBgyBUy8>{5Ln)Emo40SwY2!vkW~ME=GBrI
z#*f0|z8_xJynI%tS3IZEU>0Ouul4Mq6fQ#>sE0klF0X`cTeXcoSA2>bNCSZ7EePlM
zYxk~ycVkeYRq9+=3AdGJ4G{$ruFW9gUmJ{V92K9j)_{hEpN9eK6T%z_lkC|;w0d(w
zEZ|lUKqk8~sb&cTfhQktX^_C?oi@l^fK2WsUNE6l0;OG_{lx6<FCtY;3EW_}1?a@H
zJJhB?#L;qJ%9gU$qh`7;)7Zrj^HuTK$GFD(CgpXlt(w5amYp73AaXwk#X6d=JKP?J
z`<{m6VF_?cT%*kOap*@NCm@;(Ob3Ym?tsfMH*6X5ttz@#q->+?%a<3}dt+l;(r6iU
z%%V6!(9M_g*`0to6be;Q@l`^e#P$|_0kIUFJAEm9+Df6bcN3m1O{p^Ubdr-VLk$cX
z-p&K7Cn<q!p!VKn2BqYeEuZRVM$y@(AA{rB?s@WPwa4~})XJWH2+BLm(g-ChD}p_)
zk`{O*_Gp}=bd-CAPx@3P>tbYo0n&<jm{-V&IjD8ST&?ECb+&Em(Ma9e@ph|+PCo~8
z&iICdgTvqt3%jwLo|!w~Qz>4@fotH0q@*Oy$l}-^^EsFA0OEeXIM1HI@~^+ASBy4!
z5xi){Seq-maK33X+J3nJqFveyG5@A5j+%8W8U`igLlIYl%$I`{)@VzEc0gA^>vbDG
zGi;R6yzn;h{3G$xJ;{E&Y-@YFD(+dY;L@uB+`_R(@MPtg+}Z&<<hnOg3ZKmrZhT!2
zm5(x<#o6i_JC;zPRkj|kT{;URPcQHku~e37f0z~J#~lTt;B}>}Kb=pEmOGtWAtl6k
z!P02Ci`|ZWEH;{(=n?i__BT!ZC3eBcXsI4*me(0pgTxD#Pb-`mIOydrH)?cSYY!!|
zM#GJv(1mnSz0!!8pitxdfp!|en>rw;?aJC4@mSc<fLuYy1{cP&W8g{JK35fex=j%e
zdN^N?!?||A=%TYUi}1q6$urP(aYkFyWYy!W`_tv6KjP^0U}ac*&EteSDN^9~`e^Af
z;GRu<5c=0aMCW3CUbGXU^?Y`xil<bEOR~=&v*Urf49Myp8MZGoY5?Zjj(i@qOKMj>
zHfZOc+3^t1t+DLzN`cY1@5ePaA7F`59X?X&aQBye8330ZKVZO|NM**tlvh0Q{kxsj
zURi8;NX0H9kw{_n^I%7W$@c?4Z*Kztd(4N$mKBMe*6V<@!jY%;eZyZPZee>d8sFQ(
zCfQQVX)ga<w4`oxXXoVn5?s&@ZL~(i3tm+YNa!hX{*KK3c5)e4=KllA|3ey;3`xeX
z_Eers6`$MUD##aRVpJuY4v7b^@#FzAY||uTd#iuY<iX;HW-&X3wgGEHea;MgPoF-0
zicnq4x1HMZ@aH@9&svbjxQCF9mz!!Pm~%he6ud3UVDa&`D~-Hc4MR|(aS=$(^wz-1
zf$)(uA9`5Y({ZN$_jy19n_EvIRy^d*kxynLtXOmS<Wf8~X(Qe=JH#z1F@88FU)b|G
zuf<E-H)0_faYi<ILg)hq_8}eLGASsY2Ib2nh(U7PZ&QMjp^AmeeZ6wNr%!1uJdQoa
zMaS~&*wyht2?Qm<ECd}D(_0BERjsY9)zu0X;hWI=YD|CI$ZXC3?PNk4?dj?1pcxX`
zpP#oHE|1VPG%<-?te<?t%ga00;2Mr=vmhR@*G0`|+M?FHXHMfGnaM&>!yo!}nC3A;
zb+;H9)m{tTe^4)si8}ANj|&C?q%x1Mu9&ud8$<10mJW_>i8?gi4<;P_u!`O}^4ao0
z#gm0_-=OysUR59BYWGeAPhV|qtyc=y!}=0LxMaL4Nth@i;9{>w%xR9TD7c0}2JO4k
ze4_8oLV)edy)^+i5gO_$gHz9?7uv#Cep)4xe;A=-4^gewS7i*#*=W?FRJ9E_NEa(N
zz5XQl&Y7XdIit`vp}<X;>qDHe5Y|oKgJqc}cyg}5x>VFaMXj1F4%;*zd9!HSx*Kwn
z&6GRjErWH=Alr7B`JXXEC;yARo+NNVyiekSqu3BE;$--q&IHR>zCv><sI@g3-t4-f
z@k{BjYJg}+_+jkF_9cUDNsaPp#JHU!<)Chve4uCR^t{5dcS~z4T4<F6@eJ#4jFE%H
z1@p1aHakS@K@q=wWz}`^?lM~*dYO?ve2Ev_c6@w{+G#08l61t|_0($6B&pO78N<Eg
z0IS?Tgm_77Qik$v{SJQrME<=3T1_MDxcf?N)3h&*z@X@H$&Dk)nxaz7j%llR-t^Yc
zGl{dr1{tdR9=9d_!ZSmy5(W4tV}!0Df=cAOHqM0^{|m4{I%<};+1~o*dP3a68OfQE
zKR(g)IxerGZB4cRqw%9Bnydst&CShQTU*v}Z!25d2#vKaYEvU4qs^0Z+q6UyzJhg5
z`0U(dgY%+t0vns-vr->nnbohqjXz1>LfTbLCM;nIo9E%%HF1r+K^xI@d9nfaBKxdD
zfH(7(l!+~mMR5*)s-cZn5(k1gJ2Ar+QHzIxt(aE7(<;dNP{H$2J9j6ioyE8^F?z&-
zrtufuby%0HaVsV+QFzM@Rp&Un?tvOnQS!Y%!I}n%!oLlkAA>Ai*S6I|3KLF>^X3ZZ
z#FEsN4YiDYobm?s4Gp6f|BP)JMny%L)41HpL|rPC6bst^n94~-RsA8dq{-tH>~1>f
zmx^69s(;&d(4<jx(uU7G+lX8i?+3b8l8<sFf%67ePtG$nie??31E{H}f>_A%lE3W3
zSe9-omec(C%IV^E2`L0p7)Y0s-+LfU+X)6d4WVpzpM@5rSsJ8u0Y6AT&*zVYI1dFL
zAWXNmw;jJY#WxXo`jC+Nj@R)E-{l06m%w=TCP<k21hG3RAN0R{N9G?7gAmPgCec4l
z`r&q!?uoG#O;1vG2rO?NfEJJ11-E6-I*!x1+p#ozY(dM#cAK(C?FRQ<lM?B3V0OZE
z?NbA|8^nJT(H`RDp9ML|@D;6jL;XZw&iveXeu5yMW|Q)9+w?JnVO>7VzLdV{U{pUQ
z7iuq%%j=X!t_x_2A4%`b0SKfC1Fah%y{^U<YBS7-#%Ryx<z-9O&Z()Xv$M0Kjd8iN
z)jR|Oad~-ZQa)}Y3`HbwG%lHZ+?J;a8yPi?=M7H%2jry0NsuESe@n}PS;s_|2F9Ny
z58C;S3=B$iOY0nGhoIwjB80vA+FGj4&$9cV676(LLdm_B*h%5!lM0&>q~Bz*qpDD4
z^kMVI$H)EsBrmsO1dvb%fB($6c7ReWJ~b6pXWPd-{(nr@4^~#WGTqV@bXMR>rl%if
zCF&=5X^C%hYwPITAA)O<!^aU0OHjd%A#nIKV5y!8q(ZlR*QBG+vy#?({~^WgGbrIL
z1bxut)7&2{YO{6Pvg6H^w8_|WFX){D&=>i2;ywD;!S}|_IQk;*#1`28q;*z-3s`<B
zRL6O3iWDzcqe#KiJy&W=ZTUwUr@Q|?;~Yl~=V;55hlaftJe#<n9j*`Yq2@N@<y*FJ
z%G04lMNbR0>d7yoc9wbsH<h*5K+lfnz>)8E!-}|hPqU&ZALvokkl&Z)bhhut?I4gM
zbFF!-5C7z1_8ohR2>Wo0(03m-yFFz7JY}mev%flPF)ba{cdTqmwpn;^%5oWS9q|O7
zP3Xm{rW}d$m-C6c?~xZL@H^ESUNUM2wYQBnbKG+<CCII+@PLt*a(bs&PO?PU;-|m_
zi93XuW7l}zv~X3|GSE|H#8y_Cw_=K_NH6uv$3ZPDv5T3RnNY--jj-1bA#b%;HJW05
zg8RWn<Nn8!)(+~lCg1<RNx@Zt^p1{>f(u@aza(5Hama^td~`HOws)}UH>{qNcKxl^
zY=VxNo1R8_Y)y@g>9%4{uub)c_$}RO1SZcprL{R4VM9xj>g2471<+BbZ!BuS=B#B0
zH=ukR<-FLvHC?BttE<W$eqvA=kG*xMKJ4b|svQkJu+XE!k_|?GlV`?B@3Ltx9FzRe
zUJL~t@Q5jM7K9D}m%0atBW7rxy5vMJsv?9~-E{6Jl?#4!KM$T`IS#5AHTuKM*Sa5i
zeR`^A;xoA<8Iw5wRSbX!Qj-w0Rb-tKR3^+(&Pc&ERj_yHoOO|Kf3WN=yXqP9E$Ok{
z5jd?&ezglEr*UQgukZEVpP?wfn!kQosw1`KA4vt^U-~w}2-u~w7#klq0MnQV-6k5@
z@$tdgoRRgl{Iv`6TLm-4u)>l7Wx(jo(%j_SoG$o29u8o+NbYit+SE?~l;D9<@3L99
zt5UM=Ze%jLS2?ZJfPoW^!EzqEa2G6yb3|I-)GZ-ohhN=i^-TSf2<3(OVXqWSG^AZ#
z+1f@-zDaR5+rNd>PZB>jbB;mj5L_!?_zG9}p>+}@mf_fp160-8npL<qH^=n7-VHUI
zV&Y@#?VTF-BXRMW{3OhSS%`M2;l*UyP|%2lVkm4ru3`0Lp?UUFqlltM;GqXR@apvM
z+TvOg4;ha#;2S^j`1p8_73rN_T0doyvx%=r<1yPeNT@fQXy+ZD8H#@PQloDANcr-j
zY(r#21ie?yv*9M0vm-(mBaQZLHlYdAl)F6qnJzZH<<V>sxA@78(Y7y<GX^_t?Mh<b
zt$vuZPcTjVWQk(MA5&CZjoC>YmOm4ZQO=unRMG0p`nK>oKcc$6-bQ<}><H&Jd_LOu
z?EWNV-9J&iu~q!jnSp(2Y%F;Us-z`I!#OVFxjn;tHP1}<n6an9Wx4liZu|K7cwu2-
zXb6&QStD_@RflmDP1kWNOqbp(*<HhbJxH1?^5^|VBjwqk9dSo|XSW~5)Y$lb#|r{v
zMaA32ZlwKqnN}xt&t7kDuhdSH!pMqde&U)3ik_bS_|&Xa?A8>bL;5)%C>P*a{Ftn^
zCK_CrE$?<uWLtBSg1abE;>yR<yDs-8P1iX+0Uh70p2k|Z@YalNd7vOAA?9Ako0D~z
zfOLJ;trJ|&MKek(jzg~5r1M<=vcn)Y+Pm^>1vAsLf#+Lwp)YQt;I12z=8-S&e_8;#
z<MT_a>W0=<j2)6IiSS{I3_4FPF~JkkdwF?TP{8gxt05_KllGWr$FW*l_k^XVr_apV
zI+^5N^=4)=0`fN+of%MN8(wfo|J)oLMsk^~IB;@uQqtS@^H{hlkp!~J^i)bVcZBA3
z-DM&R$siP<LXgSk-8^=2iMjU2kcPfMLbujOPf8|$9iQ?z34_c61GB)&FyVaan&~aq
zmHtUwhGUUmvNxm^@u5KY`;3Y_=JcPx^K<dn9?_XEuvzI9kSh;qC4mvTrR<=D!ZkDg
z>_&Wb>bc2D^9ZFz^mLAHL%1o7(j<hen?UNNih{tWnX-*#Z&?~Pr>4CPw(t2c$nPX@
zC?UX{hHGsgmgnp_z@0NB`&D0ecUXl7^8~5c&Of)Ay)W?jnyVn}fWyT>CCaFm2Gspc
zZNsq@L)ejG;#X->?kgW(^nIAR|9XMC_1EdKGlP?Z!)%jx;@YE->??J4HuVa*0bjNd
z$%)fI&#OwB$U^PawC;!<pG%$`?dQWI?iVKICks)0-esoc<K?sU``f6UF*~HNdLo;1
z^z+3G&_>kfdHBj~y>rJwQ)p;tP#W>;gxj{|dodgbLlIO;TAr;ILhvI4X>=kmVR-(g
zTDiW&Tt6+Ke2hmHS0Yq`*}*h<C*nP+<{ei(pGhSrja8>kXrZ?K!x8++@4m&M8UOAj
zf9#^^_1XQNy&x9BZW|%~ZXK?N3(j&(FV49bldIgfJkouh12pd5zB+_FtpQb0@uGB8
za_dqMZPTYsb~o6IC4}aN7vf^|!;Ayti9aohH=C405!>6_CanSf<;~-3ZpDV*wo9og
zBDpr-!hpa<?~ZmiB-CMN8&JTN)H^pfR}ufzJ+139pmlsh6%aZyYA2$u4am?a8s6S4
zvW1q9hZYd{ogZ(pff#yNmyK?WR8w}uqVLUFt4X<D>1gG7-UmW%Zf^Jnh}8fqx|AK3
z6t!4CzA@Y4f8L)dHR~wWCx|%#u)U6;_5HM$Gbym|xhinV_|qzJUAnZiRM_JKP>xk-
zdDW=Ljc(R4rF+E5$!W#g1feV8tEveJ53HUHvBmit%AW{ZTVqcBG37d3qB#!zUCvES
zO&OMx2*Wy;%pPY3FL?8Ol1@imZLKQSW`Cws&ElBH+h_qWSfF98XrSWzD`R1!hVczV
zSs4jlu>4G7yR9hHd1&Y499+Wld`K9f!vzx5VYFc92e3a#Bix&wo)&IzFe&eNc1z?^
zfLC44C7;t#71T!OsLg~DQJeUz6+n?zH%pOC_mX-SmMCc~rnWrN3SoEi^Bw@Uj(-4J
zH034QPW%(hXJ%)A9{5>UJdS+iB5XI>y|C~KzS6DQvv+)a4DeO8JRz04i1#@M^<_L8
zURe+~fkJa9DQ;^qc<_aB^(0St2+yX=N<ZVc`^M4P)D*O6_`%q3sL%c7qp7Xq<9-i>
zZk`&gd9l|oagOoa8fd3@*So=kw7SwlTc3m9KSxJLmzS5P>$d+=rL!yq>qrh<xcLj`
znfW`Oo}Q>#$7*CnO^u>&jnVj)o8)Cc7WR*>t}cFJ^QnL4SGZ1ChQGYoyOmK>FzP;A
zs#iX?aim*X02B0fj0UOTQrI=L`kn4yT?HT^#`^l%8FZtN1@Xe#eCcugN$KCPH!l!j
z86-W<$0sM%Jk!#smX?-)mHtd&^$vcu;il;=u7b~_>u23yN~IJ&(-!vwA0)IO=Ns(Y
z)i~vD(At-FenoA@zc`L==bOX!A-0urq%<}%V$;>SYaRUnOb38%yqGt<q5u6?`ZIl+
zxA7edAO>H=){oAPkB@uA$~+|*E!6BQ4a&!3l7aMk672-+ui;iL8xjyp2&V+YIY-E<
zhg5J|HWX1-mN5t&{v^IE*-f)n%+r_eCXFtT&KBra9gM@@X}-SteKv_iiumkQqh-?z
z*PH^+r#(>3&CSiIx^YKO=<}$ksHlz{hxR{?Y$3gZ>grdAJxqP$S6&m(Zz??e%Xg3D
z=Z<s`x<n^|CEG3UB*pY}b@77R%=lHS#Upcz;EnNY-!n61FhtabtP&irCJ=$tY{jZd
z<luwB%Rnb5zP>7c;_<Pu5VA~-C+Gut@+fDVbqBwTy`E9Kq}={-)4*BhjDXhGx;ksc
zZSnr~buM>BOM^mW?B^t_YH#ZsDapRBnGV4%Wfu}e;oxzyy0GwQT&8&WLlX{b2uuS`
zs*)u_7h{J^V~gNlUmq=1?qvh1US*V^pXM$Z@aK3JC2lk}o5YPa)r`rLDQa~}wRxc(
zy&uq7ggn^tNU#0MRp5v5G*0=v3#EaI!q|0s5sD(LonvEE>dqX%>MG)!ERuh~_1*Ha
zrN+GTsqZ)7<KmC9>K5d8ve{;TPS*i)m+FU9b3y@Z9X8`%W`(&zJ}iD>%C`lNEIsIg
zfQ7hrD5Ya_^2;|=^M<7RVvePq1|nhv<jK5Z?L+1tMU!zw`k@cXj8V1C&6$>|EBBX)
z-rQoBdA4TRhJ0K~ax&+4B~3d-C{r)>Dhe747f@g{%w;(xQuqzZ$>&i^s=McKlAEBN
zjVuHUqwXcvexG8(XN=+aF>GZpwZLAZ#Y=QVqN1_6y$y*<*l5hhDS@?%0&kYI9!tk6
zSP-FWpij3)tu<T?$-`}97quvC(h7yEttVXAlq7yEVI^{Y^J6Sa)cTkSeNoL*joZ;H
z1M&M^Gs_Jk@9o{oQV9Q9#iQ<809)~PW(fQ<A3p1tqKbYT6~Ay>)jXLRH;asqdr>~l
zodjm+nIh~7o9TT;{`F^7v}DMKJ+^b;aBSw_VfOwQ7F{gh%dFAJkIpD-ewqR62anfa
zRXpi#n0(#9u_uq?I3ja}HKf^%$BW`tPtKc7%4Z#?*MO{w1(2Lr_S=kP1xKFjuKZUM
zoE_aEsPE$=Ln;Y27n`RcFGlY8JmWTEuo<s2&=9%ro1vI&X`2=qJY7bJv(>|^x^KxD
zu6kbLH{N$(^uZiah}qfM*{RNx?_xN6UKvC7H`~!{M74>TBis?XrK5JR-QE}~aN5TY
z(OL}x%3!6)XsEqK2yBRzgZ^iKNOI8Up<0xDS>%ehAlf~7_^q06qhiM4WJLWmk0lHi
z*1PO6Xao+Q)YN|Z%~cC*DM<~qVSEl)6xU4X{4}4|cQE7bFImbNxqc*>_D|-eXuZ98
zL6=0=`|>wykqQombKJ_44g@&Rid2`R9A0Z*$nll+Cwwq$q60hU?n$r^iazFNrPBNb
zCb8VxB$Pt&`-Rvc*Ux1)>25PjBhl$4mM>*xQ}<9Pdh3{MXmxhZx5q9o4&p0AsgMF-
zO65C~N2$Q?p=3P*A_Y{1b?VTN<36uW!BZYZoAd=s_Drkl@4c^Ya6ijWdd!&NVsU?8
zP|S<a@IonaW>szF5Ut9}xa?Kt#vlawwj9b@0|?LZnCcIB#+QAD<g^WbDD2^|q7;qS
zpUB1gR5amgf!+F?L)v_prn;iSjI`_@*TZJDO?cN131!fneEgos{cT}6^&jD&xx%#x
z&<^gPlJnaG?uWx&#mR!k?OFu#06DrAkP~b82fBQl@G^h8CW`1D2QxvQ+b-LPrZf!M
zAqlHzJBytnq(CKY2abpit+JhlmY$;+?DQ>c$)cf6uNa6ED1l$fS|ad_Wn1l4gsPqM
zQ{rYmwH6yBl;8T7&>v|PFSV|OO$QC&hpsLqy9Iza$;GG32ZU`k{ADg-#%JI@o~)#S
zJZE_wGW0>l^3YDeS=-}@9<_wd6MxLf_Z=1ocetwJ2BL!Rt0N;jP!mjaE35Jk67=*l
z-Z*NUbwVF5V~hC`)};25;yjI}b?{yGcBI54DF9tPqqg4CM%Uue^rH-lUK3h>Gm6Xo
zV7GTDFHaUfL%qC7xMyo_D-o+8Y5lJTm%-m-2^O|4fW2Z9P<RjLq-;Cwm-}GwpqnNy
z<^klxgKDBaWqSln>dhl^L1Jn1eW-})!h147jYP-R6t?g29uV84L49AVC;n8SF-t}9
zdGZNFHPvGz4~g78rYN7Mzbo>)_c!=I%TgS%6TzG$vONeF!P|=)c?KROJ|@yfMGe0W
zeVwu5jnK9C^)<BLY7|sgPqx%K=SWHwR`054dBjMhI4P{o*u%=#!TVP8&N&#q@{;S}
zzhx7+Pz@AehotMNjBj_06Vq0q-gvNGb!;YOXU^&0it#kAgO)r24ZRWd^z;nX3ZQx6
z^=;Ingi?Eq3iSXuaA4HUO4*p%EoqQ1uCTcMpX31kqI}#QIW;y$6~RDNm=VK%XUDOs
zM~(O%Tj)n1mu(0c<h7(8)C(>|lW&{GRR9-18L__3x;7-(I}2>x8=G#mt(zX{|L)z4
zYWw}6x6>(sr2<J(SZxr^F{t%wkO_<MpXlf7$)$4M$CU<`OklSI)r2L*beCC{(q~q{
z`K7Fk>p{0ekF$q|hbmqQb_Zu9S5hQ1o^3|HE!gn0>fSp+XAh-mkEmYjzSiZ&_!VzX
z@}R#3&&B(&^hxB0O1<XY{HG+(22<4^$F7Bt0l$l@t2QZvkad`=-`A&gJbgyXgEq_s
zBm4Wnyg}9B8abL5A*yKVTAB&eJ;JU;7gN}!MFFHlhiiE8Z>DUXt@(&9M%g@SgvX>i
z2Zh)i!dEv=g!q_{^*AG;)KlW{=N2<TEHuP;mjM{(3=^@!iTGGec52>EqUZB<WaP=3
zVVF@H;o@TK+s<dahYFH*I^%a45w_s1Y#z3O#VFET0(p|21MAFbem6KXD5X0aFW=Sr
zMiKnYdd(d*GS|5t<)#J~Wdlof7Jhja;ERM7OagC>3vHlQUt6n8sg{sGAS^j{e_qN@
zLX{F<iE_>65S&(Ft2Vb`2`-u08<Jk^&J&M4zYIt&Jnkekp$WzHcp)So>#?=6@XN7O
z8ePJkjHLY-{7<-q16qyz_+qSixwf~RU`gbK7K&v-$)QkqEqp;Xc^DbT%JGKx6T4f%
zeZ9jne&Wf3_T}3jdbjuX5++u~<8tE%SG#5k+UraeI={^b6Y3W4f5G$d_1Deg!a<c!
zmF`<EhC>shT_K{~BX%P7=v(zeij8Rcj4EI3M6%AWRFRRQdhNcsSoVS+Rh@*}!~zBc
z>OGvDaNO2z82@*is(bfu$Mb@fSiv#9hzmbOk%Rqr;Q$o2WE>*G`ytiXQJk^4JJoF|
z2*<@nDU@3X33Y(j+`Ii%gfgX)hm`|QqScSdhg0dF6g=uxau#NPLMcK}y-}~hnbu$u
zEr6209{<n3$o3*zFvq0)yhRfsr-+=)YX`p2g|nL<d@{yzc}s{beC%5k?yD`$a?axR
zwm_$PGUWW0adwRW7XZl{DV1jpM^Q~D-<ee3JlWg~8xG175ViH<L_EnPrAVtaez=6b
zVSd8i%dYXa-_@egeIx)wy<{j)nk7Wd7`+wl7WCaDI9rp`aDLRA3HmWLh}&G6^_>2$
z4TWCbV1@hp+aJS8<B!4Sz+HjuJvqpT?kC&VL^J&3Aa_sY@5X;?K7to)438pn`H8y*
zr4*RiTYEk$#`^k=i{)I)prdjL#%TX8+MwBkSc-K^mkm-~=XsNad~hRh#@)Re7NEDp
zg7kY{X-lLAiTV@VutbJ<5LYAY^W%B!e|bjS0PurVwe874mM}Cf=87<3Juz1aePGki
zQ6_Sm`m=jE4SkP3FRW)xwE4NS@1G?d3j{FVYN!%P#(KyfAC*f;9#p>JJv>I0Jx`o@
zi)gdn^^SeV8;iq)PntzNrUS364(e7m(FXRnmrb@$6Zsc{zgM!FvvMsVjJm&p)`e;e
z+uV)eixEUOi*UQyE4x<iyKq0b!Qso9>7o;+B*qvJ3TM;wqafR@#x5AHH}FoxTpi2j
zuE2=C=KLya4h^?jha8?f)?XC{|9~qoowKN@pH#xx_{Rz9s6c_Wx<sa^;NFHBT`i`&
zS#8$&;=gHl(5mi9l?v0b)Iz*8zUYUStV?R@9|QlZ{)2c$(b<%*{6gF}?eJ6xbsT6-
z|7Gw#Eo~Ag->4lX%0l#OZaE3jcSr?|gga7ma)h@7<GVt3?_K6ypr+h=0I*S;f$($j
zjKUxuR#w}J#ofq|Tr#l;tsYMGJQ`o2tj;6QWxn=UnEx}2Rm-aEIp5W8u63cOVvUe1
z0kkU>?^nf#e{Bse2U9s>K$Xigw5$jL2;SYfb;9yDRC(Q3;jC~e_WNRsYccL(Rw-vs
z)q382$IEJ4X~1$B82j1lp2{2w>OOfk7GAU4OaHp4I#GjE{dU1YraZf}zhIt1>6JiP
z{438erghnjV(^38YJs$SkrSrP5!3JY`U3vw6@Ns_G8fsK|FmhF8MC0b0^L=$&wAF{
ze&r`~7}?*p6ukp10eprIOYE67ydo`-t09x?Bhc{r>zXO%WL`hqmRht*(|)+lZhfwd
z-+%U1oal(OMLEVKPvw0&4*`jqq?G|w-rjiK>E$7C3|){6;e{<m-jV{|g!hW1=qz6e
zbk^U+;CO;!btC}Sgx~Mq`s01pd9Cux&GM|vq{P>6cVafMC#`S)gBt>GXoc*_0T=_M
zlf_7DWo2t^-5??vfj<t6SSbEU7YR`3{w9w7)z#YI?^SsJAe+5#=If3GkcTfWkM~pM
z(<~JSjYn}fYyV`FdPNp*ga))|FP_Z_TJ$?68!`D)N#9B(;1;HNesWo5CHiw8+}W%!
zXou?o;#r()#T(~~!(9!Q{d%v*xj4#IhqYnaOW4x0<jAo1Y_fEL3=(TB-Ms_>10J4~
zPF1~DGcBbT7UG}=s?HNU4jBR3ScC|WG=EZP4-(|Nov4Eqe+IxGpVv<;hJBK)USeTo
zeOwTKsnHV*#Ub@jiiz2@S`ii{yN$d}?Q=_#N@^P)PpOC5iF#=}6tv(>cW-bO!f>$S
ztO{70*TN~oZ%<mYw>`VtU_kH>x&4Nxk`pB6ez^g^FP8-hTZB_Ue18f3iKgr+*%Ocb
zr9E?P^3FxtYn7JiXz|xyEgtb<Q?8!^JonzNjenLc`YYextqMJC#L~Z<iK{IZ2`sF3
z4M>jYl%rvfz0+_ETNP~`D=XLt2&Fos1s=br&r!F!i~PU^V5IudrR#J%kL*7J4)=b!
zJy{)Sn$|BlvPc!gzYP%r)qY<L_u_NA^1|NR<m23IiWmmX&~nq0_O5*@xM!PuqCu<M
zIY*fBPsftUI{&yOhFbBPRq6x1iS)Ot8~<S0*NQpMPQJnY5H7aUE_sWh40$iyWZyHr
zV8zSOQB4&tT!ni&{Byt_?)iCdhH9dpY6iq_v+nHD;`wY_JS)AgZHL%$QJmK>;cfk)
zkK}y#I+_eh;2>w_ZD^r3FKnZ6u-hBMlwy3(!iBYFES2mL+O@~IibosV1_?(0I`F##
zWw0RdG$L;l()d_Gt$9kT1wNRsx|u=g)#0y;zGVf{&$fa<tn)k&!R3=GQryH_8!ozo
zJHLxv+RIf(`q}-kxX<Ft5^%nm^4`8a%WH|h#FEeU<i#_B6D-Eu$|$=bF!wcUS(Fjg
zE!umViG$dG<=|;otEIQ%?{oyro%kD>-g>nKp8`NhJ6;p0YY*u!W1+RsTk3I1yW8Q1
zsnhnVU$})MCrl`0W<v-Swa5A7jfO$Ig~ZQ8cLw}%>RY`wjho>Zlqe_WdlES`dJ@4F
zn(fhlUJ@NQSEhVT()2Duzqp-wDo=7<j<H3_eyh<j+0vXQ@|@<*zd7DhF{dPFqLXBN
z{A7DRuK@O6GU?ah%s`mQWXa~0zo<6ECr1fixknt2o7J}Bjl)oiQgmkMIcTaJKhF=<
zs`mWjS`$@z6YqDkR~~kM0)zw<&#5#t%A8B2xIZMspRZ-JIsO+rRVd2rDSRN4uN$}j
zC>Y<fcu8fQ19(7}LUY@jPXjZirxnf7=W?6*{<;=%&jP8>#BRsfv6ZN_GSH;#aw5Ls
zi*~T=U+HZhipT56z|Dd&LgZc*jRofw{j?(}0XoJV-t*}fbuj=A%z2^%tuX!SlvRc9
z4S?fX=ELACd)-e1m~L5!17{2ec0*a;p}(+3k5)J{ro+6!i4yP+i=G3Ak4S=kX;Crv
zx-^H6mG^BptSf(cWk_Ble%q@4uWfpiN}K+auPVdq;tQo%66eHa_<0y8{BMGRblfwN
zGpro$q(~Y)n3u4?T7Dd=&fEETx`RJt@!x>aBcU;~F)CCs8j~9$9#7Tj6y-7p;#~Z1
zOTWu^3PJ!&gzjSQZe9rqGqgF?dH*-1cr3-;J9z){em{yd-U~L`j&MCfW<%E01;-yP
z2a)}gR4I3En^@Ko`q5RZbkvIuS5L3^bsF$&tw|0B@jw;N)|kq2Wa8Za^obI<AEM4h
zB_DgcBD^xOw(FlI3Xlm(IN_;bnl5u=JECO`*=Q`=U}}7fbsLf?V)%(klLnCfF@S<~
zeEKJ`%ZE85HTPnoh;CKugt@9TVLi(>YLh`C{tTBn864_(@Bfowqk81^GON5Sb5i#m
zuJ2Uk$5*72-(v#h{%~e6?7`BzNyN;vSI9^0jwbSoK%r?MO(r@TDj;y;Umy@7duoTI
zlVI#I@uo4<X%H*wIPssNi`r+o^*Vu^JkD1!2LMAI=FhGIfQcr2NyrvlhUCB6Q7+z!
zH#8(h`LViok29eUwwhppjsz9GjP8XdSOsi-xJYvb280ge1$G3(%(I@Yr3}%4dYDmp
zdVnN0PyvKBE_h1Sx#2JQ=mY<%Llne95JY<!rILD)R>f%lW<E3}0}`2TzBB21I|*mv
z_taA)2!ia8c9^9dZGE#L?!K1jPctq$W(PUvueMSoVkwk98h3{OlPG)RZpCJXTKBAa
zen?fKixFs2{0F5@MR}8NH11U~d8ly}I@U|ByCgt<d(YVjZ;HGVz12>_pW7f(l9R2R
zg_)Y81Rlq2dA$IaAWe*nq<N|D-A)~T2mNQ8@-JV0$i5Hq7P7D_|5|(Qsad#@M#Kt(
z^!4>^HvPBvz%^PqPpf5}bcxqLOB&8bEpbVa1hKe&^dGAx`kacIS_Vx&o8bzGA#3D$
zWl#Ef06N`J0U80U&TAMv9crI=45NRpRFa^<cI@9e`G%^W_O=lcQG^i;qjoO=UH;N4
z#-s~u>|Hj~FDaFt931`=Gh?TRk`WORm2FUYm^}1*UpbO0n7HshV_x6W%BMdzgs6V~
zX~lEgTT_wbH`3QPJH-~rX%2)uU(=d=<5Zcs-0YDzq<^nxe<P1`A)f5tR>hTs-p(fo
zcO(>{!v)<CEPC>tbuKPNAj<1hCi-|@uIPrw6ES*qi_yNG3Iq?r=G)tW$(C%7gi0y{
zkHfCdbI$XzDxU3uM0{?v8f=!Sz}5d(+Ed~0`Ul$De&4>61`(2|8D5ny*zM(E*a(B6
z5rZ}rRm8Oq{-q5rX=Qbg&nD#uNIo(8+3M^cI63D$&AG>MNnp!vv47mpkOI)+$Jv<=
zU|R_MP-Q=!;VI%h?V8~SfxfNc1^z8;)HA16|2I-xTT#fA+{~!kT-&D~TLHj+vZt0x
zwns4H-m^{lDPY1SL?5AR{_&PF7p|ud5wh;5B=<NO_C4Iio&W@5XL*#4RxvWr{7X8W
zpydd}B>RrSLvyRtV~<sOQez>@y%``~<u2Qxr?+<l+57*t{k5^kn3$N51id4|EbpJd
z+E28U7_Idn)Qd&k57C%_Zg=C)zc30)fAuUhtBD^%LveYjQj#7%@usNO_HL9DT%`H}
zqTt+AGbOvrK>lBjV7n`2Q<pHCDhzP-L=(%d8y2d#S{!(Ge*zZ(r=l0&wNAGggZ~BR
zAw8}<S=f9q`)aUEI}gsxx5bL<c#xs*e^uo+9$=n4hnkxDK-xO9`#}xND!(|LTf|Qp
zAg>wAzMV6JoR;gc!XoOucU)EhtgXy0H7p&qNepTxj$gesS8wb+eSHh}w4cB85tWuH
z^LJt|Qpq=x8o0ZY+(HU?s%vU=Cfwec{0kg?#RDxv+}zyS%1S>b+z&tGb?w)dB9X{_
zpLhRUT*9K7QTQIKsF+w0MIG74pY_xms_LqiMI8ZE@wMDL+3ay0j;gN$3IE&OwYx!M
zy!rE|I{8m7>z^d<&tioIif7U!`=<L2k-_r)KcDjOP%bF`$0S&DDh6h3RUs{`a`HZL
zdGezcg>3KrT!`2;G#WQHHh#MFM_lS36EG7J;#P3l&iC}`%hFLm<+K|fv-`oQmZ`KZ
zD!ZbCiy$Z_CZ_5+?h_)cC}J!u^6Z;)0dDvFu0#(Uv+IG8P=r;rgbcghTe4n8xs$>g
zsVJ0yrLps?{)48jE~R5Zrgh>Mw}8R?N>x=oZ_|h8?`4D7G8Ar(ex%sgeBfkjw@(?H
zj01A67}jRcY0qr`g)O4u)LYPWuE%ym<I%_9UEgz?8u*W)IhI-t>~SuBq@^0KC34CH
zb9mzasv+6sS_rdBphX#KuCFTIUu8*jJ9&w*qoXeu%6>M01fePqFVh5E7<?x{`8-~a
zh=_>f$tVM&m~Oxm{<xmSF_l|!=0^5mZsz^j@YFfgij?gt&C=CjUc?(de0t!t<LXOu
zQzPtV$4Ri&D6}GxBD_fx^lCkXqOxBN4u#4Z0d1LMQ#1<fP9u2#ob3;tsCp7)r9bn)
z-xL;dzt1<7Dce<mou6kTMHBjPiCt!|lLA*%)AV13lx1TY%z-nQNKa2cYKQz~ADt;C
z{e7oC(0w+qj5eTo<3{lOaN-%k-#}aReKEVSmMnMjjV{;2GT;j{eX`-k>ouv+dKV9g
z9ssT<pkPrPp<BxH&?9S*`?k92!Gds^EfBIo5o2d(J_&4UA9?!f^+u@dD(O{w_7ikG
zw*nsnOl+&Gd1Nf)I!2iU)<^3+DJF>c`l^<fE%(JYTmQN8FwPtlY#CWu?Xg{iaowa@
z1f|vkDs#pp(XKvfrTueLL^r1z90EE|4^|GOt!pPek5rgTlY?IbgyFoLk|;#Vy8e#d
z$PFj|yS<xFR7@;_H+GRfqNkQK0-se)w&1XB-u(T*vR&Mw_=s?1JIl=h23b~L%FBm;
zvrDarfVMZ_QCt?NP^+THdhb^QB}c2assEnHP((;iPmj>$M!Sx2XMftbVyBHeOm4qh
zTdAH`EBB~C+H;$sQRL=qhBILcZ|_u#(n`bUJEoLYZ@`Y=zCnG>kS5~KP4<Xj7O(y9
zPn=J0?|e)Uq?{-3AVX>)ZTY@_nd73}u@tZvRLraCRHDPhV}$j$w`+><6}0pLaa~ju
z8A7Hq$e;k08}{PNT213;4sg}L#&}ocn`eb3;p(u2LQho#(1z(E4;H!T<?QTiYkO}P
zar>?g=ZvExcaOVP4_M^Lt!T5oS0C66zo&7JOIQzD@t(-QzB&D&h(S~4h!X8chEM;l
z_d60~3=aR?$Z&=&N!R1QTqlGW7FNQ(-8wH<Go~rMcNai2Az~>|Hs(CipI_Ovu@-sv
zRZyb@Q6+al6;Garo{=op4GTAliG`GwmOg*}JmYivlBwFO^$Ev;s-eaFo@GTi%@YTO
zHR&m~LfF*A1ScAX^S8Y<tdY5+qocy=UG=Aup%ZVDsd8zX<3L*T`AY3qs$_S$xw-4#
zV*Me;@$Z#?KQ~!zeIT8c0H-+NdSSTBL6S)&Aj(uD)@6rC|M`1rif+dGrX2x11kEii
z8b^@;#?0j>asN}ub%wLucJbJX(prh}v^-|e(AJ)nRuR-JwPy)cv&2>-9jLbC(b5XF
z6;UH<)gCP+MoWztNrlvWh)um$qVM&7eD4qUr*qxszJB*P=YRg^zR!;W-u(brG5x6w
zuGl6J2t7T_b?516oC+tQsJ^YEkwPP5KZrALo%@8n=Y4^!YS2D!yMybQ^Sp@<_D6e}
zpK?@e_w~UFE!wfPzgbJp3MFi+b=mFSK$Jzx`o&4j2mWh4KVZqLd&WAf<jP`iSR*N&
zk^fIRA|Z0Cyt4A6-KCMj>=A*3w*29sr%?yRFWfg*YH&#jJlS+K?6Rpf-Q^HW8N7lW
zyMASBZ59uT{0h#2y2okaf`u24_P2HvL;*B|m%5`kN9azr&1k@Akn5a3w`;Y<Z6GoE
z<aZ_Oht02mU{2bStIjVhdR`Z!BV_uotgW`j4#d%)_xcw0w$`8kg<0+ioQ5k}+t@G#
z4N>tuR!vO2kxvz7rJtO%B2lihwX8(!@;*;+PQN>mZmQkT+?>MBLbaafOwxvkos|hB
z5@|RI*=_aY3{mF{xwzCdn607D{#+vuKvO^9%MbPS^MlCC3%N_*w|O$?3%QbBfU*OL
zAzwcBEy|({*ZE>BlF;C$3(c!C{ncLR@JDu~T?QBq0F6oEU^V3jS#_`>c(LSi`chB{
z%VlDv<kN4ck2AMQOU!Vs>xV#jr&^qV%{dw<4WqgR;qyq~O5|_e?MiSvo`HM><k@k!
zUG{x3Cl-wp_=C!T%YjctPV|l~^@>@a4J%pr({n{wuxwN{G#lieH9+d=VIFUyQY;8C
zAD|L45o^<Gv%AGS|6cGI?7i^wLJ{LacuQTKb>%oxiC5qi7ft!qH)Kx?N<EnLl|XRI
zDoTG6WMz`jK`N;dDl38)PU$Q6h#LmYcQC#G#cIV$Te%8a_FX;pcT~pRh0lK6Upx_)
zITsYm;!SKp1s0Mo5>6{LbPncUwx&byQs}UbmduNN<U`5>&t14d#!3g0{q47WWl0BJ
zD%LHF%b|qUY;%hKC+$}dM?oQOe)0A&{$fQaT<qEFzY%TE8_ZD=DJ#84SzvNAtZ?(|
zRosyOmL~A?pZXASE>OWTC+2|cgN@+Q?tb@@STH?}8kCxnH5`2q9UblM{nTKk5n>@s
zbHz!=yo9$+0rSvLPEt$>^e2+!UxOWoh9jiV&tJ3+_V=hw%7ZyNrV{=^DxBYMoZh`g
zteqKnC!pksDK9_gE*Z{pSNS5Wd=r%$AA`|)SrVWaLn0UF)N#=(Y0#`^K}4`B;vrGh
zROeWcCt^hI=Y$rgy^(LyPj^=jhY1yPnAYxe@X>2Nt^g()o{BtK{&N(fk^CoA5&2H6
zYY)KkYu$WbD&53cfik)4X)20gd2_P!Y^R>jd1jw3@Bj&PVvV0Olj_(JOGS0mB<N-d
zN=dFDv3eo)6=NilWGg$*ZCaG75>dqOmuAToii_fdjHT8>9!;ST1J(K&pytNL#`=1A
zjj$S=w(Vn4QG_$Mj<O1M)QDd~{Zoh<F|P%%$z9aw32W@4)A&oS$^i4&BB`st!QUAs
z(ED!<PTQ!mR)=2bR2PaTtD!rPs{Z@!CrwAPO@i9Q_U8u#x&9~hwi&}aGBW75I<e>o
zJ>+el-kW@<THiucMZ^pG?=C=HBYYjyw0;R6{wzS8H)*g;>bciK88O<49A-RAbKdrk
z`BrMO2=a)8k2wKjK{`OK4NmCP9yvk6NA-ui%)?5snDJ$xypvoPx<2$YG!O{g$ymE*
z*_;rqi!g%WgPd;ShpT}rer6;;S6A1N5Ns5^!suy~Ch8vEx;6i!udk0p@=O!&@Zpl7
z_zo_)eZ8_#Vb(aW`PbP|<1~-x=ug&VfsZ(kg=h-uAKv2?KF~9#bg;`8c=v5d{$P52
z7x{HBFn#9pSqq9sR?#bnqfD5V!Vq9DN_{TA`te9VBx>}e-0B`n1YthWMOh=90i^L4
z^a;>8>g8Zu)H#YS1GPfen>x1RQfm{l9vg<%Z<V;L;GUw0_{1QY?&$pv?$>uyZqvCw
z2<lieE!)R}vMBQY)d*?O0m?fSs95xJ=Un2TF(2uqhW#on7JSBx->@yO6J8sr_U|hS
z+II|f&3^TGY%&Bd*Izp(D=S-m$V4M!5*ZsG$GuhS%sxuzW$tO@y9+ht2FR9CHW_*Y
zQ!a<2{r&tPmoCjGoiaBiE;j-p4!NtQyxbWG^}oF9rYIW&Ga7ARH8wu>JZAtkb<tT<
z=xILM?C+BC*_4M%@e`V=IbIJC!JQL5lG|Z?3*m$5&uO0#=0{x-^GKj@uju7CsOSBa
zf}HC%Pe4*BvOP*K(h%v34U6IO%^UPdaa7pP3b%D91F6s5SB~P0qdurPhF<d>+idxP
z#bT3z@&r5D1_J;>wBc6ZVq`wA^`ibO9?Z>{O5Erhw)6M(Ew8AU|0DP?7*<-G6QiE$
zzP4O@n`y<wY_x2qu2zh%`f2%er*n};^o^_{`PQQ=o?P^ETVUo;?ime;L;W?A{8Zw(
z;^%#r?3lY8Wrod4Z=kIBS3{tt>Zx1bEKTQS0CQJ0;Vv9b;R}2|A8cS%lrS~aRi0dZ
zGuW`QOsEQ5C2wIL$M%lp7a={GKQJeStu-w2^YhpHKY&fEXo)NKc-UqXd1n=Aj`tQ}
z<wS8?)@9xKWI909%_N3;cJRXH<|dD+W>r&@Q6rr@`xr&lWVC9k1ZAOUnVDtU4KMd<
zos|j!Mb=z<S9Q{XWS5nd1)*t~)U}rbRyN_JOfM=AP!p!#Qogs5&pQ;cUXG99t^b?C
z@cwR%L*tlws(YHGbdQGEYP?)OT<#pTmaj0>2Fen2hoj#(k|3z&%wXi^=Zz_Z<H5^E
z$3xeYCj<Krl8z$m4IN?oEU_CbsP#@P^}`6CgM`74_O})jL`3*6^u+|44I~#0S>n8T
z^;|*By1Cev=tE`G5nduCn0h_Aw7;0MD5ZN35T*T38!*sxcJj$J`IbGmnhEjZgsh~n
zTERo0-M#x)#w~CDOy$1m<vREM-anrCq(;nGqg@3A0vYqciW`Q8hKA9-7&YH;*2D>M
zFjKo?Hor*i69e=B8v+*;1I80_DYi8enuxV&A^+y{jO~<P%J=gm)^ms9jJk8GsoYl#
zx!sM^#O;=8Px+0ClhXp|luCRmaA+<2QY%KuPI}rIb4Se<hx=(N=bdBV*2LM{+uPr{
zlRIPz);k$r-j+^s7!Pq&Ny?*k)1p@^QnnvR+en+4(@{~$<!D-R9ltHvAQX;9P&*N=
zt*xzXY_>E{mhzv|Xo)QPe6X;mI=HRR#h~TDp~oZrRD+5<l*6zBw8gsVcr#@Z!+!5C
zX3nn21+2bVmO74U#rw%aYEc&1w~Fm54q7fA&?$+YrS{_1$PuHf2rijZzq^n~<SVC$
zrwBsFI_-FJLD>u8YpR3$TZ=$`{)1y}GALz1Yc+d2Iu?OY>96*zu`RU{?)_KOKQ>mU
z|H=$dqtpQUHPlhXFfAD<k5&sVIwwUB*h}GM3D_Mp-QDl*?q1A^)lMaXhXqP`;1vlX
z8_}(^>*=w&{Vw6ukr|OzJLY~Js(p(VCiA|{pj3HjDO4}es#Ve?a}ga0NhMZoiLsUo
z^7LN5pNF5BnZe_!&56aMqTlK5xRDt}o6t0iG!MG_Z!dMF&|*#}Q9*f8d%M&$qzT{d
zl8ZFQq?0mVb{M=vzB>W?q+75_l;-3xx_u^pC=4QBW_sgh_33=RNmW9-2uJ5D=NQ|R
ztRto*8Ngmt#Qf2=^NCUmGCy9TehF=wFFg~zi{EjwXPZ|~9kw$ht7C@kK>7Mi{NO^t
zXU03xv%!vT9>TqW!n1f-nN{)VztK9Z^mZJPk&&=cD$QH$;m6p+UuBh^wxmW#_QNnM
zwrA4#hq$?|{1(M}XMC`xL5wbyypCOz${}~$sdLmh-m-&T9<Nk+WAZ*ux{#ncNHO^B
zz$N<)v;4@lr0c~r<EB!z+-OJb)T(q+yvWjaL@KfQ;8&UR!N{xMKTUrp>Wpir>l0nu
zX)mHVC{c-tJKrT94X69J9`D#t$=;$CWNj*)3Zby9B5yRfFj3j9pbNyP%d00juIc*3
z%hba*!^1mGJRI%s>l;Pj$=Tb|IoZNRk*?N?C2M8N^=smYXM#?N_83@Hvx~ssFh0z2
zwg%$&@$AX*)a>ujCcM*~JF3AXW31hM<u}i6=3A8RwXCZ_OtR<jnB$n(*jOFIG{28R
z#b*i^wGSt7Ek~REas~D;7~QiIAFn=W`?Gb;I4}AM{NW9=jCQ{KosoE}hA;X-jj+l0
zE`;19H3<@1%vmkN6U&d}f|%PNT22#FejUoc<knIxW|k`a*jcG?wIt^69-LSHr4L;;
zN&M;JqQ`=H*y9ZP^*>2-pp+u}!@xe{dliYiP*yNgbeV;ZjB#1hY>gtn5vmsWXw^^Q
zaeX3GKx+ry1s|O1y!GS1z$UZ;+8Er=7*kuAF0y<urxH0{pi(#jxC8+J05f%Z7{~l)
u0=VQ-86QFL|4yd@|C2fu_`gz|?I&E)5w3b%AWf<&fT7;48yKid{C@yPNwlQ^

literal 0
HcmV?d00001

diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index e173b7893f..0c5ef09867 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -88,14 +88,9 @@ public:
 int main(int argc, char** argv) {
     QGuiApplication app(argc, argv);
     QQmlApplicationEngine engine;
-    for (auto path : qApp->libraryPaths()) {
-        qDebug() << path;
-    }
-
-    for (auto path : qApp->libraryPaths()) {
-        qDebug() << path;
-    }
+    new PluginContainerProxy();
 
+    // Simulate our application idle loop
     QTimer timer;
     QObject::connect(&timer, &QTimer::timeout, [] {
         static float last = secTimestampNow();
@@ -122,11 +117,12 @@ int main(int argc, char** argv) {
                 auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
                 keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
             }
+            inputPlugin->pluginUpdate(0, false);
         }
-        //new PluginContainerProxy();
         auto rootContext = engine.rootContext();
         rootContext->setContextProperty("Controllers", new MyControllerScriptingInterface());
     }
+    
     engine.load(getQmlDir() + "main.qml");
     app.exec();
     return 0;

From 20416455dbb61b7c139ff094182ae144d42eb293 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 16 Oct 2015 18:06:58 -0700
Subject: [PATCH 049/301] Adding the loadMapping feature

---
 examples/controllers/controllerMappings.js    | 25 +++++++-----
 .../src/controllers/ScriptingInterface.cpp    | 39 +++++++++++++++++--
 .../src/controllers/ScriptingInterface.h      |  2 +
 3 files changed, 53 insertions(+), 13 deletions(-)

diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js
index c39ece4bc1..d314df3f4c 100644
--- a/examples/controllers/controllerMappings.js
+++ b/examples/controllers/controllerMappings.js
@@ -12,7 +12,7 @@
 
 // Assumes you only have the default keyboard connected
 
-myFirstMapping = function() {
+/*myFirstMapping = function() {
 return {
     "name": "example",
     "channels": [
@@ -42,31 +42,36 @@ return {
     ]
 }
 }
-
+*/
 mySecondMapping = function() {
 return {
     "name": "example2",
     "channels": [
-        { "from": "Standard.LY", "to": "Actions.TRANSLATE_Z" },
-        { "from": "Standard.LX", "to": "Actions.YAW" },
+        { "from": "Standard.LY", "to": "Actions.TranslateZ" },
+        { "from": "Standard.LX", "to": "Actions.Yaw" },
     ]
 }
 }
 
 //Script.include('mapping-test0.json');
-var myFirstMappingJSON = myFirstMapping();
+/*var myFirstMappingJSON = myFirstMapping();
 print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
 
 var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON));
 
-Controller.enableMapping("example");
 
-var myFirstMappingJSON = myFirstMapping();
-print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
+Controller.enableMapping("example3");
 
-var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON));
+var mySecondMappingJSON = mySecondMapping();
+print('mySecondMappingJSON' + JSON.stringify(mySecondMappingJSON));
 
-Controller.enableMapping("example");
+var mapping2 = Controller.parseMapping(JSON.stringify(mySecondMappingJSON));
+mapping2.enable();
+
+Controller.enableMapping("example2");
+*/
+var mapping3 = Controller.loadMapping("E:/Github/hifi/examples/controllers/example3.json");
+Controller.enableMapping("example3");
 
 /*
 Object.keys(Controller.Standard).forEach(function (input) {
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index abb9544892..80816d9773 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -14,14 +14,18 @@
 
 #include <QJsonDocument>
 #include <QJsonObject>
+#include <QEventLoop>
 
 #include <GLMHelpers.h>
 #include <DependencyManager.h>
 
+#include <ResourceManager.h>
+
 #include "impl/MappingBuilderProxy.h"
 #include "Logging.h"
 #include "InputDevice.h"
 
+
 namespace controller {
 
     class VirtualEndpoint : public Endpoint {
@@ -176,7 +180,8 @@ namespace controller {
     QObject* ScriptingInterface::parseMapping(const QString& json) {
 
         QJsonObject obj;
-        QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
+        QJsonParseError error;
+        QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error);
         // check validity of the document
         if (!doc.isNull()) {
             if (doc.isObject()) {
@@ -194,12 +199,35 @@ namespace controller {
                 qDebug() << "Mapping json Document is not an object" << endl;
             }
         } else {
-            qDebug() << "Invalid JSON...\n" << json << endl;
+            qDebug() << "Invalid JSON...\n";
+            qDebug() << error.errorString();
+            qDebug() << "JSON was:\n" << json << endl;
+
         }
 
         return nullptr;
     }
-    
+
+    QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) {
+        auto request = ResourceManager::createResourceRequest(nullptr, QUrl(jsonUrl));
+        if (request) {
+            QEventLoop eventLoop;
+            request->setCacheEnabled(false);
+            connect(request, &ResourceRequest::finished, &eventLoop, &QEventLoop::quit);
+            request->send();
+            if (request->getState() != ResourceRequest::Finished) {
+                eventLoop.exec();
+            }
+
+            if (request->getResult() == ResourceRequest::Success) {
+                return parseMapping(QString(request->getData()));
+            } else {
+                qDebug() << "Failed to load mapping url <" << jsonUrl << ">" << endl;
+                return nullptr;
+            }
+        }
+    }
+
     Q_INVOKABLE QObject* newMapping(const QJsonObject& json);
 
     void ScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
@@ -286,6 +314,11 @@ namespace controller {
 
                 for (const auto& route : routes) {
                     const auto& destination = route->_destination;
+                    // THis could happen if the route destination failed to create
+                    // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
+                    if (!destination) {
+                        continue;
+                    }
 
                     if (writtenEndpoints.count(destination)) {
                         continue;
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index 36f62a3abe..64e7cb769a 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -73,6 +73,8 @@ namespace controller {
             enableMapping(mappingName, false);
         }
         Q_INVOKABLE QObject* parseMapping(const QString& json);
+        Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl);
+
 
         Q_INVOKABLE bool isPrimaryButtonPressed() const;
         Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const;

From f90f0ed1f342c37b2e8187981f10022a8021a425 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 17 Oct 2015 12:34:32 -0700
Subject: [PATCH 050/301] apply Huffman's feedback to Sam's PR

---
 examples/controllers/controllerMappings.js                  | 2 +-
 .../controllers/src/controllers/ScriptingInterface.cpp      | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js
index d314df3f4c..4de173f16c 100644
--- a/examples/controllers/controllerMappings.js
+++ b/examples/controllers/controllerMappings.js
@@ -70,7 +70,7 @@ mapping2.enable();
 
 Controller.enableMapping("example2");
 */
-var mapping3 = Controller.loadMapping("E:/Github/hifi/examples/controllers/example3.json");
+var mapping3 = Controller.loadMapping(Script.resolvePath("example3.json"));
 Controller.enableMapping("example3");
 
 /*
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 80816d9773..6edcaecd3c 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -209,6 +209,7 @@ namespace controller {
     }
 
     QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) {
+        QObject* result = nullptr;
         auto request = ResourceManager::createResourceRequest(nullptr, QUrl(jsonUrl));
         if (request) {
             QEventLoop eventLoop;
@@ -220,12 +221,13 @@ namespace controller {
             }
 
             if (request->getResult() == ResourceRequest::Success) {
-                return parseMapping(QString(request->getData()));
+                result = parseMapping(QString(request->getData()));
             } else {
                 qDebug() << "Failed to load mapping url <" << jsonUrl << ">" << endl;
-                return nullptr;
             }
+            request->deleteLater();
         }
+        return result;
     }
 
     Q_INVOKABLE QObject* newMapping(const QJsonObject& json);

From 293b7c12e151b49305b4d87137816aee387c4e1b Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 17 Oct 2015 12:46:05 -0700
Subject: [PATCH 051/301] change join to makeAxis, fix some warnings

---
 .../controllers/src/controllers/impl/MappingBuilderProxy.cpp   | 3 ++-
 .../controllers/src/controllers/impl/MappingBuilderProxy.h     | 2 +-
 tests/controllers/qml/content.qml                              | 3 +--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index fe7a5c24af..c6031d45d2 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -39,7 +39,7 @@ QObject* MappingBuilderProxy::from(const Endpoint::Pointer& source) {
     return new RouteBuilderProxy(_parent, _mapping, route);
 }
 
-QObject* MappingBuilderProxy::join(const QJSValue& source1, const QJSValue& source2) {
+QObject* MappingBuilderProxy::makeAxis(const QJSValue& source1, const QJSValue& source2) {
     auto source1Endpoint = _parent.endpointFor(source1);
     auto source2Endpoint = _parent.endpointFor(source2);
     return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint));
@@ -82,6 +82,7 @@ QObject* MappingBuilderProxy::from(const QJsonValue& json) {
         // Endpoint is defined as an object, we expect a js function then
         return nullptr;
     }
+    return nullptr;
 }
 
 QObject* MappingBuilderProxy::enable(bool enable) {
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index 9531d8bbea..a29f7ade39 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -33,7 +33,7 @@ public:
 
     Q_INVOKABLE QObject* from(const QJSValue& source);
     Q_INVOKABLE QObject* from(const QScriptValue& source);
-    Q_INVOKABLE QObject* join(const QJSValue& source1, const QJSValue& source2);
+    Q_INVOKABLE QObject* makeAxis(const QJSValue& source1, const QJSValue& source2);
 
     Q_INVOKABLE QObject* enable(bool enable = true);
     Q_INVOKABLE QObject* disable() { return enable(false); }
diff --git a/tests/controllers/qml/content.qml b/tests/controllers/qml/content.qml
index 4beda82df3..5d81ead2fd 100644
--- a/tests/controllers/qml/content.qml
+++ b/tests/controllers/qml/content.qml
@@ -83,8 +83,7 @@ Column {
                 mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
                 // Constrainting a value to -1, 0, or 1, with a deadzone
                 mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
-                // change join to makeAxis
-                mapping.join(standard.LB, standard.RB).to(actions.Yaw);
+                mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
                 mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
                 mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
                 // mapping.modifier(keyboard.Ctrl).scale(2.0)

From 251a55b1fb255355ec5f8fbb37b96f1f9c982018 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 17 Oct 2015 12:52:37 -0700
Subject: [PATCH 052/301] rename hardware controllers to not have device ID in
 the name

---
 .../src/controllers/UserInputMapper.cpp       | 26 ++++++++++++++-----
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 0d0ae7d85f..fbf1994d87 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -31,14 +31,28 @@ UserInputMapper::UserInputMapper() {
 UserInputMapper::~UserInputMapper() {
 }
 
-
-bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
-    proxy->_name += " (" + QString::number(deviceID) + ")";
-    _registeredDevices[deviceID] = proxy;
-    qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
-    return true;
+int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
+    if (!_deviceCounts.contains(deviceName)) {
+        _deviceCounts[deviceName] = 0;
+    }
+    _deviceCounts[deviceName] += 1;
+    return _deviceCounts[deviceName];
 }
 
+bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) {
+    int numberOfType = recordDeviceOfType(proxy->_name);
+    
+    if (numberOfType > 1) {
+        proxy->_name += QString::number(numberOfType);
+    }
+    
+    qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
+    _registeredDevices[deviceID] = proxy;
+    return true;
+    
+}
+
+
 bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) {
     device->_name = "Standard"; // Just to make sure
     _registeredDevices[getStandardDeviceID()] = device;

From 7d48fe918729f9cd6f5d2014a3cb7673b2a0becb Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 17 Oct 2015 13:00:43 -0700
Subject: [PATCH 053/301] don't include Standard device in Controllers.Hardware

---
 .../src/controllers/ScriptingInterface.cpp    | 47 ++++++++++---------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 6edcaecd3c..a51c587afd 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -481,31 +481,34 @@ namespace controller {
         auto devices = userInputMapper->getDevices();
         QSet<QString> foundDevices;
         for (const auto& deviceMapping : devices) {
-            auto device = deviceMapping.second.get();
-            auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
-            qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
-            foundDevices.insert(device->getName());
-            if (_hardware.contains(deviceName)) {
-                continue;
-            }
-
-            // Expose the IDs to JS
-            _hardware.insert(deviceName, createDeviceMap(device));
-
-            // Create the endpoints
-            for (const auto& inputMapping : device->getAvailabeInputs()) {
-                const auto& input = inputMapping.first;
-                // Ignore aliases
-                if (_endpoints.count(input)) {
+            auto deviceID = deviceMapping.first;
+            if (deviceID != userInputMapper->getStandardDeviceID()) {
+                auto device = deviceMapping.second.get();
+                auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
+                qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
+                foundDevices.insert(device->getName());
+                if (_hardware.contains(deviceName)) {
                     continue;
                 }
-                _endpoints[input] = std::make_shared<LambdaEndpoint>([=] {
-                    auto deviceProxy = userInputMapper->getDeviceProxy(input);
-                    if (!deviceProxy) {
-                        return 0.0f;
+
+                // Expose the IDs to JS
+                _hardware.insert(deviceName, createDeviceMap(device));
+
+                // Create the endpoints
+                for (const auto& inputMapping : device->getAvailabeInputs()) {
+                    const auto& input = inputMapping.first;
+                    // Ignore aliases
+                    if (_endpoints.count(input)) {
+                        continue;
                     }
-                    return deviceProxy->getValue(input, 0);
-                });
+                    _endpoints[input] = std::make_shared<LambdaEndpoint>([=] {
+                        auto deviceProxy = userInputMapper->getDeviceProxy(input);
+                        if (!deviceProxy) {
+                            return 0.0f;
+                        }
+                        return deviceProxy->getValue(input, 0);
+                    });
+                }
             }
         }
     }

From 7956d737ab1b50fecf2c72253ff7a612e4796975 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 17 Oct 2015 14:08:21 -0700
Subject: [PATCH 054/301] fix thread safety issue on JS based fliters

---
 .../scripts/controllerScriptingExamples.js    | 16 ++++---
 .../controllers/src/controllers/Endpoint.cpp  |  5 ++
 .../controllers/src/controllers/Endpoint.h    | 13 +++--
 .../src/controllers/ScriptingInterface.cpp    | 48 ++++++++++++-------
 .../src/controllers/ScriptingInterface.h      | 20 ++++++++
 5 files changed, 75 insertions(+), 27 deletions(-)

diff --git a/examples/example/scripts/controllerScriptingExamples.js b/examples/example/scripts/controllerScriptingExamples.js
index b3dc92029d..93e91c6b00 100644
--- a/examples/example/scripts/controllerScriptingExamples.js
+++ b/examples/example/scripts/controllerScriptingExamples.js
@@ -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) {
diff --git a/libraries/controllers/src/controllers/Endpoint.cpp b/libraries/controllers/src/controllers/Endpoint.cpp
index 3f1d12b9de..5c5aa6cbc4 100644
--- a/libraries/controllers/src/controllers/Endpoint.cpp
+++ b/libraries/controllers/src/controllers/Endpoint.cpp
@@ -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");
+
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index 5c6e6c028b..f3cd163071 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -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
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index a51c587afd..68095505af 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -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);
                     }
 
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index 64e7cb769a..07ddd625f5 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -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;
+    };
+
 }
 
 

From 8578b40236d9f4dfbd9b4feb0098133ce94a2ece Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 17 Oct 2015 14:14:45 -0700
Subject: [PATCH 055/301] get JS source functions working across threads

---
 examples/example/scripts/controllerScriptingExamples.js      | 3 +++
 libraries/controllers/src/controllers/ScriptingInterface.cpp | 4 +---
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/examples/example/scripts/controllerScriptingExamples.js b/examples/example/scripts/controllerScriptingExamples.js
index 93e91c6b00..edf4dca414 100644
--- a/examples/example/scripts/controllerScriptingExamples.js
+++ b/examples/example/scripts/controllerScriptingExamples.js
@@ -29,6 +29,9 @@ if (hydra !== undefined) {
     var mapping = Controller.newMapping("Test");
     var standard = Controller.Standard;
     print("standard:" + standard);
+    mapping.from(function () { return Math.sin(Date.now() / 250); }).to(function (newValue, oldValue, source) {
+        print("function source newValue:" + newValue + ", oldValue:" + oldValue + ", source:" + source);
+    });
     mapping.from(hydra.L1).to(standard.A);
     mapping.from(hydra.L2).to(standard.B);
     mapping.from(hydra.L3).to(function (newValue, oldValue, source) {
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 68095505af..9f9ca85dd4 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -62,9 +62,7 @@ namespace controller {
     };
 
     float ScriptEndpoint::value() {
-        if (QThread::currentThread() == thread()) {
-            updateValue();
-        }
+        updateValue();
         return _lastValue;
     }
 

From fda8292fa60679419a715e20d048d7ce14e3898a Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 17 Oct 2015 14:53:23 -0700
Subject: [PATCH 056/301] remove dead code

---
 libraries/controllers/src/controllers/Endpoint.cpp | 4 ----
 libraries/controllers/src/controllers/Endpoint.h   | 4 ----
 2 files changed, 8 deletions(-)

diff --git a/libraries/controllers/src/controllers/Endpoint.cpp b/libraries/controllers/src/controllers/Endpoint.cpp
index 5c5aa6cbc4..9e9b13f8ea 100644
--- a/libraries/controllers/src/controllers/Endpoint.cpp
+++ b/libraries/controllers/src/controllers/Endpoint.cpp
@@ -12,7 +12,3 @@ 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");
-
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index f3cd163071..923412ac6c 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -54,8 +54,4 @@ 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

From 57be59935d79e6594eced9e44320c133f93a967f Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sat, 17 Oct 2015 19:11:09 -0700
Subject: [PATCH 057/301] Move controller test to app

---
 .../resources/qml}/ScrollingGraph.qml         |   2 +-
 interface/resources/qml/TestControllers.qml   | 171 ++++++++++++++++++
 .../qml/controller}/AnalogButton.qml          |   2 +-
 .../resources/qml/controller}/AnalogStick.qml |   4 +-
 .../resources/qml/controller}/Hydra.qml       |   3 +-
 .../qml/controller}/ToggleButton.qml          |   2 +-
 .../resources/qml/controller}/Xbox.qml        |   3 +-
 .../qml/controller}/hydra/HydraButtons.qml    |   2 +-
 .../qml/controller}/hydra/HydraStick.qml      |   2 +-
 .../resources/qml/controller}/hydra/hydra.png | Bin
 .../resources/qml/controller}/xbox/DPad.qml   |   3 +-
 .../qml/controller}/xbox/LeftAnalogStick.qml  |   2 +-
 .../qml/controller}/xbox/RightAnalogStick.qml |   2 +-
 .../qml/controller}/xbox/XboxButtons.qml      |   2 +-
 .../xbox/xbox360-controller-md.png            | Bin
 interface/src/Application.cpp                 | 112 +++++++-----
 interface/src/Application.h                   |  21 ++-
 .../src/controllers/ScriptingInterface.cpp    |  76 ++++----
 .../src/controllers/ScriptingInterface.h      |   5 +-
 .../controllers/impl/MappingBuilderProxy.cpp  |   7 +-
 .../controllers/impl/MappingBuilderProxy.h    |   1 +
 .../controllers/impl/RouteBuilderProxy.cpp    |   6 +
 .../src/controllers/impl/RouteBuilderProxy.h  |   1 +
 .../src/EntityTreeRenderer.cpp                |   3 +-
 .../render-utils/src/OffscreenQmlSurface.cpp  |   6 +
 .../render-utils/src/OffscreenQmlSurface.h    |   1 +
 .../src/AbstractScriptingServicesInterface.h  |  11 --
 libraries/script-engine/src/ScriptEngine.cpp  |  11 +-
 libraries/script-engine/src/ScriptEngine.h    |   2 -
 libraries/shared/src/DependencyManager.h      |  22 ++-
 tests/controllers/qml/content.qml             | 157 ----------------
 tests/controllers/qml/main.qml                |  10 +-
 tests/controllers/src/main.cpp                |  36 +++-
 33 files changed, 391 insertions(+), 297 deletions(-)
 rename {tests/controllers/qml/controls => interface/resources/qml}/ScrollingGraph.qml (98%)
 create mode 100644 interface/resources/qml/TestControllers.qml
 rename {tests/controllers/qml/controls => interface/resources/qml/controller}/AnalogButton.qml (95%)
 rename {tests/controllers/qml/controls => interface/resources/qml/controller}/AnalogStick.qml (92%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/Hydra.qml (94%)
 rename {tests/controllers/qml/controls => interface/resources/qml/controller}/ToggleButton.qml (93%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/Xbox.qml (95%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/hydra/HydraButtons.qml (91%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/hydra/HydraStick.qml (99%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/hydra/hydra.png (100%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/xbox/DPad.qml (96%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/xbox/LeftAnalogStick.qml (92%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/xbox/RightAnalogStick.qml (92%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/xbox/XboxButtons.qml (97%)
 rename {tests/controllers/qml => interface/resources/qml/controller}/xbox/xbox360-controller-md.png (100%)
 delete mode 100644 tests/controllers/qml/content.qml

diff --git a/tests/controllers/qml/controls/ScrollingGraph.qml b/interface/resources/qml/ScrollingGraph.qml
similarity index 98%
rename from tests/controllers/qml/controls/ScrollingGraph.qml
rename to interface/resources/qml/ScrollingGraph.qml
index 471d142d27..b5eaac6f89 100644
--- a/tests/controllers/qml/controls/ScrollingGraph.qml
+++ b/interface/resources/qml/ScrollingGraph.qml
@@ -22,7 +22,7 @@ Item {
     property string label: ""
 
     function update() {
-        value = Controllers.getValue(controlId);
+        value = Controller.getValue(controlId);
         canvas.requestPaint();
     }
 
diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
new file mode 100644
index 0000000000..388e452335
--- /dev/null
+++ b/interface/resources/qml/TestControllers.qml
@@ -0,0 +1,171 @@
+import QtQuick 2.3
+import QtQuick.Controls 1.2
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "controller"
+import "controls" as HifiControls
+import "styles"
+
+HifiControls.VrDialog {
+    id: root
+    HifiConstants { id: hifi }
+    title: "Controller Test"
+    resizable: true
+    contentImplicitWidth: clientArea.implicitWidth
+    contentImplicitHeight: clientArea.implicitHeight
+    backgroundColor: "beige"
+
+    property var actions: Controller.Actions
+    property var standard: Controller.Standard
+    property var hydra: null
+    property var testMapping: null
+    property var xbox: null
+
+
+    Component.onCompleted: {
+        enabled = true
+        var xboxRegex = /^X360Controller/;
+        var hydraRegex = /^Hydra/;
+        for (var prop in Controller.Hardware) {
+            if(xboxRegex.test(prop)) {
+                root.xbox = Controller.Hardware[prop]
+                print("found xbox")
+                continue
+            }
+            if (hydraRegex.test(prop)) {
+                root.hydra = Controller.Hardware[prop]
+                print("found hydra")
+                continue
+            }
+        }
+    }
+
+    Column {
+        id: clientArea
+        spacing: 12
+        x: root.clientX
+        y: root.clientY
+
+        Row {
+            spacing: 8
+            Button {
+                text: "Default Mapping"
+                onClicked: {
+                    var mapping = Controller.newMapping("Default");
+                    mapping.from(xbox.A).to(standard.A);
+                    mapping.from(xbox.B).to(standard.B);
+                    mapping.from(xbox.X).to(standard.X);
+                    mapping.from(xbox.Y).to(standard.Y);
+                    mapping.from(xbox.Up).to(standard.DU);
+                    mapping.from(xbox.Down).to(standard.DD);
+                    mapping.from(xbox.Left).to(standard.DL);
+                    mapping.from(xbox.Right).to(standard.Right);
+                    mapping.from(xbox.LB).to(standard.LB);
+                    mapping.from(xbox.RB).to(standard.RB);
+                    mapping.from(xbox.LS).to(standard.LS);
+                    mapping.from(xbox.RS).to(standard.RS);
+                    mapping.from(xbox.Start).to(standard.Start);
+                    mapping.from(xbox.Back).to(standard.Back);
+                    mapping.from(xbox.LY).to(standard.LY);
+                    mapping.from(xbox.LX).to(standard.LX);
+                    mapping.from(xbox.RY).to(standard.RY);
+                    mapping.from(xbox.RX).to(standard.RX);
+                    mapping.from(xbox.LT).to(standard.LT);
+                    mapping.from(xbox.RT).to(standard.RT);
+                    Controller.enableMapping("Default");
+                    enabled = false;
+                    text = "Built"
+                }
+            }
+
+            Button {
+                text: "Build Mapping"
+                onClicked: {
+                    var mapping = Controller.newMapping();
+                    // Inverting a value
+                    mapping.from(hydra.RY).invert().to(standard.RY);
+                    mapping.from(hydra.RX).to(standard.RX);
+                    mapping.from(hydra.LY).to(standard.LY);
+                    mapping.from(hydra.LY).to(standard.LX);
+                    // Assigning a value from a function
+                    // mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
+                    // Constrainting a value to -1, 0, or 1, with a deadzone
+//                    mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
+                    mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
+//                    mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
+//                    mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
+                    // mapping.modifier(keyboard.Ctrl).scale(2.0)
+//                    mapping.from(keyboard.A).to(actions.TranslateLeft)
+//                    mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
+//                    mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
+//                    // First loopbacks
+//                    // Then non-loopbacks by constraint level (number of inputs)
+//                    mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
+//                    mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
+//                    mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
+//                    mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
+                    testMapping = mapping;
+                    enabled = false
+                    text = "Built"
+                }
+            }
+
+            Button {
+                text: "Enable Mapping"
+                onClicked: root.testMapping.enable()
+            }
+
+            Button {
+                text: "Disable Mapping"
+                onClicked: root.testMapping.disable()
+            }
+
+            Button {
+                text: "Enable Mapping"
+                onClicked: print(Controller.getValue(root.xbox.LY));
+            }
+        }
+
+        Row {
+            Xbox { device: root.standard; label: "Standard"; width: 360 }
+        }
+        
+        Row {
+            spacing: 8
+            Xbox { device: root.xbox; label: "XBox"; width: 360 }
+            Hydra { device: root.hydra; width: 360 }
+        }
+//        Row {
+//            spacing: 8
+//            ScrollingGraph {
+//                controlId: Controller.Actions.Yaw
+//                label: "Yaw"
+//                min: -3.0
+//                max: 3.0
+//                size: 128
+//            }
+//
+//            ScrollingGraph {
+//                controlId: Controller.Actions.YAW_LEFT
+//                label: "Yaw Left"
+//                min: -3.0
+//                max: 3.0
+//                size: 128
+//            }
+//
+//            ScrollingGraph {
+//                controlId: Controller.Actions.YAW_RIGHT
+//                label: "Yaw Right"
+//                min: -3.0
+//                max: 3.0
+//                size: 128
+//            }
+//        }
+    }
+} // dialog
+
+
+
+
+
diff --git a/tests/controllers/qml/controls/AnalogButton.qml b/interface/resources/qml/controller/AnalogButton.qml
similarity index 95%
rename from tests/controllers/qml/controls/AnalogButton.qml
rename to interface/resources/qml/controller/AnalogButton.qml
index 141c131063..d027332d42 100644
--- a/tests/controllers/qml/controls/AnalogButton.qml
+++ b/interface/resources/qml/controller/AnalogButton.qml
@@ -13,7 +13,7 @@ Item {
     property color color: 'black'
 
     function update() {
-        value = Controllers.getValue(controlId);
+        value = Controller.getValue(controlId);
         canvas.requestPaint();
     }
 
diff --git a/tests/controllers/qml/controls/AnalogStick.qml b/interface/resources/qml/controller/AnalogStick.qml
similarity index 92%
rename from tests/controllers/qml/controls/AnalogStick.qml
rename to interface/resources/qml/controller/AnalogStick.qml
index 4e8ceb5736..499e0e9ce9 100644
--- a/tests/controllers/qml/controls/AnalogStick.qml
+++ b/interface/resources/qml/controller/AnalogStick.qml
@@ -17,8 +17,8 @@ Item {
 
     function update() {
         value = Qt.vector2d(
-            Controllers.getValue(controlIds[0]),
-            Controllers.getValue(controlIds[1])
+            Controller.getValue(controlIds[0]),
+            Controller.getValue(controlIds[1])
         );
         if (root.invertY) {
             value.y = value.y * -1.0
diff --git a/tests/controllers/qml/Hydra.qml b/interface/resources/qml/controller/Hydra.qml
similarity index 94%
rename from tests/controllers/qml/Hydra.qml
rename to interface/resources/qml/controller/Hydra.qml
index 5ef47c4d83..19f3b4c193 100644
--- a/tests/controllers/qml/Hydra.qml
+++ b/interface/resources/qml/controller/Hydra.qml
@@ -3,8 +3,7 @@ import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
 
-import "./hydra"
-import "./controls"
+import "hydra"
 
 Item {
     id: root
diff --git a/tests/controllers/qml/controls/ToggleButton.qml b/interface/resources/qml/controller/ToggleButton.qml
similarity index 93%
rename from tests/controllers/qml/controls/ToggleButton.qml
rename to interface/resources/qml/controller/ToggleButton.qml
index 46a7b4bdfd..6481045dd0 100644
--- a/tests/controllers/qml/controls/ToggleButton.qml
+++ b/interface/resources/qml/controller/ToggleButton.qml
@@ -15,7 +15,7 @@ Item {
     Timer {
         interval: 50; running: true; repeat: true
         onTriggered: {
-            root.value = Controllers.getValue(root.controlId);
+            root.value = Controller.getValue(root.controlId);
             canvas.requestPaint();
         }
     }
diff --git a/tests/controllers/qml/Xbox.qml b/interface/resources/qml/controller/Xbox.qml
similarity index 95%
rename from tests/controllers/qml/Xbox.qml
rename to interface/resources/qml/controller/Xbox.qml
index bc9acd5a43..165ac596fe 100644
--- a/tests/controllers/qml/Xbox.qml
+++ b/interface/resources/qml/controller/Xbox.qml
@@ -3,8 +3,7 @@ import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
 
-import "./xbox"
-import "./controls"
+import "xbox"
 
 Item {
     id: root
diff --git a/tests/controllers/qml/hydra/HydraButtons.qml b/interface/resources/qml/controller/hydra/HydraButtons.qml
similarity index 91%
rename from tests/controllers/qml/hydra/HydraButtons.qml
rename to interface/resources/qml/controller/hydra/HydraButtons.qml
index 6c3070d2b1..aa8927f5b6 100644
--- a/tests/controllers/qml/hydra/HydraButtons.qml
+++ b/interface/resources/qml/controller/hydra/HydraButtons.qml
@@ -3,7 +3,7 @@ import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
 
-import "./../controls"
+import ".."
 
 Item {
     id: root
diff --git a/tests/controllers/qml/hydra/HydraStick.qml b/interface/resources/qml/controller/hydra/HydraStick.qml
similarity index 99%
rename from tests/controllers/qml/hydra/HydraStick.qml
rename to interface/resources/qml/controller/hydra/HydraStick.qml
index 3c22789f6d..d082a20b10 100644
--- a/tests/controllers/qml/hydra/HydraStick.qml
+++ b/interface/resources/qml/controller/hydra/HydraStick.qml
@@ -3,7 +3,7 @@ import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
 
-import "./../controls"
+import ".."
 
 Item {
     id: root
diff --git a/tests/controllers/qml/hydra/hydra.png b/interface/resources/qml/controller/hydra/hydra.png
similarity index 100%
rename from tests/controllers/qml/hydra/hydra.png
rename to interface/resources/qml/controller/hydra/hydra.png
diff --git a/tests/controllers/qml/xbox/DPad.qml b/interface/resources/qml/controller/xbox/DPad.qml
similarity index 96%
rename from tests/controllers/qml/xbox/DPad.qml
rename to interface/resources/qml/controller/xbox/DPad.qml
index 8efe6c2b30..2cfb6412e7 100644
--- a/tests/controllers/qml/xbox/DPad.qml
+++ b/interface/resources/qml/controller/xbox/DPad.qml
@@ -3,8 +3,7 @@ import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
 
-import "./../controls"
-
+import ".."
 
 Item {
     id: root
diff --git a/tests/controllers/qml/xbox/LeftAnalogStick.qml b/interface/resources/qml/controller/xbox/LeftAnalogStick.qml
similarity index 92%
rename from tests/controllers/qml/xbox/LeftAnalogStick.qml
rename to interface/resources/qml/controller/xbox/LeftAnalogStick.qml
index ed2689e7c8..8e2de1eb36 100644
--- a/tests/controllers/qml/xbox/LeftAnalogStick.qml
+++ b/interface/resources/qml/controller/xbox/LeftAnalogStick.qml
@@ -3,7 +3,7 @@ import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
 
-import "./../controls"
+import ".."
 
 Item {
     id: root
diff --git a/tests/controllers/qml/xbox/RightAnalogStick.qml b/interface/resources/qml/controller/xbox/RightAnalogStick.qml
similarity index 92%
rename from tests/controllers/qml/xbox/RightAnalogStick.qml
rename to interface/resources/qml/controller/xbox/RightAnalogStick.qml
index 611b4d8f92..0cdfeda2cf 100644
--- a/tests/controllers/qml/xbox/RightAnalogStick.qml
+++ b/interface/resources/qml/controller/xbox/RightAnalogStick.qml
@@ -3,7 +3,7 @@ import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
 
-import "./../controls"
+import ".."
 
 Item {
     id: root
diff --git a/tests/controllers/qml/xbox/XboxButtons.qml b/interface/resources/qml/controller/xbox/XboxButtons.qml
similarity index 97%
rename from tests/controllers/qml/xbox/XboxButtons.qml
rename to interface/resources/qml/controller/xbox/XboxButtons.qml
index 4a9e87799e..e26a4a0b98 100644
--- a/tests/controllers/qml/xbox/XboxButtons.qml
+++ b/interface/resources/qml/controller/xbox/XboxButtons.qml
@@ -3,7 +3,7 @@ import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
 
-import "./../controls"
+import ".."
 
 Item {
     id: root
diff --git a/tests/controllers/qml/xbox/xbox360-controller-md.png b/interface/resources/qml/controller/xbox/xbox360-controller-md.png
similarity index 100%
rename from tests/controllers/qml/xbox/xbox360-controller-md.png
rename to interface/resources/qml/controller/xbox/xbox360-controller-md.png
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index c01e89c6d9..b0c0109b71 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -17,27 +17,32 @@
 #include <glm/gtx/vector_angle.hpp>
 #include <glm/gtc/type_ptr.hpp>
 
-#include <QAbstractNativeEventFilter>
-#include <QActionGroup>
-#include <QDebug>
-#include <QDesktopServices>
-#include <QDesktopWidget>
-#include <QImage>
-#include <QFileDialog>
-#include <QInputDialog>
-#include <QKeyEvent>
-#include <QMediaPlayer>
-#include <QMenuBar>
-#include <QMessageBox>
-#include <QMimeData>
-#include <QMouseEvent>
-#include <QNetworkDiskCache>
-#include <QObject>
-#include <QScreen>
-#include <QTimer>
-#include <QUrl>
-#include <QWheelEvent>
-#include <QWindow>
+#include <QtCore/QDebug>
+#include <QtCore/QObject>
+#include <QtCore/QUrl>
+#include <QtCore/QTimer>
+#include <QtCore/QAbstractNativeEventFilter>
+#include <QtCore/QMimeData>
+
+#include <QtGui/QScreen>
+#include <QtGui/QImage>
+#include <QtGui/QWheelEvent>
+#include <QtGui/QWindow>
+#include <QtQml/QQmlContext>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QDesktopServices>
+
+#include <QtWidgets/QActionGroup>
+#include <QtWidgets/QDesktopWidget>
+#include <QtWidgets/QFileDialog>
+#include <QtWidgets/QInputDialog>
+#include <QtWidgets/QMenuBar>
+#include <QtWidgets/QMessageBox>
+
+#include <QtMultimedia/QMediaPlayer>
+
+#include <QtNetwork/QNetworkDiskCache>
 
 #include <AccountManager.h>
 #include <AddressManager.h>
@@ -120,6 +125,7 @@
 #include "scripting/SettingsScriptingInterface.h"
 #include "scripting/WebWindowClass.h"
 #include "scripting/WindowScriptingInterface.h"
+#include "scripting/ControllerScriptingInterface.h"
 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
 #include "SpeechRecognizer.h"
 #endif
@@ -316,6 +322,7 @@ bool setupEssentials(int& argc, char** argv) {
     DependencyManager::set<EntityScriptingInterface>();
     DependencyManager::set<WindowScriptingInterface>();
     DependencyManager::set<HMDScriptingInterface>();
+
 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
     DependencyManager::set<SpeechRecognizer>();
 #endif
@@ -327,7 +334,7 @@ bool setupEssentials(int& argc, char** argv) {
     DependencyManager::set<InterfaceActionFactory>();
     DependencyManager::set<AssetClient>();
     DependencyManager::set<UserInputMapper>();
-
+    DependencyManager::set<controller::ScriptingInterface, ControllerScriptingInterface>();
     return true;
 }
 
@@ -374,6 +381,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     
     setInstance(this);
     
+    auto controllerScriptingInterface = DependencyManager::get<controller::ScriptingInterface>().data();
+    _controllerScriptingInterface = dynamic_cast<ControllerScriptingInterface*>(controllerScriptingInterface);
     // to work around the Qt constant wireless scanning, set the env for polling interval very high
     const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT_MAX).toLocal8Bit();
     qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
@@ -618,7 +627,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
 
     // Setup the userInputMapper with the actions
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    connect(userInputMapper.data(), &UserInputMapper::actionEvent, &_controllerScriptingInterface, &ControllerScriptingInterface::actionEvent);
+    connect(userInputMapper.data(), &UserInputMapper::actionEvent, _controllerScriptingInterface, &ControllerScriptingInterface::actionEvent);
     connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
         if (state) {
             switch (action) {
@@ -975,6 +984,8 @@ void Application::initializeUi() {
     offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
     offscreenUi->load("Root.qml");
     offscreenUi->load("RootMenu.qml");
+    auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
+    offscreenUi->getRootContext()->setContextProperty("Controller", scriptingInterface.data());
     _glWidget->installEventFilter(offscreenUi.data());
     VrMenu::load();
     VrMenu::executeQueuedLambdas();
@@ -1456,7 +1467,7 @@ bool Application::event(QEvent* event) {
     }
 
     if (HFActionEvent::types().contains(event->type())) {
-        _controllerScriptingInterface.handleMetaEvent(static_cast<HFMetaEvent*>(event));
+        _controllerScriptingInterface->handleMetaEvent(static_cast<HFMetaEvent*>(event));
     }
 
     return QApplication::event(event);
@@ -1470,7 +1481,7 @@ bool Application::eventFilter(QObject* object, QEvent* event) {
         }
 
         // Filter out captured keys before they're used for shortcut actions.
-        if (_controllerScriptingInterface.isKeyCaptured(static_cast<QKeyEvent*>(event))) {
+        if (_controllerScriptingInterface->isKeyCaptured(static_cast<QKeyEvent*>(event))) {
             event->accept();
             return true;
         }
@@ -1485,10 +1496,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
     _altPressed = event->key() == Qt::Key_Alt;
     _keysPressed.insert(event->key());
 
-    _controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts
+    _controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts
 
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isKeyCaptured(event)) {
+    if (_controllerScriptingInterface->isKeyCaptured(event)) {
         return;
     }
 
@@ -1518,6 +1529,13 @@ void Application::keyPressEvent(QKeyEvent* event) {
                 if (isMeta) {
                     auto offscreenUi = DependencyManager::get<OffscreenUi>();
                     offscreenUi->load("Browser.qml");
+                } 
+                break;
+
+            case Qt::Key_X:
+                if (isMeta && isShifted) {
+                    auto offscreenUi = DependencyManager::get<OffscreenUi>();
+                    offscreenUi->load("TestControllers.qml");
                 }
                 break;
 
@@ -1752,10 +1770,10 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
 
     _keysPressed.remove(event->key());
 
-    _controllerScriptingInterface.emitKeyReleaseEvent(event); // send events to any registered scripts
+    _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts
 
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isKeyCaptured(event)) {
+    if (_controllerScriptingInterface->isKeyCaptured(event)) {
         return;
     }
 
@@ -1844,10 +1862,10 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
 
 
     _entities.mouseMoveEvent(&mappedEvent, deviceID);
-    _controllerScriptingInterface.emitMouseMoveEvent(&mappedEvent, deviceID); // send events to any registered scripts
+    _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent, deviceID); // send events to any registered scripts
 
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isMouseCaptured()) {
+    if (_controllerScriptingInterface->isMouseCaptured()) {
         return;
     }
 
@@ -1872,10 +1890,10 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
         _entities.mousePressEvent(&mappedEvent, deviceID);
     }
 
-    _controllerScriptingInterface.emitMousePressEvent(&mappedEvent); // send events to any registered scripts
+    _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts
 
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isMouseCaptured()) {
+    if (_controllerScriptingInterface->isMouseCaptured()) {
         return;
     }
 
@@ -1897,11 +1915,11 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
 
 void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID) {
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isMouseCaptured()) {
+    if (_controllerScriptingInterface->isMouseCaptured()) {
         return;
     }
 
-    _controllerScriptingInterface.emitMouseDoublePressEvent(event);
+    _controllerScriptingInterface->emitMouseDoublePressEvent(event);
 }
 
 void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
@@ -1917,10 +1935,10 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
         _entities.mouseReleaseEvent(&mappedEvent, deviceID);
     }
 
-    _controllerScriptingInterface.emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
+    _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
 
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isMouseCaptured()) {
+    if (_controllerScriptingInterface->isMouseCaptured()) {
         return;
     }
 
@@ -1943,12 +1961,12 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
 
     if (event->type() == QEvent::TouchUpdate) {
         TouchEvent thisEvent(*event, _lastTouchEvent);
-        _controllerScriptingInterface.emitTouchUpdateEvent(thisEvent); // send events to any registered scripts
+        _controllerScriptingInterface->emitTouchUpdateEvent(thisEvent); // send events to any registered scripts
         _lastTouchEvent = thisEvent;
     }
 
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isTouchCaptured()) {
+    if (_controllerScriptingInterface->isTouchCaptured()) {
         return;
     }
 
@@ -1960,13 +1978,13 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
 void Application::touchBeginEvent(QTouchEvent* event) {
     _altPressed = false;
     TouchEvent thisEvent(*event); // on touch begin, we don't compare to last event
-    _controllerScriptingInterface.emitTouchBeginEvent(thisEvent); // send events to any registered scripts
+    _controllerScriptingInterface->emitTouchBeginEvent(thisEvent); // send events to any registered scripts
 
     _lastTouchEvent = thisEvent; // and we reset our last event to this event before we call our update
     touchUpdateEvent(event);
 
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isTouchCaptured()) {
+    if (_controllerScriptingInterface->isTouchCaptured()) {
         return;
     }
 
@@ -1979,11 +1997,11 @@ void Application::touchBeginEvent(QTouchEvent* event) {
 void Application::touchEndEvent(QTouchEvent* event) {
     _altPressed = false;
     TouchEvent thisEvent(*event, _lastTouchEvent);
-    _controllerScriptingInterface.emitTouchEndEvent(thisEvent); // send events to any registered scripts
+    _controllerScriptingInterface->emitTouchEndEvent(thisEvent); // send events to any registered scripts
     _lastTouchEvent = thisEvent;
 
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isTouchCaptured()) {
+    if (_controllerScriptingInterface->isTouchCaptured()) {
         return;
     }
 
@@ -1996,10 +2014,10 @@ void Application::touchEndEvent(QTouchEvent* event) {
 
 void Application::wheelEvent(QWheelEvent* event) {
     _altPressed = false;
-    _controllerScriptingInterface.emitWheelEvent(event); // send events to any registered scripts
+    _controllerScriptingInterface->emitWheelEvent(event); // send events to any registered scripts
 
     // if one of our scripts have asked to capture this event, then stop processing it
-    if (_controllerScriptingInterface.isWheelCaptured()) {
+    if (_controllerScriptingInterface->isWheelCaptured()) {
         return;
     }
     
@@ -2709,12 +2727,12 @@ void Application::update(float deltaTime) {
     }
 
     // Dispatch input events
-    _controllerScriptingInterface.update();
+    _controllerScriptingInterface->update();
 
     // Transfer the user inputs to the driveKeys
     myAvatar->clearDriveKeys();
     if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
-        if (!_controllerScriptingInterface.areActionsCaptured()) {
+        if (!_controllerScriptingInterface->areActionsCaptured()) {
             myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
             myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
             myAvatar->setDriveKeys(UP, userInputMapper->getActionState(UserInputMapper::VERTICAL_UP));
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 61421c34d6..829265c9fb 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -14,13 +14,15 @@
 
 #include <functional>
 
-#include <QApplication>
-#include <QHash>
-#include <QImage>
-#include <QPointer>
-#include <QSet>
-#include <QStringList>
-#include <QUndoStack>
+#include <QtCore/QHash>
+#include <QtCore/QPointer>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+
+#include <QtGui/QImage>
+
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QUndoStack>
 
 #include <AbstractScriptingServicesInterface.h>
 #include <AbstractViewStateInterface.h>
@@ -161,7 +163,7 @@ public:
 
     ToolWindow* getToolWindow() { return _toolWindow ; }
 
-    virtual controller::ScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; }
+    virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
     virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine);
 
     QImage renderAvatarBillboard(RenderArgs* renderArgs);
@@ -474,8 +476,7 @@ private:
 
     NodeToJurisdictionMap _entityServerJurisdictions;
     NodeToOctreeSceneStats _octreeServerSceneStats;
-
-    ControllerScriptingInterface _controllerScriptingInterface;
+    ControllerScriptingInterface* _controllerScriptingInterface{ nullptr };
     QPointer<LogDialog> _logDialog;
     QPointer<SnapshotShareDialog> _snapshotShareDialog;
 
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 9f9ca85dd4..6d4ad1a566 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -26,7 +26,6 @@
 #include "Logging.h"
 #include "InputDevice.h"
 
-
 namespace controller {
 
     class VirtualEndpoint : public Endpoint {
@@ -144,39 +143,9 @@ namespace controller {
         }
         return deviceMap;
     }
+    
 
-    ScriptingInterface::ScriptingInterface() {
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        qCDebug(controllers) << "Setting up standard controller abstraction";
-        auto standardDevice = userInputMapper->getStandardDevice();
-        // Expose the IDs to JS
-        _standard = createDeviceMap(standardDevice.get());
-        // Create the endpoints
-        for (const auto& inputMapping : standardDevice->getAvailabeInputs()) {
-            const auto& standardInput = inputMapping.first;
-            // Ignore aliases
-            if (_endpoints.count(standardInput)) {
-                continue;
-            }
-            _endpoints[standardInput] = std::make_shared<VirtualEndpoint>(standardInput);
-        }
-
-        // FIXME allow custom user actions?
-        auto actionNames = userInputMapper->getActionNames();
-        int actionNumber = 0;
-        qCDebug(controllers) << "Setting up standard actions";
-        for (const auto& actionName : actionNames) {
-            UserInputMapper::Input actionInput(UserInputMapper::Input::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
-            qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16);
-            // Expose the IDs to JS
-            QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
-            _actions.insert(cleanActionName, actionInput.getID());
-
-            // Create the action endpoints
-            _endpoints[actionInput] = std::make_shared<ActionEndpoint>(actionInput);
-        }
-
-        updateMaps();
+    ScriptingInterface::~ScriptingInterface() {
     }
 
     QObject* ScriptingInterface::newMapping(const QString& mappingName) {
@@ -235,7 +204,7 @@ namespace controller {
             if (request->getResult() == ResourceRequest::Success) {
                 result = parseMapping(QString(request->getData()));
             } else {
-                qDebug() << "Failed to load mapping url <" << jsonUrl << ">" << endl;
+                qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl;
             }
             request->deleteLater();
         }
@@ -245,6 +214,7 @@ namespace controller {
     Q_INVOKABLE QObject* newMapping(const QJsonObject& json);
 
     void ScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
+        qCDebug(controllers) << "Attempting to enable mapping " << mappingName;
         auto iterator = _mappingsByName.find(mappingName);
         if (_mappingsByName.end() == iterator) {
             qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName;
@@ -524,9 +494,45 @@ namespace controller {
             }
         }
     }
-
 } // namespace controllers
 
+
+using namespace controller;
+// FIXME this throws a hissy fit on MSVC if I put it in the main controller namespace block
+ScriptingInterface::ScriptingInterface() {
+    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    qCDebug(controllers) << "Setting up standard controller abstraction";
+    auto standardDevice = userInputMapper->getStandardDevice();
+    // Expose the IDs to JS
+    _standard = createDeviceMap(standardDevice.get());
+    // Create the endpoints
+    for (const auto& inputMapping : standardDevice->getAvailabeInputs()) {
+        const auto& standardInput = inputMapping.first;
+        // Ignore aliases
+        if (_endpoints.count(standardInput)) {
+            continue;
+        }
+        _endpoints[standardInput] = std::make_shared<VirtualEndpoint>(standardInput);
+    }
+
+    // FIXME allow custom user actions?
+    auto actionNames = userInputMapper->getActionNames();
+    int actionNumber = 0;
+    qCDebug(controllers) << "Setting up standard actions";
+    for (const auto& actionName : actionNames) {
+        UserInputMapper::Input actionInput(UserInputMapper::Input::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
+        qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16);
+        // Expose the IDs to JS
+        QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
+        _actions.insert(cleanActionName, actionInput.getID());
+
+        // Create the action endpoints
+        _endpoints[actionInput] = std::make_shared<ActionEndpoint>(actionInput);
+    }
+
+    updateMaps();
+}
+
 //var mapping = Controller.newMapping();
 //mapping.map(hydra.LeftButton0, actions.ContextMenu);
 //mapping.map(hydra.LeftButton0).to(xbox.RT);
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index 07ddd625f5..ef9d61c32d 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -28,6 +28,8 @@
 #include <QtQml/QJSValue>
 #include <QtScript/QScriptValue>
 
+#include <DependencyManager.h>
+
 #include "UserInputMapper.h"
 #include "StandardControls.h"
 #include "Mapping.h"
@@ -55,7 +57,7 @@ namespace controller {
     };
 
     /// handles scripting of input controller commands from JS
-    class ScriptingInterface : public QObject {
+    class ScriptingInterface : public QObject, public Dependency {
         Q_OBJECT
         Q_PROPERTY(QVariantMap Hardware READ getHardware CONSTANT FINAL)
         Q_PROPERTY(QVariantMap Actions READ getActions CONSTANT FINAL)
@@ -63,6 +65,7 @@ namespace controller {
 
     public:
         ScriptingInterface();
+        virtual ~ScriptingInterface();
 
         Q_INVOKABLE float getValue(const int& source) const;
         Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index c6031d45d2..e75068b311 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -14,13 +14,18 @@
 #include <QtCore/QJsonObject>
 #include <QtCore/QJsonArray>
 
-
 #include "RouteBuilderProxy.h"
 #include "../ScriptingInterface.h"
 #include "../Logging.h"
 
 using namespace controller;
 
+QObject* MappingBuilderProxy::from(int input) {
+    qCDebug(controllers) << "Creating new Route builder proxy from " << input;
+    auto sourceEndpoint = _parent.endpointFor(UserInputMapper::Input(input));
+    return from(sourceEndpoint);
+}
+
 QObject* MappingBuilderProxy::from(const QJSValue& source) {
     qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString();
     auto sourceEndpoint = _parent.endpointFor(source);
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index a29f7ade39..53db901436 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -31,6 +31,7 @@ public:
     MappingBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping)
         : _parent(parent), _mapping(mapping) { }
 
+    Q_INVOKABLE QObject* from(int sourceInput);
     Q_INVOKABLE QObject* from(const QJSValue& source);
     Q_INVOKABLE QObject* from(const QScriptValue& source);
     Q_INVOKABLE QObject* makeAxis(const QJSValue& source1, const QJSValue& source2);
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index 033e94daa0..ba2cd60c8b 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -20,6 +20,12 @@
 
 namespace controller {
 
+void RouteBuilderProxy::to(int destinationInput) {
+    qCDebug(controllers) << "Completing route " << destinationInput;
+    auto destinationEndpoint = _parent.endpointFor(UserInputMapper::Input(destinationInput));
+    return to(destinationEndpoint);
+}
+
 void RouteBuilderProxy::to(const QJSValue& destination) {
     qCDebug(controllers) << "Completing route " << destination.toString();
     auto destinationEndpoint = _parent.endpointFor(destination);
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 6fd5f1467a..8e3b3404cc 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -30,6 +30,7 @@ class RouteBuilderProxy : public QObject {
         RouteBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route)
             : _parent(parent), _mapping(mapping), _route(route) { }
 
+        Q_INVOKABLE void to(int destination);
         Q_INVOKABLE void to(const QJSValue& destination);
         Q_INVOKABLE void to(const QScriptValue& destination);
 
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index 8f316af276..5ac8ce8f13 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -106,8 +106,7 @@ void EntityTreeRenderer::init() {
     entityTree->setFBXService(this);
 
     if (_wantScripts) {
-        _entitiesScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities",
-                                        _scriptingServices->getControllerScriptingInterface());
+        _entitiesScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities");
         _scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
         _entitiesScriptEngine->runInThread();
         DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(_entitiesScriptEngine);
diff --git a/libraries/render-utils/src/OffscreenQmlSurface.cpp b/libraries/render-utils/src/OffscreenQmlSurface.cpp
index 6c68b60f42..b53ff37436 100644
--- a/libraries/render-utils/src/OffscreenQmlSurface.cpp
+++ b/libraries/render-utils/src/OffscreenQmlSurface.cpp
@@ -19,6 +19,7 @@
 #include <QMutex>
 
 #include <PerfStat.h>
+#include <DependencyManager.h>
 #include <NumericalConstants.h>
 
 #include "GLEscrow.h"
@@ -614,3 +615,8 @@ QQuickWindow* OffscreenQmlSurface::getWindow() {
 QSize OffscreenQmlSurface::size() const {
     return _renderer->_quickWindow->geometry().size();
 }
+
+QQmlContext* OffscreenQmlSurface::getRootContext() {
+    return _qmlEngine->rootContext();
+}
+
diff --git a/libraries/render-utils/src/OffscreenQmlSurface.h b/libraries/render-utils/src/OffscreenQmlSurface.h
index 01dd2b88f9..67315b0783 100644
--- a/libraries/render-utils/src/OffscreenQmlSurface.h
+++ b/libraries/render-utils/src/OffscreenQmlSurface.h
@@ -60,6 +60,7 @@ public:
     QQuickItem* getRootItem();
     QQuickWindow* getWindow();
     QObject* getEventHandler();
+    QQmlContext* getRootContext();
 
     QPointF mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget);
     virtual bool eventFilter(QObject* originalDestination, QEvent* event);
diff --git a/libraries/script-engine/src/AbstractScriptingServicesInterface.h b/libraries/script-engine/src/AbstractScriptingServicesInterface.h
index 565a415f63..de18338fca 100644
--- a/libraries/script-engine/src/AbstractScriptingServicesInterface.h
+++ b/libraries/script-engine/src/AbstractScriptingServicesInterface.h
@@ -12,24 +12,13 @@
 #ifndef hifi_AbstractScriptingServicesInterface_h
 #define hifi_AbstractScriptingServicesInterface_h
 
-namespace controller {
-    class ScriptingInterface;
-}
-
-class Transform;
 class ScriptEngine;
-class QThread;
 
 /// Interface provided by Application to other objects that need access to scripting services of the application
 class AbstractScriptingServicesInterface {
 public:
-    
-    /// Returns the controller interface for the application
-    virtual controller::ScriptingInterface* getControllerScriptingInterface() = 0;
-
     /// Registers application specific services with a script engine.
     virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) = 0;
-
 };
 
 
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 494f038a61..0dfc2fe09e 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -84,8 +84,7 @@ void inputControllerFromScriptValue(const QScriptValue &object, controller::Inpu
     out = qobject_cast<controller::InputController*>(object.toQObject());
 }
 
-ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
-    controller::ScriptingInterface* controllerScriptingInterface, bool wantSignals) :
+ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) :
 
     _scriptContents(scriptContents),
     _isFinished(false),
@@ -93,7 +92,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
     _isInitialized(false),
     _timerFunctionMap(),
     _wantSignals(wantSignals),
-    _controllerScriptingInterface(controllerScriptingInterface), 
     _fileNameString(fileNameString),
     _quatLibrary(),
     _vec3Library(),
@@ -310,7 +308,8 @@ void ScriptEngine::init() {
 
     registerGlobalObject("Script", this);
     registerGlobalObject("Audio", &AudioScriptingInterface::getInstance());
-    registerGlobalObject("Controller", _controllerScriptingInterface);
+    auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
+    registerGlobalObject("Controller", scriptingInterface.data());
     registerGlobalObject("Entities", entityScriptingInterface.data());
     registerGlobalObject("Quat", &_quatLibrary);
     registerGlobalObject("Vec3", &_vec3Library);
@@ -320,8 +319,8 @@ void ScriptEngine::init() {
     // constants
     globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
 
-    if (_controllerScriptingInterface) {
-        _controllerScriptingInterface->registerControllerTypes(this);
+    if (scriptingInterface) {
+        scriptingInterface->registerControllerTypes(this);
     }
 
 
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index 642159339e..5a0fb64ae2 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -55,7 +55,6 @@ class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScr
 public:
     ScriptEngine(const QString& scriptContents = NO_SCRIPT,
                  const QString& fileNameString = QString(""),
-                 controller::ScriptingInterface* controllerScriptingInterface = nullptr,
                  bool wantSignals = true);
 
     ~ScriptEngine();
@@ -184,7 +183,6 @@ private:
     QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot);
     void stopTimer(QTimer* timer);
 
-    controller::ScriptingInterface* _controllerScriptingInterface;
     QString _fileNameString;
     Quat _quatLibrary;
     Vec3 _vec3Library;
diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h
index 01b755fdd0..db41e72e1e 100644
--- a/libraries/shared/src/DependencyManager.h
+++ b/libraries/shared/src/DependencyManager.h
@@ -51,7 +51,10 @@ public:
     
     template<typename T, typename ...Args>
     static QSharedPointer<T> set(Args&&... args);
-    
+
+    template<typename T, typename I, typename ...Args>
+    static QSharedPointer<T> set(Args&&... args);
+
     template<typename T>
     static void destroy();
     
@@ -89,13 +92,26 @@ QSharedPointer<T> DependencyManager::get() {
 template <typename T, typename ...Args>
 QSharedPointer<T> DependencyManager::set(Args&&... args) {
     static size_t hashCode = _manager.getHashCode<T>();
-    
+
     QSharedPointer<Dependency>& instance = _manager.safeGet(hashCode);
     instance.clear(); // Clear instance before creation of new one to avoid edge cases
     QSharedPointer<T> newInstance(new T(args...), &T::customDeleter);
     QSharedPointer<Dependency> storedInstance = qSharedPointerCast<Dependency>(newInstance);
     instance.swap(storedInstance);
-    
+
+    return newInstance;
+}
+
+template <typename T, typename I, typename ...Args>
+QSharedPointer<T> DependencyManager::set(Args&&... args) {
+    static size_t hashCode = _manager.getHashCode<T>();
+
+    QSharedPointer<Dependency>& instance = _manager.safeGet(hashCode);
+    instance.clear(); // Clear instance before creation of new one to avoid edge cases
+    QSharedPointer<T> newInstance(new I(args...), &I::customDeleter);
+    QSharedPointer<Dependency> storedInstance = qSharedPointerCast<Dependency>(newInstance);
+    instance.swap(storedInstance);
+
     return newInstance;
 }
 
diff --git a/tests/controllers/qml/content.qml b/tests/controllers/qml/content.qml
deleted file mode 100644
index 5d81ead2fd..0000000000
--- a/tests/controllers/qml/content.qml
+++ /dev/null
@@ -1,157 +0,0 @@
-import QtQuick 2.1
-import QtQuick.Controls 1.0
-import QtQuick.Layouts 1.0
-import QtQuick.Dialogs 1.0
-
-import "./xbox"
-import "./controls"
-
-Column {
-    id: root
-    property var actions: Controllers.Actions
-    property var standard: Controllers.Standard
-    property var hydra: null
-    property var testMapping: null
-    property var xbox: null
-
-
-    Component.onCompleted: {
-        var xboxRegex = /^X360Controller/;
-        var hydraRegex = /^Hydra/;
-        for (var prop in Controllers.Hardware) {
-            if(xboxRegex.test(prop)) {
-                root.xbox = Controllers.Hardware[prop]
-                print("found xbox")
-                continue
-            }
-            if (hydraRegex.test(prop)) {
-                root.hydra = Controllers.Hardware[prop]
-                print("found hydra")
-                continue
-            }
-        }
-    }
-
-    spacing: 12
-
-    Timer {
-        interval: 50; running: true; repeat: true
-        onTriggered: {
-            Controllers.update();
-        }
-    }
-
-    Row {
-        spacing: 8
-        Button {
-            text: "Default Mapping"
-            onClicked: {
-                var mapping = Controllers.newMapping("Default");
-                mapping.from(xbox.A).to(standard.A);
-                mapping.from(xbox.B).to(standard.B);
-                mapping.from(xbox.X).to(standard.X);
-                mapping.from(xbox.Y).to(standard.Y);
-                mapping.from(xbox.Up).to(standard.DU);
-                mapping.from(xbox.Down).to(standard.DD);
-                mapping.from(xbox.Left).to(standard.DL);
-                mapping.from(xbox.Right).to(standard.Right);
-                mapping.from(xbox.LB).to(standard.LB);
-                mapping.from(xbox.RB).to(standard.RB);
-                mapping.from(xbox.LS).to(standard.LS);
-                mapping.from(xbox.RS).to(standard.RS);
-                mapping.from(xbox.Start).to(standard.Start);
-                mapping.from(xbox.Back).to(standard.Back);
-                mapping.from(xbox.LY).to(standard.LY);
-                mapping.from(xbox.LX).to(standard.LX);
-                mapping.from(xbox.RY).to(standard.RY);
-                mapping.from(xbox.RX).to(standard.RX);
-                mapping.from(xbox.LT).to(standard.LT);
-                mapping.from(xbox.RT).to(standard.RT);
-                Controllers.enableMapping("Default");
-                enabled = false;
-                text = "Built"
-            }
-        }
-
-        Button {
-            text: "Build Mapping"
-            onClicked: {
-                var mapping = Controllers.newMapping();
-                // Inverting a value
-                mapping.from(xbox.RY).invert().to(standard.RY);
-                // Assigning a value from a function
-                mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
-                // Constrainting a value to -1, 0, or 1, with a deadzone
-                mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
-                mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
-                mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
-                mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
-                // mapping.modifier(keyboard.Ctrl).scale(2.0)
-//                mapping.from(keyboard.A).to(actions.TranslateLeft)
-//                mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
-//                mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
-//                // First loopbacks
-//                // Then non-loopbacks by constraint level (number of inputs)
-//                mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
-//                mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
-//                mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
-//                mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
-                testMapping = mapping;
-                enabled = false
-                text = "Built"
-            }
-        }
-
-        Button {
-            text: "Enable Mapping"
-            onClicked: root.testMapping.enable()
-        }
-
-        Button {
-            text: "Disable Mapping"
-            onClicked: root.testMapping.disable()
-        }
-    }
-
-    Row {
-        Xbox { device: root.standard; label: "Standard"; width: 360 }
-    }
-    
-    Row {
-        spacing: 8
-        Xbox { device: root.xbox; label: "XBox"; width: 360 }
-    }
-
-    Row {
-        spacing: 8
-        Hydra { device: root.hydra; width: 360 }
-    }
-
-    Row {
-        spacing: 8
-        ScrollingGraph {
-            controlId: Controllers.Actions.Yaw
-            label: "Yaw"
-            min: -3.0
-            max: 3.0
-            size: 128
-        }
-
-        ScrollingGraph {
-            controlId: Controllers.Actions.YAW_LEFT
-            label: "Yaw Left"
-            min: -3.0
-            max: 3.0
-            size: 128
-        }
-
-        ScrollingGraph {
-            controlId: Controllers.Actions.YAW_RIGHT
-            label: "Yaw Right"
-            min: -3.0
-            max: 3.0
-            size: 128
-        }
-    }
-}
-
diff --git a/tests/controllers/qml/main.qml b/tests/controllers/qml/main.qml
index 5ed68cc1fb..66060399a6 100644
--- a/tests/controllers/qml/main.qml
+++ b/tests/controllers/qml/main.qml
@@ -7,8 +7,16 @@ ApplicationWindow {
     id: window
     visible: true
 
+    Timer {
+        interval: 50; running: true; repeat: true
+        onTriggered: {
+            Controller.update();
+        }
+    }
+
+
     Loader {
         id: pageLoader
-        source: "content.qml"
+        source: ResourcePath + "TestControllers.qml"
     }
 }
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index 0c5ef09867..ccd670640c 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -43,17 +43,37 @@
 #include <DependencyManager.h>
 #include <controllers/UserInputMapper.h>
 
-const QString& getQmlDir() {
+const QString& getResourcesDir() {
     static QString dir;
     if (dir.isEmpty()) {
         QDir path(__FILE__);
         path.cdUp();
-        dir = path.cleanPath(path.absoluteFilePath("../qml/")) + "/";
+        dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/";
+        qDebug() << "Resources Path: " << dir;
+    }
+    return dir;
+}
+
+const QString& getQmlDir() {
+    static QString dir;
+    if (dir.isEmpty()) {
+        dir = getResourcesDir() + "qml/";
         qDebug() << "Qml Path: " << dir;
     }
     return dir;
 }
 
+const QString& getTestQmlDir() {
+    static QString dir;
+    if (dir.isEmpty()) {
+        QDir path(__FILE__);
+        path.cdUp();
+        dir = path.cleanPath(path.absoluteFilePath("../")) + "/qml/";
+        qDebug() << "Qml Test Path: " << dir;
+    }
+    return dir;
+}
+
 using namespace controller;
 
 
@@ -88,6 +108,7 @@ public:
 int main(int argc, char** argv) {
     QGuiApplication app(argc, argv);
     QQmlApplicationEngine engine;
+    auto rootContext = engine.rootContext();
     new PluginContainerProxy();
 
     // Simulate our application idle loop
@@ -119,11 +140,16 @@ int main(int argc, char** argv) {
             }
             inputPlugin->pluginUpdate(0, false);
         }
-        auto rootContext = engine.rootContext();
         rootContext->setContextProperty("Controllers", new MyControllerScriptingInterface());
     }
-    
-    engine.load(getQmlDir() + "main.qml");
+    qDebug() << getQmlDir();
+    rootContext->setContextProperty("ResourcePath", getQmlDir());
+    engine.setBaseUrl(QUrl::fromLocalFile(getQmlDir()));
+    engine.addImportPath(getQmlDir());
+    engine.load(getTestQmlDir() + "main.qml");
+    for (auto pathItem : engine.importPathList()) {
+        qDebug() << pathItem;
+    }
     app.exec();
     return 0;
 }

From 734a39f962916e49dfeaa0702a0d13f57d4c1c6d Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 18 Oct 2015 18:58:03 -0700
Subject: [PATCH 058/301] Breaking up UserInputMapper, restoring some mappings

---
 interface/resources/qml/TestControllers.qml   |   2 +-
 .../ControllerScriptingInterface.cpp          | 315 ------------------
 .../scripting/ControllerScriptingInterface.h  |  47 +--
 .../src/controllers/DeviceProxy.cpp           |  31 ++
 .../controllers/src/controllers/DeviceProxy.h |  57 ++++
 .../controllers/src/controllers/Input.cpp     |  19 ++
 libraries/controllers/src/controllers/Input.h |  76 +++++
 .../src/controllers/InputDevice.cpp           |   4 +-
 .../controllers/src/controllers/InputDevice.h |   8 +-
 .../controllers/src/controllers/Pose.cpp      |  30 ++
 libraries/controllers/src/controllers/Pose.h  |  43 +++
 .../src/controllers/ScriptingInterface.cpp    | 125 ++++---
 .../src/controllers/ScriptingInterface.h      |  39 ++-
 .../src/controllers/StandardController.cpp    |  61 +++-
 .../src/controllers/UserInputMapper.cpp       | 184 ++++++----
 .../src/controllers/UserInputMapper.h         | 111 +-----
 .../src/input-plugins/Joystick.cpp            |  60 ++++
 .../src/input-plugins/Joystick.h              |   1 +
 .../src/input-plugins/SixenseManager.cpp      |  75 ++++-
 .../src/input-plugins/SixenseManager.h        |   2 +
 libraries/script-engine/src/ScriptEngine.cpp  |  10 +-
 21 files changed, 670 insertions(+), 630 deletions(-)
 create mode 100644 libraries/controllers/src/controllers/DeviceProxy.cpp
 create mode 100644 libraries/controllers/src/controllers/DeviceProxy.h
 create mode 100644 libraries/controllers/src/controllers/Input.cpp
 create mode 100644 libraries/controllers/src/controllers/Input.h
 create mode 100644 libraries/controllers/src/controllers/Pose.cpp
 create mode 100644 libraries/controllers/src/controllers/Pose.h

diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index 388e452335..d8c9cb4343 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -87,7 +87,7 @@ HifiControls.VrDialog {
                     mapping.from(hydra.RY).invert().to(standard.RY);
                     mapping.from(hydra.RX).to(standard.RX);
                     mapping.from(hydra.LY).to(standard.LY);
-                    mapping.from(hydra.LY).to(standard.LX);
+                    mapping.from(hydra.LX).to(standard.LX);
                     // Assigning a value from a function
                     // mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
                     // Constrainting a value to -1, 0, or 1, with a deadzone
diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp
index f1f7b08587..931c97a7d2 100644
--- a/interface/src/scripting/ControllerScriptingInterface.cpp
+++ b/interface/src/scripting/ControllerScriptingInterface.cpp
@@ -23,109 +23,6 @@
 // TODO: this needs to be removed, as well as any related controller-specific information
 #include <input-plugins/SixenseManager.h>
 
-ControllerScriptingInterface::ControllerScriptingInterface() :
-    _mouseCaptured(false),
-    _touchCaptured(false),
-    _wheelCaptured(false),
-    _actionsCaptured(false)
-{
-
-}
-
-ControllerScriptingInterface::~ControllerScriptingInterface() {
-}
-
-
-static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
-static int inputChannelMetaTypeId = qRegisterMetaType<UserInputMapper::InputChannel>();
-static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
-static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
-
-QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input);
-void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input);
-QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel);
-void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel);
-QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action);
-void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action);
-QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair);
-void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair);
-
-QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) {
-    QScriptValue obj = engine->newObject();
-    obj.setProperty("device", input.getDevice());
-    obj.setProperty("channel", input.getChannel());
-    obj.setProperty("type", (unsigned short) input.getType());
-    obj.setProperty("id", input.getID());
-    return obj;
-}
-
-void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) {
-    input.setDevice(object.property("device").toUInt16());
-    input.setChannel(object.property("channel").toUInt16());
-    input.setType(object.property("type").toUInt16());
-    input.setID(object.property("id").toInt32());
-}
-
-QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel) {
-    QScriptValue obj = engine->newObject();
-    obj.setProperty("input", inputToScriptValue(engine, inputChannel.getInput()));
-    obj.setProperty("modifier", inputToScriptValue(engine, inputChannel.getModifier()));
-    obj.setProperty("action", inputChannel.getAction());
-    obj.setProperty("scale", inputChannel.getScale());
-    return obj;
-}
-
-void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel) {
-    UserInputMapper::Input input;
-    UserInputMapper::Input modifier;
-    inputFromScriptValue(object.property("input"), input);
-    inputChannel.setInput(input);
-    inputFromScriptValue(object.property("modifier"), modifier);
-    inputChannel.setModifier(modifier);
-    inputChannel.setAction(UserInputMapper::Action(object.property("action").toVariant().toInt()));
-    inputChannel.setScale(object.property("scale").toVariant().toFloat());
-}
-
-QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) {
-    QScriptValue obj = engine->newObject();
-    auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    QVector<UserInputMapper::InputChannel> inputChannels = userInputMapper->getInputChannelsForAction(action);
-    QScriptValue _inputChannels = engine->newArray(inputChannels.size());
-    for (int i = 0; i < inputChannels.size(); i++) {
-        _inputChannels.setProperty(i, inputChannelToScriptValue(engine, inputChannels[i]));
-    }
-    obj.setProperty("action", (int) action);
-    obj.setProperty("actionName", userInputMapper->getActionName(action));
-    obj.setProperty("inputChannels", _inputChannels);
-    return obj;
-}
-
-void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) {
-    action = UserInputMapper::Action(object.property("action").toVariant().toInt());
-}
-
-QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) {
-    QScriptValue obj = engine->newObject();
-    obj.setProperty("input", inputToScriptValue(engine, inputPair.first));
-    obj.setProperty("inputName", inputPair.second);
-    return obj;
-}
-
-void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) {
-    inputFromScriptValue(object.property("input"), inputPair.first);
-    inputPair.second = QString(object.property("inputName").toVariant().toString());
-}
-
-void ControllerScriptingInterface::registerControllerTypes(QScriptEngine* engine) {
-    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
-    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputChannel> >(engine);
-    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
-    qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
-    qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue);
-    qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
-    qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
-}
-
 void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
     if (event->type() == HFActionEvent::startType()) {
         emit actionStartEvent(static_cast<HFActionEvent&>(*event));
@@ -183,162 +80,6 @@ const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const
     return NULL;
 }
 
-/*
-bool ControllerScriptingInterface::isPrimaryButtonPressed() const {
-    const PalmData* primaryPalm = getPrimaryPalm();
-    if (primaryPalm) {
-        if (primaryPalm->getControllerButtons() & BUTTON_FWD) {
-            return true;
-        }
-    }
-    
-    return false;
-}
-
-glm::vec2 ControllerScriptingInterface::getPrimaryJoystickPosition() const {
-    const PalmData* primaryPalm = getPrimaryPalm();
-    if (primaryPalm) {
-        return glm::vec2(primaryPalm->getJoystickX(), primaryPalm->getJoystickY());
-    }
-
-    return glm::vec2(0);
-}
-
-int ControllerScriptingInterface::getNumberOfButtons() const {
-    return getNumberOfActivePalms() * NUMBER_OF_BUTTONS_PER_PALM;
-}
-
-bool ControllerScriptingInterface::isButtonPressed(int buttonIndex) const {
-    int palmIndex = buttonIndex / NUMBER_OF_BUTTONS_PER_PALM;
-    int buttonOnPalm = buttonIndex % NUMBER_OF_BUTTONS_PER_PALM;
-    const PalmData* palmData = getActivePalm(palmIndex);
-    if (palmData) {
-        switch (buttonOnPalm) {
-            case 0:
-                return palmData->getControllerButtons() & BUTTON_0;
-            case 1:
-                return palmData->getControllerButtons() & BUTTON_1;
-            case 2:
-                return palmData->getControllerButtons() & BUTTON_2;
-            case 3:
-                return palmData->getControllerButtons() & BUTTON_3;
-            case 4:
-                return palmData->getControllerButtons() & BUTTON_4;
-            case 5:
-                return palmData->getControllerButtons() & BUTTON_FWD;
-        }
-    }
-    return false;
-}
-
-int ControllerScriptingInterface::getNumberOfTriggers() const {
-    return getNumberOfActivePalms() * NUMBER_OF_TRIGGERS_PER_PALM;
-}
-
-float ControllerScriptingInterface::getTriggerValue(int triggerIndex) const {
-    // we know there's one trigger per palm, so the triggerIndex is the palm Index
-    int palmIndex = triggerIndex;
-    const PalmData* palmData = getActivePalm(palmIndex);
-    if (palmData) {
-        return palmData->getTrigger();
-    }
-    return 0.0f;
-}
-
-int ControllerScriptingInterface::getNumberOfJoysticks() const {
-    return getNumberOfActivePalms() * NUMBER_OF_JOYSTICKS_PER_PALM;
-}
-
-glm::vec2 ControllerScriptingInterface::getJoystickPosition(int joystickIndex) const {
-    // we know there's one joystick per palm, so the joystickIndex is the palm Index
-    int palmIndex = joystickIndex;
-    const PalmData* palmData = getActivePalm(palmIndex);
-    if (palmData) {
-        return glm::vec2(palmData->getJoystickX(), palmData->getJoystickY());
-    }
-    return glm::vec2(0);
-}
-
-int ControllerScriptingInterface::getNumberOfSpatialControls() const {
-    return getNumberOfActivePalms() * NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-}
-
-glm::vec3 ControllerScriptingInterface::getSpatialControlPosition(int controlIndex) const {
-    int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    const PalmData* palmData = getActivePalm(palmIndex);
-    if (palmData) {
-        switch (controlOfPalm) {
-            case PALM_SPATIALCONTROL:
-                return palmData->getPosition();
-            case TIP_SPATIALCONTROL:
-                return palmData->getTipPosition();
-        }
-    }
-    return glm::vec3(0); // bad index
-}
-
-glm::vec3 ControllerScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
-    int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    const PalmData* palmData = getActivePalm(palmIndex);
-    if (palmData) {
-        switch (controlOfPalm) {
-            case PALM_SPATIALCONTROL:
-                return palmData->getVelocity();
-            case TIP_SPATIALCONTROL:
-                return palmData->getTipVelocity();
-        }
-    }
-    return glm::vec3(0); // bad index
-}
-
-glm::quat ControllerScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
-    int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    const PalmData* palmData = getActivePalm(palmIndex);
-    if (palmData) {
-        switch (controlOfPalm) {
-            case PALM_SPATIALCONTROL:
-                return palmData->getRawRotation();
-            case TIP_SPATIALCONTROL:
-                return palmData->getRawRotation(); // currently the tip doesn't have a unique rotation, use the palm rotation
-        }
-    }
-    return glm::quat(); // bad index
-}
-    
-glm::vec3 ControllerScriptingInterface::getSpatialControlRawAngularVelocity(int controlIndex) const {
-    int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    const PalmData* palmData = getActivePalm(palmIndex);
-    if (palmData) {
-        switch (controlOfPalm) {
-            case PALM_SPATIALCONTROL:
-                return palmData->getRawAngularVelocity();
-            case TIP_SPATIALCONTROL:
-                return palmData->getRawAngularVelocity();  //  Tip = palm angular velocity        
-        }
-    }
-    return glm::vec3(0); // bad index
-}
-
-glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const {
-    int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
-    const PalmData* palmData = getActivePalm(palmIndex);
-    if (palmData) {
-        switch (controlOfPalm) {
-            case PALM_SPATIALCONTROL:
-                return palmData->getNormal();
-            case TIP_SPATIALCONTROL:
-                return palmData->getFingerDirection();
-        }
-    }
-    return glm::vec3(0); // bad index
-}
-*/
-
 bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const {
     return isKeyCaptured(KeyEvent(*event));
 }
@@ -448,62 +189,6 @@ void ControllerScriptingInterface::update() {
     controller::ScriptingInterface::update();
 }
 
-QVector<UserInputMapper::Action> ControllerScriptingInterface::getAllActions() {
-    return DependencyManager::get<UserInputMapper>()->getAllActions();
-}
-
-QVector<UserInputMapper::InputChannel> ControllerScriptingInterface::getInputChannelsForAction(UserInputMapper::Action action) {
-    return DependencyManager::get<UserInputMapper>()->getInputChannelsForAction(action);
-}
-
-QString ControllerScriptingInterface::getDeviceName(unsigned int device) {
-    return DependencyManager::get<UserInputMapper>()->getDeviceName((unsigned short)device);
-}
-
-QVector<UserInputMapper::InputChannel> ControllerScriptingInterface::getAllInputsForDevice(unsigned int device) {
-    return DependencyManager::get<UserInputMapper>()->getAllInputsForDevice(device);
-}
-
-bool ControllerScriptingInterface::addInputChannel(UserInputMapper::InputChannel inputChannel) {
-    return DependencyManager::get<UserInputMapper>()->addInputChannel(inputChannel._action, inputChannel._input, inputChannel._modifier, inputChannel._scale);
-}
-
-bool ControllerScriptingInterface::removeInputChannel(UserInputMapper::InputChannel inputChannel) {
-    return DependencyManager::get<UserInputMapper>()->removeInputChannel(inputChannel);
-}
-
-QVector<UserInputMapper::InputPair> ControllerScriptingInterface::getAvailableInputs(unsigned int device) {
-    return DependencyManager::get<UserInputMapper>()->getAvailableInputs((unsigned short)device);
-}
-
-void ControllerScriptingInterface::resetAllDeviceBindings() {
-    DependencyManager::get<UserInputMapper>()->resetAllDeviceBindings();
-}
-
-void ControllerScriptingInterface::resetDevice(unsigned int device) {
-    DependencyManager::get<UserInputMapper>()->resetDevice(device);
-}
-
-int ControllerScriptingInterface::findDevice(QString name) {
-    return DependencyManager::get<UserInputMapper>()->findDevice(name);
-}
-
-QVector<QString> ControllerScriptingInterface::getDeviceNames() {
-    return DependencyManager::get<UserInputMapper>()->getDeviceNames();
-}
-
-float ControllerScriptingInterface::getActionValue(int action) {
-    return DependencyManager::get<UserInputMapper>()->getActionState(UserInputMapper::Action(action));
-}
-
-int ControllerScriptingInterface::findAction(QString actionName) {
-    return DependencyManager::get<UserInputMapper>()->findAction(actionName);
-}
-
-QVector<QString> ControllerScriptingInterface::getActionNames() const {
-    return DependencyManager::get<UserInputMapper>()->getActionNames();
-}
-
 InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
     _deviceTrackerId(deviceTrackerId),
     _subTrackerId(subTrackerId),
diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h
index 25d9a523d3..24065e6799 100644
--- a/interface/src/scripting/ControllerScriptingInterface.h
+++ b/interface/src/scripting/ControllerScriptingInterface.h
@@ -63,33 +63,8 @@ class ControllerScriptingInterface : public controller::ScriptingInterface {
 
 
 public:    
-    ControllerScriptingInterface();
-    ~ControllerScriptingInterface();
+    virtual ~ControllerScriptingInterface() {}
 
-    Q_INVOKABLE QVector<UserInputMapper::Action> getAllActions();
-
-    Q_INVOKABLE bool addInputChannel(UserInputMapper::InputChannel inputChannel);
-    Q_INVOKABLE bool removeInputChannel(UserInputMapper::InputChannel inputChannel);
-    Q_INVOKABLE QVector<UserInputMapper::InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
-
-    Q_INVOKABLE QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
-    Q_INVOKABLE QVector<UserInputMapper::InputChannel> getAllInputsForDevice(unsigned int device);
-
-    Q_INVOKABLE QString getDeviceName(unsigned int device);
-
-    Q_INVOKABLE float getActionValue(int action);
-
-    Q_INVOKABLE void resetDevice(unsigned int device);
-    Q_INVOKABLE void resetAllDeviceBindings();
-    Q_INVOKABLE int findDevice(QString name);
-    Q_INVOKABLE QVector<QString> getDeviceNames();
-
-    Q_INVOKABLE int findAction(QString actionName);
-    Q_INVOKABLE QVector<QString> getActionNames() const;
-
-
-    virtual void registerControllerTypes(QScriptEngine* engine);
-    
     void emitKeyPressEvent(QKeyEvent* event);
     void emitKeyReleaseEvent(QKeyEvent* event);
     
@@ -108,10 +83,6 @@ public:
 
     bool isKeyCaptured(QKeyEvent* event) const;
     bool isKeyCaptured(const KeyEvent& event) const;
-    bool isMouseCaptured() const { return _mouseCaptured; }
-    bool isTouchCaptured() const { return _touchCaptured; }
-    bool isWheelCaptured() const { return _wheelCaptured; }
-    bool areActionsCaptured() const { return _actionsCaptured; }
     bool isJoystickCaptured(int joystickIndex) const;
 
     virtual void update() override;
@@ -121,18 +92,6 @@ public slots:
     virtual void captureKeyEvents(const KeyEvent& event);
     virtual void releaseKeyEvents(const KeyEvent& event);
 
-    virtual void captureMouseEvents() { _mouseCaptured = true; }
-    virtual void releaseMouseEvents() { _mouseCaptured = false; }
-
-    virtual void captureTouchEvents() { _touchCaptured = true; }
-    virtual void releaseTouchEvents() { _touchCaptured = false; }
-
-    virtual void captureWheelEvents() { _wheelCaptured = true; }
-    virtual void releaseWheelEvents() { _wheelCaptured = false; }
-    
-    virtual void captureActionEvents() { _actionsCaptured = true; }
-    virtual void releaseActionEvents() { _actionsCaptured = false; }
-
     virtual void captureJoystick(int joystickIndex);
     virtual void releaseJoystick(int joystickIndex);
 
@@ -173,10 +132,6 @@ private:
     int getNumberOfActivePalms() const;
     const PalmData* getActivePalm(int palmIndex) const;
     
-    bool _mouseCaptured;
-    bool _touchCaptured;
-    bool _wheelCaptured;
-    bool _actionsCaptured;
     QMultiMap<int,KeyEvent> _capturedKeys;
     QSet<int> _capturedJoysticks;
 
diff --git a/libraries/controllers/src/controllers/DeviceProxy.cpp b/libraries/controllers/src/controllers/DeviceProxy.cpp
new file mode 100644
index 0000000000..9ac701e80d
--- /dev/null
+++ b/libraries/controllers/src/controllers/DeviceProxy.cpp
@@ -0,0 +1,31 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/18
+//  (based on UserInputMapper inner class created by Sam Gateau on 4/27/15)
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "DeviceProxy.h"
+
+namespace controller {
+
+    float DeviceProxy::getValue(const Input& input, int timestamp) const {
+        switch (input.getType()) {
+        case ChannelType::BUTTON:
+            return getButton(input, timestamp) ? 1.0f : 0.0f;
+
+        case ChannelType::AXIS:
+            return getAxis(input, timestamp);
+
+        case ChannelType::POSE:
+            return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
+
+        default:
+            return NAN;
+        }
+    }
+
+}
+
diff --git a/libraries/controllers/src/controllers/DeviceProxy.h b/libraries/controllers/src/controllers/DeviceProxy.h
new file mode 100644
index 0000000000..78d13fe5c4
--- /dev/null
+++ b/libraries/controllers/src/controllers/DeviceProxy.h
@@ -0,0 +1,57 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/18
+//  (based on UserInputMapper inner class created by Sam Gateau on 4/27/15)
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_controllers_DeviceProxy_h
+#define hifi_controllers_DeviceProxy_h
+
+#include <functional>
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+#include "Input.h"
+#include "Pose.h"
+
+namespace controller {
+
+    using Modifiers = std::vector<Input>;
+    typedef QPair<Input, QString> InputPair;
+
+    
+    template<typename T>
+    using InputGetter = std::function<T(const Input& input, int timestamp)>;
+    using ButtonGetter = InputGetter<bool>;
+    using AxisGetter = InputGetter<float>;
+    using PoseGetter = InputGetter<Pose>;
+    using ResetBindings = std::function<bool()>;
+    using AvailableInputGetter = std::function<Input::NamedVector()>;
+
+    class DeviceProxy {
+    public:
+       DeviceProxy(QString name) : _baseName(name), _name(name) {}
+       const QString& getBaseName() const { return _baseName; }
+       const QString& getName() const { return _name; }
+
+       ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
+       AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; };
+       PoseGetter getPose = [](const Input& input, int timestamp) -> Pose { return Pose(); };
+       AvailableInputGetter getAvailabeInputs = []() -> Input::NamedVector { return Input::NamedVector(); };
+       ResetBindings resetDeviceBindings = [] () -> bool { return true; };
+       float getValue(const Input& input, int timestamp = 0) const;
+
+       using Pointer = std::shared_ptr<DeviceProxy>;
+
+       QString _baseName;
+       QString _name;
+    };
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/Input.cpp b/libraries/controllers/src/controllers/Input.cpp
new file mode 100644
index 0000000000..29d2fed617
--- /dev/null
+++ b/libraries/controllers/src/controllers/Input.cpp
@@ -0,0 +1,19 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/18
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Input.h"
+
+namespace controller {
+
+    const Input Input::INVALID_INPUT = Input(UINT32_MAX);
+    const uint16_t Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
+    const uint16_t Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
+    const uint16_t Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
+
+}
+
diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h
new file mode 100644
index 0000000000..8cc682df70
--- /dev/null
+++ b/libraries/controllers/src/controllers/Input.h
@@ -0,0 +1,76 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/18
+//  (based on UserInputMapper inner class created by Sam Gateau on 4/27/15)
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_controllers_Input_h
+#define hifi_controllers_Input_h
+
+#include <GLMHelpers.h>
+
+namespace controller {
+
+enum class ChannelType {
+    UNKNOWN = 0,
+    BUTTON = 1,
+    AXIS,
+    POSE,
+};
+
+// Input is the unique identifier to find a n input channel of a particular device
+// Devices are responsible for registering to the UseInputMapper so their input channels can be sued and mapped
+// to the Action channels
+struct Input {
+    union {
+        struct {
+            uint16_t _device; // Up to 64K possible devices
+            uint16_t _channel : 13; // 2^13 possible channel per Device
+            uint16_t _type : 2; // 2 bits to store the Type directly in the ID
+            uint16_t _padding : 1; // 2 bits to store the Type directly in the ID
+        };
+        uint32_t _id = 0; // by default Input is 0 meaning invalid
+    };
+
+    bool isValid() const { return (_id != 0); }
+
+    uint16_t getDevice() const { return _device; }
+    uint16_t getChannel() const { return _channel; }
+    uint32_t getID() const { return _id; }
+    ChannelType getType() const { return (ChannelType) _type; }
+
+    void setDevice(uint16_t device) { _device = device; }
+    void setChannel(uint16_t channel) { _channel = channel; }
+    void setType(uint16_t type) { _type = type; }
+    void setID(uint32_t ID) { _id = ID; }
+
+    bool isButton() const { return getType() == ChannelType::BUTTON; }
+    bool isAxis() const { return getType() == ChannelType::AXIS; }
+    bool isPose() const { return getType() == ChannelType::POSE; }
+
+    // WORKAROUND: the explicit initializer here avoids a bug in GCC-4.8.2 (but not found in 4.9.2)
+    // where the default initializer (a C++-11ism) for the union data above is not applied.
+    explicit Input() : _id(0) {}
+    explicit Input(uint32_t id) : _id(id) {}
+    explicit Input(uint16_t device, uint16_t channel, ChannelType type) : _device(device), _channel(channel), _type(uint16_t(type)), _padding(0) {}
+    Input(const Input& src) : _id(src._id) {}
+    Input& operator = (const Input& src) { _id = src._id; return (*this); }
+    bool operator ==(const Input& right) const { return _id == right._id; }
+    bool operator < (const Input& src) const { return _id < src._id; }
+
+    static const Input INVALID_INPUT;
+    static const uint16_t INVALID_DEVICE;
+    static const uint16_t INVALID_CHANNEL;
+    static const uint16_t INVALID_TYPE;
+
+    using NamedPair = QPair<Input, QString>;
+    using NamedVector = QVector<NamedPair>;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/InputDevice.cpp b/libraries/controllers/src/controllers/InputDevice.cpp
index 4b2376d32a..1f86741b88 100644
--- a/libraries/controllers/src/controllers/InputDevice.cpp
+++ b/libraries/controllers/src/controllers/InputDevice.cpp
@@ -13,7 +13,7 @@
 bool InputDevice::_lowVelocityFilter = false;
 
 const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
-float InputDevice::reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
+float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
 
 //Constants for getCursorPixelRangeMultiplier()
 const float MIN_PIXEL_RANGE_MULT = 0.4f;
@@ -23,7 +23,7 @@ const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f;
 //Returns a multiplier to be applied to the cursor range for the controllers
 float InputDevice::getCursorPixelRangeMult() {
     //scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT)
-    return InputDevice::reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
+    return InputDevice::_reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
 }
 
 float InputDevice::getButton(int channel) const {
diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h
index 66f7addc58..4854df0ada 100644
--- a/libraries/controllers/src/controllers/InputDevice.h
+++ b/libraries/controllers/src/controllers/InputDevice.h
@@ -34,7 +34,7 @@ public:
     UserInputMapper::PoseValue getPose(int channel) const;
 
     virtual void registerToUserInputMapper(UserInputMapper& mapper) = 0;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) {};
+    virtual void assignDefaultInputMapping(UserInputMapper& mapper) = 0;
 
     // Update call MUST be called once per simulation loop
     // It takes care of updating the action states and deltas
@@ -45,8 +45,8 @@ public:
     int getDeviceID() { return _deviceID; }
 
     static float getCursorPixelRangeMult();
-    static float getReticleMoveSpeed() { return reticleMoveSpeed; }
-    static void setReticleMoveSpeed(float sixenseReticleMoveSpeed) { reticleMoveSpeed = sixenseReticleMoveSpeed; }
+    static float getReticleMoveSpeed() { return _reticleMoveSpeed; }
+    static void setReticleMoveSpeed(float reticleMoveSpeed) { _reticleMoveSpeed = reticleMoveSpeed; }
 
     static bool getLowVelocityFilter() { return _lowVelocityFilter; };
 
@@ -72,5 +72,5 @@ protected:
     static bool _lowVelocityFilter;
 
 private:
-    static float reticleMoveSpeed;
+    static float _reticleMoveSpeed;
 };
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp
new file mode 100644
index 0000000000..a716955d70
--- /dev/null
+++ b/libraries/controllers/src/controllers/Pose.cpp
@@ -0,0 +1,30 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/18
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Pose.h"
+
+namespace controller {
+
+    Pose::Pose(const vec3& translation, const quat& rotation,
+            const vec3& velocity, const quat& angularVelocity) :
+            _translation(translation), _rotation(rotation), _velocity(velocity), _angularVelocity(angularVelocity) { }
+
+    bool Pose::operator==(const Pose& right) const {
+        // invalid poses return false for comparison, even against identical invalid poses, like NaN
+        if (_valid || !right._valid) {
+            return false;
+        }
+
+        // FIXME add margin of error?  Or add an additional withinEpsilon function?
+        return _translation == right.getTranslation() && _rotation == right.getRotation() && 
+            _velocity == right.getVelocity() && _angularVelocity == right.getAngularVelocity();
+    }
+
+
+}
+
diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h
new file mode 100644
index 0000000000..b77064f2c1
--- /dev/null
+++ b/libraries/controllers/src/controllers/Pose.h
@@ -0,0 +1,43 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/18
+//  (based on UserInputMapper inner class created by Sam Gateau on 4/27/15)
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_controllers_Pose_h
+#define hifi_controllers_Pose_h
+
+#include <GLMHelpers.h>
+
+namespace controller {
+
+    struct Pose {
+    public:
+        vec3 _translation;
+        quat _rotation;
+        vec3 _velocity;
+        quat _angularVelocity;
+        bool _valid{ false };
+
+        Pose() {}
+        Pose(const vec3& translation, const quat& rotation,
+             const vec3& velocity = vec3(), const quat& angularVelocity = quat());
+
+        Pose(const Pose&) = default;
+        Pose& operator = (const Pose&) = default;
+        bool operator ==(const Pose& right) const;
+        bool isValid() const { return _valid; }
+        vec3 getTranslation() const { return _translation; }
+        quat getRotation() const { return _rotation; }
+        vec3 getVelocity() const { return _velocity; }
+        quat getAngularVelocity() const { return _angularVelocity; }
+    };
+
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 6d4ad1a566..c5c7969604 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -67,7 +67,7 @@ namespace controller {
 
     void ScriptEndpoint::updateValue() {
         if (QThread::currentThread() != thread()) {
-            QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
+            QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
             return;
         }
 
@@ -80,10 +80,10 @@ namespace controller {
 
     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));
+            QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
+                Q_ARG(float, newValue),
+                Q_ARG(float, oldValue),
+                Q_ARG(int, sourceID));
             return;
         }
         _callable.call(QScriptValue(), 
@@ -163,28 +163,28 @@ namespace controller {
         QJsonObject obj;
         QJsonParseError error;
         QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error);
-        // check validity of the document
-        if (!doc.isNull()) {
-            if (doc.isObject()) {
-                obj = doc.object();
-
+        // check validity of the document
+        if (!doc.isNull()) {
+            if (doc.isObject()) {
+                obj = doc.object();
+
                 auto mapping = std::make_shared<Mapping>("default");
                 auto mappingBuilder = new MappingBuilderProxy(*this, mapping);
 
                 mappingBuilder->parse(obj);
 
                 _mappingsByName[mapping->_name] = mapping;
-
-                return mappingBuilder;
-            } else {
-                qDebug() << "Mapping json Document is not an object" << endl;
-            }
-        } else {
-            qDebug() << "Invalid JSON...\n";
-            qDebug() << error.errorString();
-            qDebug() << "JSON was:\n" << json << endl;
-
-        }
+
+                return mappingBuilder;
+            } else {
+                qDebug() << "Mapping json Document is not an object" << endl;
+            }
+        } else {
+            qDebug() << "Invalid JSON...\n";
+            qDebug() << error.errorString();
+            qDebug() << "JSON was:\n" << json << endl;
+
+        }
 
         return nullptr;
     }
@@ -204,7 +204,7 @@ namespace controller {
             if (request->getResult() == ResourceRequest::Success) {
                 result = parseMapping(QString(request->getData()));
             } else {
-                qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl;
+                qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl;
             }
             request->deleteLater();
         }
@@ -263,8 +263,8 @@ namespace controller {
         return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID());
     }
 
-    glm::mat4 ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
-        return glm::mat4();
+    Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
+        return Pose();
     }
 
     void ScriptingInterface::update() {
@@ -368,7 +368,7 @@ namespace controller {
     }
 
     UserInputMapper::Input ScriptingInterface::inputFor(const QString& inputName) {
-        return DependencyManager::get<UserInputMapper>()->findDeviceInput(inputName);
+        return DependencyManager::get<UserInputMapper>()->findDeviceInput(inputName);
     }
 
     Endpoint::Pointer ScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) {
@@ -494,6 +494,39 @@ namespace controller {
             }
         }
     }
+
+    QVector<UserInputMapper::Action> ScriptingInterface::getAllActions() {
+        return DependencyManager::get<UserInputMapper>()->getAllActions();
+    }
+
+    QString ScriptingInterface::getDeviceName(unsigned int device) {
+        return DependencyManager::get<UserInputMapper>()->getDeviceName((unsigned short)device);
+    }
+
+    QVector<UserInputMapper::InputPair> ScriptingInterface::getAvailableInputs(unsigned int device) {
+        return DependencyManager::get<UserInputMapper>()->getAvailableInputs((unsigned short)device);
+    }
+
+    int ScriptingInterface::findDevice(QString name) {
+        return DependencyManager::get<UserInputMapper>()->findDevice(name);
+    }
+
+    QVector<QString> ScriptingInterface::getDeviceNames() {
+        return DependencyManager::get<UserInputMapper>()->getDeviceNames();
+    }
+
+    float ScriptingInterface::getActionValue(int action) {
+        return DependencyManager::get<UserInputMapper>()->getActionState(UserInputMapper::Action(action));
+    }
+
+    int ScriptingInterface::findAction(QString actionName) {
+        return DependencyManager::get<UserInputMapper>()->findAction(actionName);
+    }
+
+    QVector<QString> ScriptingInterface::getActionNames() const {
+        return DependencyManager::get<UserInputMapper>()->getActionNames();
+    }
+
 } // namespace controllers
 
 
@@ -520,7 +553,7 @@ ScriptingInterface::ScriptingInterface() {
     int actionNumber = 0;
     qCDebug(controllers) << "Setting up standard actions";
     for (const auto& actionName : actionNames) {
-        UserInputMapper::Input actionInput(UserInputMapper::Input::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
+        UserInputMapper::Input actionInput(UserInputMapper::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
         qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16);
         // Expose the IDs to JS
         QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
@@ -532,43 +565,3 @@ ScriptingInterface::ScriptingInterface() {
 
     updateMaps();
 }
-
-//var mapping = Controller.newMapping();
-//mapping.map(hydra.LeftButton0, actions.ContextMenu);
-//mapping.map(hydra.LeftButton0).to(xbox.RT);
-//mapping.from(xbox.RT).constrainToBoolean().invert().to(actions.Foo)
-//    mapping.from(xbox.RY).invert().deadZone(0.2).to(actions.Pitch)
-//    mapping.from(xbox.RY).filter(function(newValue, oldValue) {
-//    return newValue * 2.0
-//}).to(actions.Pitch)
-
-//mapping.from(function(time) {
-//        return Math.cos(time);
-//    }).to(actions.Pitch);
-
-//    mapping.mapFromFunction(function() {
-//        return x;
-//    }, actions.ContextMenu);
-
-//    mapping.from(xbox.LY).clamp(0, 1).to(actions.Forward);
-//    mapping.from(xbox.LY).clamp(-1, 0).to(actions.Backward);
-//    mapping.from(xbox.RY).clamp(0, 1).to(actions.Forward);
-//    mapping.from(xbox.RS).to();
-//    mapping.from(xbox.ALL).to();
-
-//    mapping.from(xbox.RY).to(function(...) { ... });
-//    mapping.from(xbox.RY).pass();
-
-//    mapping.suppress() ≅ mapping.to(null)
-//        mapping.pass() ≅ mapping.to(fromControl)
-
-//        mapping.from(keyboard.RightParen).invert().to(actions.Yaw)
-//        mapping.from(keyboard.LeftParen).to(actions.Yaw)
-
-//        mapping.from(hydra.LX).pulse(MIN_SNAP_TIME, 3.0).to(Actions.Yaw)
-
-//        mapping.from(keyboard.LeftParen).pulse(MIN_SNAP_TIME).to(Actions.Yaw)
-//        // Enable and disable as above
-
-//        mappingSnap.from(hydra.LX).to(function(newValue, oldValue) {
-//        timeSinceLastYaw += deltaTime
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index ef9d61c32d..f473562b9e 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -67,15 +67,22 @@ namespace controller {
         ScriptingInterface();
         virtual ~ScriptingInterface();
 
+        Q_INVOKABLE QVector<UserInputMapper::Action> getAllActions();
+        Q_INVOKABLE QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
+        Q_INVOKABLE QString getDeviceName(unsigned int device);
+        Q_INVOKABLE float getActionValue(int action);
+        Q_INVOKABLE int findDevice(QString name);
+        Q_INVOKABLE QVector<QString> getDeviceNames();
+        Q_INVOKABLE int findAction(QString actionName);
+        Q_INVOKABLE QVector<QString> getActionNames() const;
+
         Q_INVOKABLE float getValue(const int& source) const;
         Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
         Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const;
-        Q_INVOKABLE glm::mat4 getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
+        Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
         Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
         Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
-        Q_INVOKABLE void disableMapping(const QString& mappingName) {
-            enableMapping(mappingName, false);
-        }
+        Q_INVOKABLE void disableMapping(const QString& mappingName) { enableMapping(mappingName, false); }
         Q_INVOKABLE QObject* parseMapping(const QString& json);
         Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl);
 
@@ -102,13 +109,30 @@ namespace controller {
         Q_INVOKABLE const QVariantMap& getActions() { return _actions; }
         Q_INVOKABLE const QVariantMap& getStandard() { return _standard; }
 
+        bool isMouseCaptured() const { return _mouseCaptured; }
+        bool isTouchCaptured() const { return _touchCaptured; }
+        bool isWheelCaptured() const { return _wheelCaptured; }
+        bool areActionsCaptured() const { return _actionsCaptured; }
+
         static QRegularExpression SANITIZE_NAME_EXPRESSION;
 
     public slots:
         virtual void update();
-        virtual void registerControllerTypes(QScriptEngine* engine) = 0;
         virtual void updateMaps();
 
+        virtual void captureMouseEvents() { _mouseCaptured = true; }
+        virtual void releaseMouseEvents() { _mouseCaptured = false; }
+
+        virtual void captureTouchEvents() { _touchCaptured = true; }
+        virtual void releaseTouchEvents() { _touchCaptured = false; }
+
+        virtual void captureWheelEvents() { _wheelCaptured = true; }
+        virtual void releaseWheelEvents() { _wheelCaptured = false; }
+
+        virtual void captureActionEvents() { _actionsCaptured = true; }
+        virtual void releaseActionEvents() { _actionsCaptured = false; }
+
+
     private:
         friend class MappingBuilderProxy;
         friend class RouteBuilderProxy;
@@ -141,6 +165,11 @@ namespace controller {
         ValueMap _overrideValues;
         MappingMap _mappingsByName;
         MappingStack _activeMappings;
+
+        bool _mouseCaptured{ false };
+        bool _touchCaptured{ false };
+        bool _wheelCaptured{ false };
+        bool _actionsCaptured{ false };
     };
 
     class ScriptEndpoint : public Endpoint {
diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index 9c423eded2..6b1ada25ed 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -96,16 +96,65 @@ void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
         return availableInputs;
     };
 
-    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
-
     mapper.registerStandardDevice(proxy);
 }
 
 void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
+    const float JOYSTICK_MOVE_SPEED = 1.0f;
+    const float DPAD_MOVE_SPEED = 0.5f;
+    const float JOYSTICK_YAW_SPEED = 0.5f;
+    const float JOYSTICK_PITCH_SPEED = 0.25f;
+    const float BOOM_SPEED = 0.1f;
+
+    // Y axes are flipped (up is negative)
+    // Left Joystick: Movement, strafing
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED);
+    // Right Joystick: Camera orientation
+    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED);
+    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED);
+
+    // Dpad movement
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED);
+
+    // Button controls
+    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED);
+
+    // Zoom
+    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED);
+    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LB), BOOM_SPEED);
+
+    // Hold front right shoulder button for precision controls
+    // Left Joystick: Movement, strafing
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
+
+    // Right Joystick: Camera orientation
+    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
+
+    // Dpad movement
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+
+    // Button controls
+    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+
+    // Zoom
+    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
+
+    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
+
+    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
+    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A));
 }
 
 UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) {
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index fbf1994d87..2c80eb98a1 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -1,7 +1,4 @@
 //
-//  UserInputMapper.cpp
-//  input-plugins/src/input-plugins
-//
 //  Created by Sam Gateau on 4/27/15.
 //  Copyright 2015 High Fidelity, Inc.
 //
@@ -12,14 +9,10 @@
 #include "UserInputMapper.h"
 #include "StandardController.h"
 
-#include "Logging.h"
+#include "Logging.h"
 
-const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX);
-const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
-const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
-const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
-const uint16_t UserInputMapper::Input::ACTIONS_DEVICE = INVALID_DEVICE - (uint16)1;
-const uint16_t UserInputMapper::Input::STANDARD_DEVICE = 0;
+const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - (uint16)1;
+const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
 
 // Default contruct allocate the poutput size with the current hardcoded action channels
 UserInputMapper::UserInputMapper() {
@@ -46,18 +39,18 @@ bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer
         proxy->_name += QString::number(numberOfType);
     }
     
-    qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
+    qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
     _registeredDevices[deviceID] = proxy;
     return true;
     
 }
 
 
-bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) {
-    device->_name = "Standard"; // Just to make sure
-    _registeredDevices[getStandardDeviceID()] = device;
-    return true;
-}
+bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) {
+    device->_name = "Standard"; // Just to make sure
+    _registeredDevices[getStandardDeviceID()] = device;
+    return true;
+}
 
 
 UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
@@ -110,51 +103,51 @@ QVector<QString> UserInputMapper::getDeviceNames() {
     return result;
 }
 
-UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
-    
-    // Split the full input name as such: deviceName.inputName
-    auto names = inputName.split('.');
-
-    if (names.size() >= 2) {
-        // Get the device name:
-        auto deviceName = names[0];
-        auto inputName = names[1];
-
-        int deviceID = findDevice(deviceName);
-        if (deviceID != Input::INVALID_DEVICE) {
-            const auto& deviceProxy = _registeredDevices.at(deviceID);
-            auto deviceInputs = deviceProxy->getAvailabeInputs();
-
-            for (auto input : deviceInputs) {
-                if (input.second == inputName) {
-                    return input.first;
-                }
-            }
-
-            qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">";
-
-        } else if (deviceName == "Actions") {
-            deviceID = Input::ACTIONS_DEVICE;
-            int actionNum = 0;
-            for (auto action : _actionNames) {
-                if (action == inputName) {
-                    return Input(Input::ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
-                }
-                actionNum++;
-            }
-
-            qCDebug(controllers) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions";
-
-        } else {
-            qCDebug(controllers) << "Couldn\'t find InputDevice named <" << deviceName << ">";
-        }
-    } else {
-        qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
-    }
-
-    return Input();
-}
-
+UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
+    
+    // Split the full input name as such: deviceName.inputName
+    auto names = inputName.split('.');
+
+    if (names.size() >= 2) {
+        // Get the device name:
+        auto deviceName = names[0];
+        auto inputName = names[1];
+
+        int deviceID = findDevice(deviceName);
+        if (deviceID != Input::INVALID_DEVICE) {
+            const auto& deviceProxy = _registeredDevices.at(deviceID);
+            auto deviceInputs = deviceProxy->getAvailabeInputs();
+
+            for (auto input : deviceInputs) {
+                if (input.second == inputName) {
+                    return input.first;
+                }
+            }
+
+            qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">";
+
+        } else if (deviceName == "Actions") {
+            deviceID = ACTIONS_DEVICE;
+            int actionNum = 0;
+            for (auto action : _actionNames) {
+                if (action == inputName) {
+                    return Input(ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
+                }
+                actionNum++;
+            }
+
+            qCDebug(controllers) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions";
+
+        } else {
+            qCDebug(controllers) << "Couldn\'t find InputDevice named <" << deviceName << ">";
+        }
+    } else {
+        qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
+    }
+
+    return Input::INVALID_INPUT;
+}
+
 
 
 bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
@@ -261,7 +254,6 @@ void UserInputMapper::update(float deltaTime) {
     }
 
     int currentTimestamp = 0;
-
     for (auto& channelInput : _actionToInputsMap) {
         auto& inputMapping = channelInput.second;
         auto& inputID = inputMapping._input;
@@ -430,18 +422,62 @@ void UserInputMapper::registerStandardDevice() {
     _standardController->registerToUserInputMapper(*this);
 }
 
-float UserInputMapper::DeviceProxy::getValue(const Input& input, int timestamp) const {
-    switch (input.getType()) {
-        case UserInputMapper::ChannelType::BUTTON:
-            return getButton(input, timestamp) ? 1.0f : 0.0f;
 
-        case UserInputMapper::ChannelType::AXIS:
-            return getAxis(input, timestamp);
+static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
+static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
+static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
 
-        case UserInputMapper::ChannelType::POSE:
-            return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
+QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input);
+void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input);
+QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action);
+void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action);
+QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair);
+void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair);
 
-        default:
-            return 0.0f;
-    }
-}
\ No newline at end of file
+QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) {
+    QScriptValue obj = engine->newObject();
+    obj.setProperty("device", input.getDevice());
+    obj.setProperty("channel", input.getChannel());
+    obj.setProperty("type", (unsigned short)input.getType());
+    obj.setProperty("id", input.getID());
+    return obj;
+}
+
+void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) {
+    input.setDevice(object.property("device").toUInt16());
+    input.setChannel(object.property("channel").toUInt16());
+    input.setType(object.property("type").toUInt16());
+    input.setID(object.property("id").toInt32());
+}
+
+QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) {
+    QScriptValue obj = engine->newObject();
+    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    obj.setProperty("action", (int)action);
+    obj.setProperty("actionName", userInputMapper->getActionName(action));
+    return obj;
+}
+
+void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) {
+    action = UserInputMapper::Action(object.property("action").toVariant().toInt());
+}
+
+QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) {
+    QScriptValue obj = engine->newObject();
+    obj.setProperty("input", inputToScriptValue(engine, inputPair.first));
+    obj.setProperty("inputName", inputPair.second);
+    return obj;
+}
+
+void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) {
+    inputFromScriptValue(object.property("input"), inputPair.first);
+    inputPair.second = QString(object.property("inputName").toVariant().toString());
+}
+
+void UserInputMapper::registerControllerTypes(QScriptEngine* engine) {
+    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
+    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
+    qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
+    qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
+    qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
+}
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 8b466d79c9..b8bc0850cf 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -1,7 +1,4 @@
 //
-//  UserInputMapper.h
-//  input-plugins/src/input-plugins
-//
 //  Created by Sam Gateau on 4/27/15.
 //  Copyright 2015 High Fidelity, Inc.
 //
@@ -9,6 +6,7 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
+#pragma once
 #ifndef hifi_UserInputMapper_h
 #define hifi_UserInputMapper_h
 
@@ -20,6 +18,10 @@
 #include <DependencyManager.h>
 #include <RegisteredMetaTypes.h>
 
+#include "Pose.h"
+#include "Input.h"
+#include "DeviceProxy.h"
+
 class StandardController;    
 typedef std::shared_ptr<StandardController> StandardControllerPointer;
 
@@ -30,86 +32,22 @@ class UserInputMapper : public QObject, public Dependency {
 public:
     ~UserInputMapper();
 
+    using DeviceProxy = controller::DeviceProxy;
+    using PoseValue = controller::Pose;
+    using Input = controller::Input;
+    using ChannelType = controller::ChannelType;
+
     typedef unsigned short uint16;
     typedef unsigned int uint32;
 
-    enum class ChannelType {
-        UNKNOWN = 0,
-        BUTTON = 1,
-        AXIS,
-        POSE,
-    };
+    static void registerControllerTypes(QScriptEngine* engine);
 
-    // Input is the unique identifier to find a n input channel of a particular device
-    // Devices are responsible for registering to the UseInputMapper so their input channels can be sued and mapped
-    // to the Action channels
-    class Input {
-    public:
-        union {
-            struct {
-                uint16 _device; // Up to 64K possible devices
-                uint16 _channel : 13; // 2^13 possible channel per Device
-                uint16 _type : 2; // 2 bits to store the Type directly in the ID
-                uint16 _padding : 1; // 2 bits to store the Type directly in the ID
-            };
-            uint32 _id = 0; // by default Input is 0 meaning invalid
-        };
-        
-        bool isValid() const { return (_id != 0); }
-        
-        uint16 getDevice() const { return _device; }
-        uint16 getChannel() const { return _channel; }
-        uint32 getID() const { return _id; }
-        ChannelType getType() const { return (ChannelType) _type; }
-        
-        void setDevice(uint16 device) { _device = device; }
-        void setChannel(uint16 channel) { _channel = channel; }
-        void setType(uint16 type) { _type = type; }
-        void setID(uint32 ID) { _id = ID; }
-
-        bool isButton() const { return getType() == ChannelType::BUTTON; }
-        bool isAxis() const { return getType() == ChannelType::AXIS; }
-        bool isPose() const { return getType() == ChannelType::POSE; }
-
-        // WORKAROUND: the explicit initializer here avoids a bug in GCC-4.8.2 (but not found in 4.9.2)
-        // where the default initializer (a C++-11ism) for the union data above is not applied.
-        explicit Input() : _id(0) {}
-        explicit Input(uint32 id) : _id(id) {}
-        explicit Input(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)), _padding(0) {}
-        Input(const Input& src) : _id(src._id) {}
-        Input& operator = (const Input& src) { _id = src._id; return (*this); }
-        bool operator ==(const Input& right) const { return _id == right._id; }
-        bool operator < (const Input& src) const { return _id < src._id; }
-
-        static const Input INVALID_INPUT;
-        static const uint16 INVALID_DEVICE;
-        static const uint16 INVALID_CHANNEL;
-        static const uint16 INVALID_TYPE;
-        static const uint16 ACTIONS_DEVICE;
-        static const uint16 STANDARD_DEVICE;
-    };
+    static const uint16 ACTIONS_DEVICE;
+    static const uint16 STANDARD_DEVICE;
 
 
     // Modifiers are just button inputID
     typedef std::vector< Input > Modifiers;
-
-    class PoseValue {
-    public:
-        glm::vec3 _translation{ 0.0f };
-        glm::quat _rotation;
-        bool _valid;
-
-        PoseValue() : _valid(false) {};
-        PoseValue(glm::vec3 translation, glm::quat rotation) : _translation(translation), _rotation(rotation), _valid(true) {}
-        PoseValue(const PoseValue&) = default;
-        PoseValue& operator = (const PoseValue&) = default;
-        bool operator ==(const PoseValue& right) const { return _translation == right.getTranslation() && _rotation == right.getRotation() && _valid == right.isValid(); }
-        
-        bool isValid() const { return _valid; }
-        glm::vec3 getTranslation() const { return _translation; }
-        glm::quat getRotation() const { return _rotation; }
-    };
-    
     typedef std::function<bool (const Input& input, int timestamp)> ButtonGetter;
     typedef std::function<float (const Input& input, int timestamp)> AxisGetter;
     typedef std::function<PoseValue (const Input& input, int timestamp)> PoseGetter;
@@ -119,22 +57,6 @@ public:
     
     typedef QVector<InputPair> AvailableInput;
 
-   class DeviceProxy {
-    public:
-       DeviceProxy(QString name) : _baseName(name), _name(name) {}
-       const QString& getBaseName() const { return _baseName; }
-       const QString& getName() const { return _name; }
-
-       QString _baseName;
-       QString _name;
-       ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
-       AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; };
-       PoseGetter getPose = [] (const Input& input, int timestamp) -> PoseValue { return PoseValue(); };
-       AvailableInputGetter getAvailabeInputs = [] () -> AvailableInput { return QVector<InputPair>(); };
-       ResetBindings resetDeviceBindings = [] () -> bool { return true; };
-       float getValue(const Input& input, int timestamp = 0) const;
-       typedef std::shared_ptr<DeviceProxy> Pointer;
-    };
     // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
     uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
 
@@ -222,7 +144,7 @@ public:
     // Return true if theinput channel is created correctly, false either
     bool addInputChannel(Action action, const Input& input, float scale = 1.0f);
     bool addInputChannel(Action action, const Input& input, const Input& modifer, float scale = 1.0f);
-    
+
     // Under the hood, the input channels are organized in map sorted on the _output
     // The InputChannel class is just the full values describing the input channel in one object 
     class InputChannel {
@@ -276,7 +198,7 @@ public:
     typedef std::map<int, DeviceProxy::Pointer> DevicesMap;
     DevicesMap getDevices() { return _registeredDevices; }
 
-    uint16 getStandardDeviceID() const { return Input::STANDARD_DEVICE; }
+    uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
     DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
 
 signals:
@@ -288,7 +210,7 @@ protected:
     StandardControllerPointer _standardController;
         
     DevicesMap _registeredDevices;
-    uint16 _nextFreeDeviceID = Input::STANDARD_DEVICE + 1;
+    uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
 
     typedef std::map<int, Modifiers> InputToMoModifiersMap;
     InputToMoModifiersMap _inputToModifiersMap;
@@ -309,6 +231,7 @@ protected:
 };
 
 Q_DECLARE_METATYPE(UserInputMapper::InputPair)
+Q_DECLARE_METATYPE(UserInputMapper::PoseValue)
 Q_DECLARE_METATYPE(QVector<UserInputMapper::InputPair>)
 Q_DECLARE_METATYPE(UserInputMapper::Input)
 Q_DECLARE_METATYPE(UserInputMapper::InputChannel)
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index aa5bbbba07..09e81f7346 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -143,3 +143,63 @@ void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
     mapper.registerDevice(_deviceID, proxy);
 }
 
+
+void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
+#ifdef HAVE_SDL2
+    const float JOYSTICK_MOVE_SPEED = 1.0f;
+    const float DPAD_MOVE_SPEED = 0.5f;
+    const float JOYSTICK_YAW_SPEED = 0.5f;
+    const float JOYSTICK_PITCH_SPEED = 0.25f;
+    const float BOOM_SPEED = 0.1f;
+
+    // Y axes are flipped (up is negative)
+    // Left Joystick: Movement, strafing
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED);
+    // Right Joystick: Camera orientation
+    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED);
+    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED);
+
+    // Dpad movement
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED);
+
+    // Button controls
+    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED);
+
+    // Zoom
+    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED);
+    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), BOOM_SPEED);
+
+    // Hold front right shoulder button for precision controls
+    // Left Joystick: Movement, strafing
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
+
+    // Right Joystick: Camera orientation
+    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
+
+    // Dpad movement
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+
+    // Button controls
+    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+
+    // Zoom
+    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
+
+    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
+
+    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
+    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A)); 
+#endif
+}
\ No newline at end of file
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h
index 8e4cdb365f..ad99774737 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.h
+++ b/libraries/input-plugins/src/input-plugins/Joystick.h
@@ -37,6 +37,7 @@ public:
 
     // Device functions
     virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
+    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
     
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 9d3d06ecb7..e8cebd8e54 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -449,6 +449,17 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, boo
 #endif // HAVE_SIXENSE
 }
 
+static const auto L0 = controller::BACK;
+static const auto L1 = controller::DL;
+static const auto L2 = controller::DD;
+static const auto L3 = controller::DR;
+static const auto L4 = controller::DU;
+static const auto R0 = controller::START;
+static const auto R1 = controller::X;
+static const auto R2 = controller::A;
+static const auto R3 = controller::B;
+static const auto R4 = controller::Y;
+
 void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) {
     // Grab the current free device ID
     _deviceID = mapper.getFreeDeviceID();
@@ -459,31 +470,75 @@ void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) {
     using namespace controller;
     proxy->getAvailabeInputs = [this]() -> QVector<UserInputMapper::InputPair> {
         QVector<UserInputMapper::InputPair> availableInputs;
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BACK), "L0"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(DL), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(DD), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(DR), "L3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(DU), "L4"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(L0), "L0"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(L1), "L1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(L2), "L2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(L3), "L3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(L4), "L4"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(LB), "LB"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(LS), "LS"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(LX), "LX"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(LY), "LY"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(LT), "LT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(START), "R0"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(X), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(A), "R2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(B), "R3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Y), "R4"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(R0), "R0"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(R1), "R1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(R2), "R2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(R3), "R3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(R4), "R4"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(RB), "RB"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(RS), "RS"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(RX), "RX"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(RY), "RY"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(RT), "RT"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT), "LeftPose"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT), "RightPose"));
         return availableInputs;
     };
     mapper.registerDevice(_deviceID, proxy);
 }
 
+void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
+    const float JOYSTICK_MOVE_SPEED = 1.0f;
+    const float JOYSTICK_YAW_SPEED = 0.5f;
+    const float JOYSTICK_PITCH_SPEED = 0.25f;
+    const float BUTTON_MOVE_SPEED = 1.0f;
+    const float BOOM_SPEED = 0.1f;
+    using namespace controller;
+
+    // Left Joystick: Movement, strafing
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(LY), JOYSTICK_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(LX), JOYSTICK_MOVE_SPEED);
+
+    // Right Joystick: Camera orientation
+    mapper.addInputChannel(UserInputMapper::YAW, makeInput(RX), JOYSTICK_YAW_SPEED);
+    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(RY), JOYSTICK_PITCH_SPEED);
+
+    // Buttons
+    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(L3), BOOM_SPEED);
+    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(L1), BOOM_SPEED);
+
+    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(R3), BUTTON_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(R1), BUTTON_MOVE_SPEED);
+
+    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(L2));
+    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(R2));
+
+    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(L4));
+    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(R4));
+
+    // FIXME
+//    mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
+//    mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
+
+    mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(LT));
+    mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(RT));
+
+    // TODO find a mechanism to allow users to navigate the context menu via
+    mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(L0));
+    mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(R0));
+
+}
+
 // virtual
 void SixenseManager::saveSettings() const {
     Settings settings;
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index 2e7dd3223d..897ca72940 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -61,6 +61,8 @@ public:
 
     // Device functions
     virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
+    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 0dfc2fe09e..dc08fd7a69 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -308,8 +308,6 @@ void ScriptEngine::init() {
 
     registerGlobalObject("Script", this);
     registerGlobalObject("Audio", &AudioScriptingInterface::getInstance());
-    auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
-    registerGlobalObject("Controller", scriptingInterface.data());
     registerGlobalObject("Entities", entityScriptingInterface.data());
     registerGlobalObject("Quat", &_quatLibrary);
     registerGlobalObject("Vec3", &_vec3Library);
@@ -319,11 +317,9 @@ void ScriptEngine::init() {
     // constants
     globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
 
-    if (scriptingInterface) {
-        scriptingInterface->registerControllerTypes(this);
-    }
-
-
+    auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
+    registerGlobalObject("Controller", scriptingInterface.data());
+    UserInputMapper::registerControllerTypes(this);
 }
 
 void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {

From 184303d3c9a817593052ec64bcc1e04fb8a2a267 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 18 Oct 2015 20:44:32 -0700
Subject: [PATCH 059/301] Using JS mappings for joystick, updating test code

---
 interface/resources/qml/TestControllers.qml   | 57 +++++++++++++++++--
 .../src/controllers/UserInputMapper.cpp       | 35 +++++++++++-
 .../src/controllers/UserInputMapper.h         |  8 ++-
 .../src/input-plugins/Joystick.cpp            |  2 +
 4 files changed, 93 insertions(+), 9 deletions(-)

diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index d8c9cb4343..137a8548ac 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -50,9 +50,38 @@ HifiControls.VrDialog {
         Row {
             spacing: 8
             Button {
-                text: "Default Mapping"
+                text: "Standard Mapping"
                 onClicked: {
                     var mapping = Controller.newMapping("Default");
+                    mapping.from(standard.LX).to(actions.TranslateX);
+                    mapping.from(standard.LY).to(actions.TranslateZ);
+                    mapping.from(standard.RY).to(actions.Pitch);
+                    mapping.from(standard.RX).to(actions.Yaw);
+                    mapping.from(standard.DU).scale(0.5).to(actions.LONGITUDINAL_FORWARD);
+                    mapping.from(standard.DD).scale(0.5).to(actions.LONGITUDINAL_BACKWARD);
+                    mapping.from(standard.DL).scale(0.5).to(actions.LATERAL_LEFT);
+                    mapping.from(standard.DR).scale(0.5).to(actions.LATERAL_RIGHT);
+                    mapping.from(standard.X).to(actions.VERTICAL_DOWN);
+                    mapping.from(standard.Y).to(actions.VERTICAL_UP);
+                    mapping.from(standard.RT).scale(0.1).to(actions.BOOM_IN);
+                    mapping.from(standard.LT).scale(0.1).to(actions.BOOM_OUT);
+                    mapping.from(standard.B).to(actions.ACTION1);
+                    mapping.from(standard.A).to(actions.ACTION2);
+                    mapping.from(standard.RB).to(actions.SHIFT);
+                    mapping.from(standard.Back).to(actions.TOGGLE_MUTE);
+                    mapping.from(standard.Start).to(actions.CONTEXT_MENU);
+                    Controller.enableMapping("Default");
+                    enabled = false;
+                    text = "Standard Built"
+                }
+            }
+            
+            Button {
+                text: root.xbox ? "XBox Mapping" : "XBox not found"
+                property bool built: false
+                enabled: root.xbox && !built
+                onClicked: {
+                    var mapping = Controller.newMapping();
                     mapping.from(xbox.A).to(standard.A);
                     mapping.from(xbox.B).to(standard.B);
                     mapping.from(xbox.X).to(standard.X);
@@ -73,14 +102,32 @@ HifiControls.VrDialog {
                     mapping.from(xbox.RX).to(standard.RX);
                     mapping.from(xbox.LT).to(standard.LT);
                     mapping.from(xbox.RT).to(standard.RT);
-                    Controller.enableMapping("Default");
-                    enabled = false;
-                    text = "Built"
+                    mapping.enable();
+                    built = false;
+                    text = "XBox Built"
                 }
             }
 
             Button {
-                text: "Build Mapping"
+                text: root.hydra ? "Hydra Mapping" : "Hydra Not Found"
+                property bool built: false
+                enabled: root.hydra && !built
+                onClicked: {
+                    var mapping = Controller.newMapping();
+                    mapping.from(hydra.LY).invert().to(standard.LY);
+                    mapping.from(hydra.LX).to(standard.LX);
+                    mapping.from(hydra.RY).invert().to(standard.RY);
+                    mapping.from(hydra.RX).to(standard.RX);
+                    mapping.from(hydra.LT).to(standard.LT);
+                    mapping.from(hydra.RT).to(standard.RT);
+                    mapping.enable();
+                    built = false;
+                    text = "Hydra Built"
+                }
+            }
+
+            Button {
+                text: "Test Mapping"
                 onClicked: {
                     var mapping = Controller.newMapping();
                     // Inverting a value
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 2c80eb98a1..672d6a2542 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -242,6 +242,12 @@ QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(ui
     return channels;
 }
 
+void fixBisectedAxis(float& full, float& negative, float& positive) {
+    full = full + (negative * -1.0f) + positive;
+    negative = full >= 0.0f ? 0.0f : full * -1.0f;
+    positive = full <= 0.0f ? 0.0f : full;
+}
+
 void UserInputMapper::update(float deltaTime) {
 
     // Reset the axis state for next loop
@@ -303,14 +309,25 @@ void UserInputMapper::update(float deltaTime) {
     }
 
     // Scale all the channel step with the scale
-    static const float EPSILON =  0.01f;
     for (auto i = 0; i < NUM_ACTIONS; i++) {
         if (_externalActionStates[i] != 0) {
             _actionStates[i] += _externalActionStates[i];
             _externalActionStates[i] = 0.0f;
         }
-        _actionStates[i] *= _actionScales[i];
+    }
 
+    // merge the bisected and non-bisected axes for now
+    fixBisectedAxis(_actionStates[TRANSLATE_X], _actionStates[LATERAL_LEFT], _actionStates[LATERAL_RIGHT]);
+    fixBisectedAxis(_actionStates[TRANSLATE_Y], _actionStates[VERTICAL_DOWN], _actionStates[VERTICAL_UP]);
+    fixBisectedAxis(_actionStates[TRANSLATE_Z], _actionStates[LONGITUDINAL_FORWARD], _actionStates[LONGITUDINAL_BACKWARD]);
+    fixBisectedAxis(_actionStates[TRANSLATE_CAMERA_Z], _actionStates[BOOM_IN], _actionStates[BOOM_OUT]);
+    fixBisectedAxis(_actionStates[ROTATE_Y], _actionStates[YAW_LEFT], _actionStates[YAW_RIGHT]);
+    fixBisectedAxis(_actionStates[ROTATE_X], _actionStates[PITCH_UP], _actionStates[PITCH_DOWN]);
+
+
+    static const float EPSILON = 0.01f;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        _actionStates[i] *= _actionScales[i];
         // Emit only on change, and emit when moving back to 0
         if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
             _lastActionStates[i] = _actionStates[i];
@@ -420,9 +437,9 @@ void UserInputMapper::createActionNames() {
 void UserInputMapper::registerStandardDevice() {
     _standardController = std::make_shared<StandardController>();
     _standardController->registerToUserInputMapper(*this);
+    _standardController->assignDefaultInputMapping(*this);
 }
 
-
 static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
 static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
 static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
@@ -481,3 +498,15 @@ void UserInputMapper::registerControllerTypes(QScriptEngine* engine) {
     qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
     qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
 }
+
+UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) {
+    return Input(STANDARD_DEVICE, button, ChannelType::BUTTON);
+}
+
+UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) {
+    return Input(STANDARD_DEVICE, axis, ChannelType::AXIS);
+}
+
+UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
+    return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
+}
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index b8bc0850cf..d463ed0482 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -21,6 +21,7 @@
 #include "Pose.h"
 #include "Input.h"
 #include "DeviceProxy.h"
+#include "StandardControls.h"
 
 class StandardController;    
 typedef std::shared_ptr<StandardController> StandardControllerPointer;
@@ -84,8 +85,9 @@ public:
         ROTATE_Z, ROLL = ROTATE_Z,
 
         TRANSLATE_CAMERA_Z,
+        NUM_COMBINED_AXES,
 
-        LEFT_HAND,
+        LEFT_HAND = NUM_COMBINED_AXES,
         RIGHT_HAND,
 
         LEFT_HAND_CLICK,
@@ -145,6 +147,10 @@ public:
     bool addInputChannel(Action action, const Input& input, float scale = 1.0f);
     bool addInputChannel(Action action, const Input& input, const Input& modifer, float scale = 1.0f);
 
+    UserInputMapper::Input makeStandardInput(controller::StandardButtonChannel button);
+    UserInputMapper::Input makeStandardInput(controller::StandardAxisChannel axis);
+    UserInputMapper::Input makeStandardInput(controller::StandardPoseChannel pose);
+
     // Under the hood, the input channels are organized in map sorted on the _output
     // The InputChannel class is just the full values describing the input channel in one object 
     class InputChannel {
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index 09e81f7346..9d9ac8bc26 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -145,6 +145,7 @@ void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
 
 
 void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
+#if 0
 #ifdef HAVE_SDL2
     const float JOYSTICK_MOVE_SPEED = 1.0f;
     const float DPAD_MOVE_SPEED = 0.5f;
@@ -202,4 +203,5 @@ void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
     mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
     mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A)); 
 #endif
+#endif
 }
\ No newline at end of file

From a8e707ced26ed5853d0f0c04dbf24e330d42ce10 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 18 Oct 2015 22:46:14 -0700
Subject: [PATCH 060/301] Correcting update order to fix mouse

---
 interface/src/Application.cpp                    | 16 ----------------
 .../scripting/ControllerScriptingInterface.cpp   | 13 ++++++++-----
 2 files changed, 8 insertions(+), 21 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index b0c0109b71..77140fc0d3 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2710,22 +2710,6 @@ void Application::update(float deltaTime) {
     auto myAvatar = getMyAvatar();
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
-  //  userInputMapper->update(deltaTime);
-
-    // This needs to go after userInputMapper->update() because of the keyboard
-    bool jointsCaptured = false;
-    auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
-    foreach(auto inputPlugin, inputPlugins) {
-        QString name = inputPlugin->getName();
-        QAction* action = Menu::getInstance()->getActionForOption(name);
-        if (action && action->isChecked()) {
-            inputPlugin->pluginUpdate(deltaTime, jointsCaptured);
-            if (inputPlugin->isJointController()) {
-                jointsCaptured = true;
-            }
-        }
-    }
-
     // Dispatch input events
     _controllerScriptingInterface->update();
 
diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp
index 931c97a7d2..1e35713e16 100644
--- a/interface/src/scripting/ControllerScriptingInterface.cpp
+++ b/interface/src/scripting/ControllerScriptingInterface.cpp
@@ -173,15 +173,18 @@ void ControllerScriptingInterface::update() {
     float delta = now - last;
     last = now;
 
-    for(auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
+    DependencyManager::get<UserInputMapper>()->update(delta);
+
+    bool jointsCaptured = false;
+    for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
         if (inputPlugin->isActive()) {
-            inputPlugin->pluginUpdate(delta, false);
+            inputPlugin->pluginUpdate(delta, jointsCaptured);
+            if (inputPlugin->isJointController()) {
+                jointsCaptured = true;
+            }
         }
     }
 
-    auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    userInputMapper->update(delta);
-
     for (auto entry : _inputControllers) {
         entry.second->update();
     }

From 22602fb6f6506c5af6f7fa04ca51573c41d393bd Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 19 Oct 2015 10:00:16 -0700
Subject: [PATCH 061/301] Fixing line endings

---
 interface/resources/qml/TestControllers.qml   |  436 +++----
 .../src/controllers/UserInputMapper.cpp       | 1024 ++++++++---------
 .../src/input-plugins/Joystick.cpp            |  412 +++----
 .../src/input-plugins/Joystick.h              |  140 +--
 4 files changed, 1006 insertions(+), 1006 deletions(-)

diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index 137a8548ac..79be877aa3 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -1,218 +1,218 @@
-import QtQuick 2.3
-import QtQuick.Controls 1.2
-import QtQuick.Layouts 1.0
-import QtQuick.Dialogs 1.0
-
-import "controller"
-import "controls" as HifiControls
-import "styles"
-
-HifiControls.VrDialog {
-    id: root
-    HifiConstants { id: hifi }
-    title: "Controller Test"
-    resizable: true
-    contentImplicitWidth: clientArea.implicitWidth
-    contentImplicitHeight: clientArea.implicitHeight
-    backgroundColor: "beige"
-
-    property var actions: Controller.Actions
-    property var standard: Controller.Standard
-    property var hydra: null
-    property var testMapping: null
-    property var xbox: null
-
-
-    Component.onCompleted: {
-        enabled = true
-        var xboxRegex = /^X360Controller/;
-        var hydraRegex = /^Hydra/;
-        for (var prop in Controller.Hardware) {
-            if(xboxRegex.test(prop)) {
-                root.xbox = Controller.Hardware[prop]
-                print("found xbox")
-                continue
-            }
-            if (hydraRegex.test(prop)) {
-                root.hydra = Controller.Hardware[prop]
-                print("found hydra")
-                continue
-            }
-        }
-    }
-
-    Column {
-        id: clientArea
-        spacing: 12
-        x: root.clientX
-        y: root.clientY
-
-        Row {
-            spacing: 8
-            Button {
-                text: "Standard Mapping"
-                onClicked: {
-                    var mapping = Controller.newMapping("Default");
-                    mapping.from(standard.LX).to(actions.TranslateX);
-                    mapping.from(standard.LY).to(actions.TranslateZ);
-                    mapping.from(standard.RY).to(actions.Pitch);
-                    mapping.from(standard.RX).to(actions.Yaw);
-                    mapping.from(standard.DU).scale(0.5).to(actions.LONGITUDINAL_FORWARD);
-                    mapping.from(standard.DD).scale(0.5).to(actions.LONGITUDINAL_BACKWARD);
-                    mapping.from(standard.DL).scale(0.5).to(actions.LATERAL_LEFT);
-                    mapping.from(standard.DR).scale(0.5).to(actions.LATERAL_RIGHT);
-                    mapping.from(standard.X).to(actions.VERTICAL_DOWN);
-                    mapping.from(standard.Y).to(actions.VERTICAL_UP);
-                    mapping.from(standard.RT).scale(0.1).to(actions.BOOM_IN);
-                    mapping.from(standard.LT).scale(0.1).to(actions.BOOM_OUT);
-                    mapping.from(standard.B).to(actions.ACTION1);
-                    mapping.from(standard.A).to(actions.ACTION2);
-                    mapping.from(standard.RB).to(actions.SHIFT);
-                    mapping.from(standard.Back).to(actions.TOGGLE_MUTE);
-                    mapping.from(standard.Start).to(actions.CONTEXT_MENU);
-                    Controller.enableMapping("Default");
-                    enabled = false;
-                    text = "Standard Built"
-                }
-            }
-            
-            Button {
-                text: root.xbox ? "XBox Mapping" : "XBox not found"
-                property bool built: false
-                enabled: root.xbox && !built
-                onClicked: {
-                    var mapping = Controller.newMapping();
-                    mapping.from(xbox.A).to(standard.A);
-                    mapping.from(xbox.B).to(standard.B);
-                    mapping.from(xbox.X).to(standard.X);
-                    mapping.from(xbox.Y).to(standard.Y);
-                    mapping.from(xbox.Up).to(standard.DU);
-                    mapping.from(xbox.Down).to(standard.DD);
-                    mapping.from(xbox.Left).to(standard.DL);
-                    mapping.from(xbox.Right).to(standard.Right);
-                    mapping.from(xbox.LB).to(standard.LB);
-                    mapping.from(xbox.RB).to(standard.RB);
-                    mapping.from(xbox.LS).to(standard.LS);
-                    mapping.from(xbox.RS).to(standard.RS);
-                    mapping.from(xbox.Start).to(standard.Start);
-                    mapping.from(xbox.Back).to(standard.Back);
-                    mapping.from(xbox.LY).to(standard.LY);
-                    mapping.from(xbox.LX).to(standard.LX);
-                    mapping.from(xbox.RY).to(standard.RY);
-                    mapping.from(xbox.RX).to(standard.RX);
-                    mapping.from(xbox.LT).to(standard.LT);
-                    mapping.from(xbox.RT).to(standard.RT);
-                    mapping.enable();
-                    built = false;
-                    text = "XBox Built"
-                }
-            }
-
-            Button {
-                text: root.hydra ? "Hydra Mapping" : "Hydra Not Found"
-                property bool built: false
-                enabled: root.hydra && !built
-                onClicked: {
-                    var mapping = Controller.newMapping();
-                    mapping.from(hydra.LY).invert().to(standard.LY);
-                    mapping.from(hydra.LX).to(standard.LX);
-                    mapping.from(hydra.RY).invert().to(standard.RY);
-                    mapping.from(hydra.RX).to(standard.RX);
-                    mapping.from(hydra.LT).to(standard.LT);
-                    mapping.from(hydra.RT).to(standard.RT);
-                    mapping.enable();
-                    built = false;
-                    text = "Hydra Built"
-                }
-            }
-
-            Button {
-                text: "Test Mapping"
-                onClicked: {
-                    var mapping = Controller.newMapping();
-                    // Inverting a value
-                    mapping.from(hydra.RY).invert().to(standard.RY);
-                    mapping.from(hydra.RX).to(standard.RX);
-                    mapping.from(hydra.LY).to(standard.LY);
-                    mapping.from(hydra.LX).to(standard.LX);
-                    // Assigning a value from a function
-                    // mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
-                    // Constrainting a value to -1, 0, or 1, with a deadzone
-//                    mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
-                    mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
-//                    mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
-//                    mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
-                    // mapping.modifier(keyboard.Ctrl).scale(2.0)
-//                    mapping.from(keyboard.A).to(actions.TranslateLeft)
-//                    mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
-//                    mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
-//                    // First loopbacks
-//                    // Then non-loopbacks by constraint level (number of inputs)
-//                    mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
-//                    mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
-//                    mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
-//                    mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
-                    testMapping = mapping;
-                    enabled = false
-                    text = "Built"
-                }
-            }
-
-            Button {
-                text: "Enable Mapping"
-                onClicked: root.testMapping.enable()
-            }
-
-            Button {
-                text: "Disable Mapping"
-                onClicked: root.testMapping.disable()
-            }
-
-            Button {
-                text: "Enable Mapping"
-                onClicked: print(Controller.getValue(root.xbox.LY));
-            }
-        }
-
-        Row {
-            Xbox { device: root.standard; label: "Standard"; width: 360 }
-        }
-        
-        Row {
-            spacing: 8
-            Xbox { device: root.xbox; label: "XBox"; width: 360 }
-            Hydra { device: root.hydra; width: 360 }
-        }
-//        Row {
-//            spacing: 8
-//            ScrollingGraph {
-//                controlId: Controller.Actions.Yaw
-//                label: "Yaw"
-//                min: -3.0
-//                max: 3.0
-//                size: 128
-//            }
-//
-//            ScrollingGraph {
-//                controlId: Controller.Actions.YAW_LEFT
-//                label: "Yaw Left"
-//                min: -3.0
-//                max: 3.0
-//                size: 128
-//            }
-//
-//            ScrollingGraph {
-//                controlId: Controller.Actions.YAW_RIGHT
-//                label: "Yaw Right"
-//                min: -3.0
-//                max: 3.0
-//                size: 128
-//            }
-//        }
-    }
-} // dialog
-
-
-
-
-
+import QtQuick 2.3
+import QtQuick.Controls 1.2
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "controller"
+import "controls" as HifiControls
+import "styles"
+
+HifiControls.VrDialog {
+    id: root
+    HifiConstants { id: hifi }
+    title: "Controller Test"
+    resizable: true
+    contentImplicitWidth: clientArea.implicitWidth
+    contentImplicitHeight: clientArea.implicitHeight
+    backgroundColor: "beige"
+
+    property var actions: Controller.Actions
+    property var standard: Controller.Standard
+    property var hydra: null
+    property var testMapping: null
+    property var xbox: null
+
+
+    Component.onCompleted: {
+        enabled = true
+        var xboxRegex = /^X360Controller/;
+        var hydraRegex = /^Hydra/;
+        for (var prop in Controller.Hardware) {
+            if(xboxRegex.test(prop)) {
+                root.xbox = Controller.Hardware[prop]
+                print("found xbox")
+                continue
+            }
+            if (hydraRegex.test(prop)) {
+                root.hydra = Controller.Hardware[prop]
+                print("found hydra")
+                continue
+            }
+        }
+    }
+
+    Column {
+        id: clientArea
+        spacing: 12
+        x: root.clientX
+        y: root.clientY
+
+        Row {
+            spacing: 8
+            Button {
+                text: "Standard Mapping"
+                onClicked: {
+                    var mapping = Controller.newMapping("Default");
+                    mapping.from(standard.LX).to(actions.TranslateX);
+                    mapping.from(standard.LY).to(actions.TranslateZ);
+                    mapping.from(standard.RY).to(actions.Pitch);
+                    mapping.from(standard.RX).to(actions.Yaw);
+                    mapping.from(standard.DU).scale(0.5).to(actions.LONGITUDINAL_FORWARD);
+                    mapping.from(standard.DD).scale(0.5).to(actions.LONGITUDINAL_BACKWARD);
+                    mapping.from(standard.DL).scale(0.5).to(actions.LATERAL_LEFT);
+                    mapping.from(standard.DR).scale(0.5).to(actions.LATERAL_RIGHT);
+                    mapping.from(standard.X).to(actions.VERTICAL_DOWN);
+                    mapping.from(standard.Y).to(actions.VERTICAL_UP);
+                    mapping.from(standard.RT).scale(0.1).to(actions.BOOM_IN);
+                    mapping.from(standard.LT).scale(0.1).to(actions.BOOM_OUT);
+                    mapping.from(standard.B).to(actions.ACTION1);
+                    mapping.from(standard.A).to(actions.ACTION2);
+                    mapping.from(standard.RB).to(actions.SHIFT);
+                    mapping.from(standard.Back).to(actions.TOGGLE_MUTE);
+                    mapping.from(standard.Start).to(actions.CONTEXT_MENU);
+                    Controller.enableMapping("Default");
+                    enabled = false;
+                    text = "Standard Built"
+                }
+            }
+            
+            Button {
+                text: root.xbox ? "XBox Mapping" : "XBox not found"
+                property bool built: false
+                enabled: root.xbox && !built
+                onClicked: {
+                    var mapping = Controller.newMapping();
+                    mapping.from(xbox.A).to(standard.A);
+                    mapping.from(xbox.B).to(standard.B);
+                    mapping.from(xbox.X).to(standard.X);
+                    mapping.from(xbox.Y).to(standard.Y);
+                    mapping.from(xbox.Up).to(standard.DU);
+                    mapping.from(xbox.Down).to(standard.DD);
+                    mapping.from(xbox.Left).to(standard.DL);
+                    mapping.from(xbox.Right).to(standard.Right);
+                    mapping.from(xbox.LB).to(standard.LB);
+                    mapping.from(xbox.RB).to(standard.RB);
+                    mapping.from(xbox.LS).to(standard.LS);
+                    mapping.from(xbox.RS).to(standard.RS);
+                    mapping.from(xbox.Start).to(standard.Start);
+                    mapping.from(xbox.Back).to(standard.Back);
+                    mapping.from(xbox.LY).to(standard.LY);
+                    mapping.from(xbox.LX).to(standard.LX);
+                    mapping.from(xbox.RY).to(standard.RY);
+                    mapping.from(xbox.RX).to(standard.RX);
+                    mapping.from(xbox.LT).to(standard.LT);
+                    mapping.from(xbox.RT).to(standard.RT);
+                    mapping.enable();
+                    built = false;
+                    text = "XBox Built"
+                }
+            }
+
+            Button {
+                text: root.hydra ? "Hydra Mapping" : "Hydra Not Found"
+                property bool built: false
+                enabled: root.hydra && !built
+                onClicked: {
+                    var mapping = Controller.newMapping();
+                    mapping.from(hydra.LY).invert().to(standard.LY);
+                    mapping.from(hydra.LX).to(standard.LX);
+                    mapping.from(hydra.RY).invert().to(standard.RY);
+                    mapping.from(hydra.RX).to(standard.RX);
+                    mapping.from(hydra.LT).to(standard.LT);
+                    mapping.from(hydra.RT).to(standard.RT);
+                    mapping.enable();
+                    built = false;
+                    text = "Hydra Built"
+                }
+            }
+
+            Button {
+                text: "Test Mapping"
+                onClicked: {
+                    var mapping = Controller.newMapping();
+                    // Inverting a value
+                    mapping.from(hydra.RY).invert().to(standard.RY);
+                    mapping.from(hydra.RX).to(standard.RX);
+                    mapping.from(hydra.LY).to(standard.LY);
+                    mapping.from(hydra.LX).to(standard.LX);
+                    // Assigning a value from a function
+                    // mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
+                    // Constrainting a value to -1, 0, or 1, with a deadzone
+//                    mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
+                    mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
+//                    mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
+//                    mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
+                    // mapping.modifier(keyboard.Ctrl).scale(2.0)
+//                    mapping.from(keyboard.A).to(actions.TranslateLeft)
+//                    mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
+//                    mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
+//                    // First loopbacks
+//                    // Then non-loopbacks by constraint level (number of inputs)
+//                    mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
+//                    mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
+//                    mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
+//                    mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
+                    testMapping = mapping;
+                    enabled = false
+                    text = "Built"
+                }
+            }
+
+            Button {
+                text: "Enable Mapping"
+                onClicked: root.testMapping.enable()
+            }
+
+            Button {
+                text: "Disable Mapping"
+                onClicked: root.testMapping.disable()
+            }
+
+            Button {
+                text: "Enable Mapping"
+                onClicked: print(Controller.getValue(root.xbox.LY));
+            }
+        }
+
+        Row {
+            Xbox { device: root.standard; label: "Standard"; width: 360 }
+        }
+        
+        Row {
+            spacing: 8
+            Xbox { device: root.xbox; label: "XBox"; width: 360 }
+            Hydra { device: root.hydra; width: 360 }
+        }
+//        Row {
+//            spacing: 8
+//            ScrollingGraph {
+//                controlId: Controller.Actions.Yaw
+//                label: "Yaw"
+//                min: -3.0
+//                max: 3.0
+//                size: 128
+//            }
+//
+//            ScrollingGraph {
+//                controlId: Controller.Actions.YAW_LEFT
+//                label: "Yaw Left"
+//                min: -3.0
+//                max: 3.0
+//                size: 128
+//            }
+//
+//            ScrollingGraph {
+//                controlId: Controller.Actions.YAW_RIGHT
+//                label: "Yaw Right"
+//                min: -3.0
+//                max: 3.0
+//                size: 128
+//            }
+//        }
+    }
+} // dialog
+
+
+
+
+
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 672d6a2542..26e03b7719 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -1,512 +1,512 @@
-//
-//  Created by Sam Gateau on 4/27/15.
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include "UserInputMapper.h"
-#include "StandardController.h"
-
-#include "Logging.h"
-
-const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - (uint16)1;
-const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
-
-// Default contruct allocate the poutput size with the current hardcoded action channels
-UserInputMapper::UserInputMapper() {
-    registerStandardDevice();
-    assignDefaulActionScales();
-    createActionNames();
-}
-
-UserInputMapper::~UserInputMapper() {
-}
-
-int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
-    if (!_deviceCounts.contains(deviceName)) {
-        _deviceCounts[deviceName] = 0;
-    }
-    _deviceCounts[deviceName] += 1;
-    return _deviceCounts[deviceName];
-}
-
-bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) {
-    int numberOfType = recordDeviceOfType(proxy->_name);
-    
-    if (numberOfType > 1) {
-        proxy->_name += QString::number(numberOfType);
-    }
-    
-    qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
-    _registeredDevices[deviceID] = proxy;
-    return true;
-    
-}
-
-
-bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) {
-    device->_name = "Standard"; // Just to make sure
-    _registeredDevices[getStandardDeviceID()] = device;
-    return true;
-}
-
-
-UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
-    auto device = _registeredDevices.find(input.getDevice());
-    if (device != _registeredDevices.end()) {
-        return (device->second);
-    } else {
-        return DeviceProxy::Pointer();
-    }
-}
-
-QString UserInputMapper::getDeviceName(uint16 deviceID) { 
-    if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
-        return _registeredDevices[deviceID]->_name;
-    }
-    return QString("unknown");
-}
-
-
-void UserInputMapper::resetAllDeviceBindings() {
-    for (auto device : _registeredDevices) {
-        device.second->resetDeviceBindings();
-    }
-}
-
-void UserInputMapper::resetDevice(uint16 deviceID) {
-    auto device = _registeredDevices.find(deviceID);
-    if (device != _registeredDevices.end()) {
-        device->second->resetDeviceBindings();
-    }
-}
-
-int UserInputMapper::findDevice(QString name) const {
-    for (auto device : _registeredDevices) {
-        if (device.second->_name.split(" (")[0] == name) {
-            return device.first;
-        } else if (device.second->_baseName == name) {
-            return device.first;
-        }
-    }
-    return Input::INVALID_DEVICE;
-}
-
-QVector<QString> UserInputMapper::getDeviceNames() {
-    QVector<QString> result;
-    for (auto device : _registeredDevices) {
-        QString deviceName = device.second->_name.split(" (")[0];
-        result << deviceName;
-    }
-    return result;
-}
-
-UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
-    
-    // Split the full input name as such: deviceName.inputName
-    auto names = inputName.split('.');
-
-    if (names.size() >= 2) {
-        // Get the device name:
-        auto deviceName = names[0];
-        auto inputName = names[1];
-
-        int deviceID = findDevice(deviceName);
-        if (deviceID != Input::INVALID_DEVICE) {
-            const auto& deviceProxy = _registeredDevices.at(deviceID);
-            auto deviceInputs = deviceProxy->getAvailabeInputs();
-
-            for (auto input : deviceInputs) {
-                if (input.second == inputName) {
-                    return input.first;
-                }
-            }
-
-            qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">";
-
-        } else if (deviceName == "Actions") {
-            deviceID = ACTIONS_DEVICE;
-            int actionNum = 0;
-            for (auto action : _actionNames) {
-                if (action == inputName) {
-                    return Input(ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
-                }
-                actionNum++;
-            }
-
-            qCDebug(controllers) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions";
-
-        } else {
-            qCDebug(controllers) << "Couldn\'t find InputDevice named <" << deviceName << ">";
-        }
-    } else {
-        qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
-    }
-
-    return Input::INVALID_INPUT;
-}
-
-
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
-    return addInputChannel(action, input, Input(), scale);
-}
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
-    // Check that the device is registered
-    if (!getDeviceProxy(input)) {
-        qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
-        return false;
-    }
-    
-    auto inputChannel = InputChannel(input, modifier, action, scale);
-
-    // Insert or replace the input to modifiers
-    if (inputChannel.hasModifier()) {
-        auto& modifiers = _inputToModifiersMap[input.getID()];
-        modifiers.push_back(inputChannel._modifier);
-        std::sort(modifiers.begin(), modifiers.end());
-    }
-
-    // Now update the action To Inputs side of things
-    _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
-
-    return true;
-}
-
-int UserInputMapper::addInputChannels(const InputChannels& channels) {
-    int nbAdded = 0;
-    for (auto& channel : channels) {
-        nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
-    }
-    return nbAdded;
-}
-
-bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
-    // Remove from Input to Modifiers map
-    if (inputChannel.hasModifier()) {
-        _inputToModifiersMap.erase(inputChannel._input.getID());
-    }
-    
-    // Remove from Action to Inputs map
-    std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
-    ret = _actionToInputsMap.equal_range(inputChannel._action);
-    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
-        if (it->second == inputChannel) {
-            _actionToInputsMap.erase(it);
-            return true;
-        }
-    }
-    
-    return false;
-}
-
-void UserInputMapper::removeAllInputChannels() {
-    _inputToModifiersMap.clear();
-    _actionToInputsMap.clear();
-}
-
-void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
-    QVector<InputChannel> channels = getAllInputsForDevice(device);
-    for (auto& channel : channels) {
-        removeInputChannel(channel);
-    }
-}
-
-void UserInputMapper::removeDevice(int device) {
-    removeAllInputChannelsForDevice((uint16) device);
-    _registeredDevices.erase(device);
-}
-
-int UserInputMapper::getInputChannels(InputChannels& channels) const {
-    for (auto& channel : _actionToInputsMap) {
-        channels.push_back(channel.second);
-    }
-
-    return _actionToInputsMap.size();
-}
-
-QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
-    InputChannels allChannels;
-    getInputChannels(allChannels);
-    
-    QVector<InputChannel> channels;
-    for (InputChannel inputChannel : allChannels) {
-        if (inputChannel._input._device == device) {
-            channels.push_back(inputChannel);
-        }
-    }
-    
-    return channels;
-}
-
-void fixBisectedAxis(float& full, float& negative, float& positive) {
-    full = full + (negative * -1.0f) + positive;
-    negative = full >= 0.0f ? 0.0f : full * -1.0f;
-    positive = full <= 0.0f ? 0.0f : full;
-}
-
-void UserInputMapper::update(float deltaTime) {
-
-    // Reset the axis state for next loop
-    for (auto& channel : _actionStates) {
-        channel = 0.0f;
-    }
-    
-    for (auto& channel : _poseStates) {
-        channel = PoseValue();
-    }
-
-    int currentTimestamp = 0;
-    for (auto& channelInput : _actionToInputsMap) {
-        auto& inputMapping = channelInput.second;
-        auto& inputID = inputMapping._input;
-        bool enabled = true;
-        
-        // Check if this input channel has modifiers and collect the possibilities
-        auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
-        if (modifiersIt != _inputToModifiersMap.end()) {
-            Modifiers validModifiers;
-            bool isActiveModifier = false;
-            for (auto& modifier : modifiersIt->second) {
-                auto deviceProxy = getDeviceProxy(modifier);
-                if (deviceProxy->getButton(modifier, currentTimestamp)) {
-                    validModifiers.push_back(modifier);
-                    isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
-                }
-            }
-            enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
-        }
-
-        // if enabled: default input or all modifiers on
-        if (enabled) {
-            auto deviceProxy = getDeviceProxy(inputID);
-            switch (inputMapping._input.getType()) {
-                case ChannelType::BUTTON: {
-                    _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
-                    break;
-                }
-                case ChannelType::AXIS: {
-                    _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
-                    break;
-                }
-                case ChannelType::POSE: {
-                    if (!_poseStates[channelInput.first].isValid()) {
-                        _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
-                    }
-                    break;
-                }
-                default: {
-                    break; //silence please
-                }
-            }
-        } else{
-            // Channel input not enabled
-            enabled = false;
-        }
-    }
-
-    // Scale all the channel step with the scale
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        if (_externalActionStates[i] != 0) {
-            _actionStates[i] += _externalActionStates[i];
-            _externalActionStates[i] = 0.0f;
-        }
-    }
-
-    // merge the bisected and non-bisected axes for now
-    fixBisectedAxis(_actionStates[TRANSLATE_X], _actionStates[LATERAL_LEFT], _actionStates[LATERAL_RIGHT]);
-    fixBisectedAxis(_actionStates[TRANSLATE_Y], _actionStates[VERTICAL_DOWN], _actionStates[VERTICAL_UP]);
-    fixBisectedAxis(_actionStates[TRANSLATE_Z], _actionStates[LONGITUDINAL_FORWARD], _actionStates[LONGITUDINAL_BACKWARD]);
-    fixBisectedAxis(_actionStates[TRANSLATE_CAMERA_Z], _actionStates[BOOM_IN], _actionStates[BOOM_OUT]);
-    fixBisectedAxis(_actionStates[ROTATE_Y], _actionStates[YAW_LEFT], _actionStates[YAW_RIGHT]);
-    fixBisectedAxis(_actionStates[ROTATE_X], _actionStates[PITCH_UP], _actionStates[PITCH_DOWN]);
-
-
-    static const float EPSILON = 0.01f;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        _actionStates[i] *= _actionScales[i];
-        // Emit only on change, and emit when moving back to 0
-        if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
-            _lastActionStates[i] = _actionStates[i];
-            emit actionEvent(i, _actionStates[i]);
-        }
-        // TODO: emit signal for pose changes
-    }
-}
-
-QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
-    QVector<Action> actions;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        actions.append(Action(i));
-    }
-    return actions;
-}
-
-QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
-    QVector<InputChannel> inputChannels;
-    std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
-    ret = _actionToInputsMap.equal_range(action);
-    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
-        inputChannels.append(it->second);
-    }
-    return inputChannels;
-}
-
-int UserInputMapper::findAction(const QString& actionName) const {
-    auto actions = getAllActions();
-    for (auto action : actions) {
-        if (getActionName(action) == actionName) {
-            return action;
-        }
-    }
-    // If the action isn't found, return -1
-    return -1;
-}
-
-QVector<QString> UserInputMapper::getActionNames() const {
-    QVector<QString> result;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        result << _actionNames[i];
-    }
-    return result;
-}
-
-void UserInputMapper::assignDefaulActionScales() {
-    _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit
-    _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit
-    _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit
-    _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit
-    _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit
-    _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit
-    _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit
-    _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit
-    _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit
-    _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
-    _actionScales[BOOM_IN] = 0.5f; // .5m per unit
-    _actionScales[BOOM_OUT] = 0.5f; // .5m per unit
-    _actionScales[LEFT_HAND] = 1.0f; // default
-    _actionScales[RIGHT_HAND] = 1.0f; // default
-    _actionScales[LEFT_HAND_CLICK] = 1.0f; // on
-    _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
-    _actionScales[SHIFT] = 1.0f; // on
-    _actionScales[ACTION1] = 1.0f; // default
-    _actionScales[ACTION2] = 1.0f; // default
-    _actionScales[TRANSLATE_X] = 1.0f; // default
-    _actionScales[TRANSLATE_Y] = 1.0f; // default
-    _actionScales[TRANSLATE_Z] = 1.0f; // default
-    _actionScales[ROLL] = 1.0f; // default
-    _actionScales[PITCH] = 1.0f; // default
-    _actionScales[YAW] = 1.0f; // default
-}
-
-// This is only necessary as long as the actions are hardcoded
-// Eventually you can just add the string when you add the action
-void UserInputMapper::createActionNames() {
-    _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
-    _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
-    _actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
-    _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
-    _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
-    _actionNames[VERTICAL_UP] = "VERTICAL_UP";
-    _actionNames[YAW_LEFT] = "YAW_LEFT";
-    _actionNames[YAW_RIGHT] = "YAW_RIGHT";
-    _actionNames[PITCH_DOWN] = "PITCH_DOWN";
-    _actionNames[PITCH_UP] = "PITCH_UP";
-    _actionNames[BOOM_IN] = "BOOM_IN";
-    _actionNames[BOOM_OUT] = "BOOM_OUT";
-    _actionNames[LEFT_HAND] = "LEFT_HAND";
-    _actionNames[RIGHT_HAND] = "RIGHT_HAND";
-    _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
-    _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
-    _actionNames[SHIFT] = "SHIFT";
-    _actionNames[ACTION1] = "ACTION1";
-    _actionNames[ACTION2] = "ACTION2";
-    _actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
-    _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
-    _actionNames[TRANSLATE_X] = "TranslateX";
-    _actionNames[TRANSLATE_Y] = "TranslateY";
-    _actionNames[TRANSLATE_Z] = "TranslateZ";
-    _actionNames[ROLL] = "Roll";
-    _actionNames[PITCH] = "Pitch";
-    _actionNames[YAW] = "Yaw";
-}
-
-void UserInputMapper::registerStandardDevice() {
-    _standardController = std::make_shared<StandardController>();
-    _standardController->registerToUserInputMapper(*this);
-    _standardController->assignDefaultInputMapping(*this);
-}
-
-static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
-static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
-static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
-
-QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input);
-void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input);
-QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action);
-void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action);
-QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair);
-void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair);
-
-QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) {
-    QScriptValue obj = engine->newObject();
-    obj.setProperty("device", input.getDevice());
-    obj.setProperty("channel", input.getChannel());
-    obj.setProperty("type", (unsigned short)input.getType());
-    obj.setProperty("id", input.getID());
-    return obj;
-}
-
-void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) {
-    input.setDevice(object.property("device").toUInt16());
-    input.setChannel(object.property("channel").toUInt16());
-    input.setType(object.property("type").toUInt16());
-    input.setID(object.property("id").toInt32());
-}
-
-QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) {
-    QScriptValue obj = engine->newObject();
-    auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    obj.setProperty("action", (int)action);
-    obj.setProperty("actionName", userInputMapper->getActionName(action));
-    return obj;
-}
-
-void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) {
-    action = UserInputMapper::Action(object.property("action").toVariant().toInt());
-}
-
-QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) {
-    QScriptValue obj = engine->newObject();
-    obj.setProperty("input", inputToScriptValue(engine, inputPair.first));
-    obj.setProperty("inputName", inputPair.second);
-    return obj;
-}
-
-void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) {
-    inputFromScriptValue(object.property("input"), inputPair.first);
-    inputPair.second = QString(object.property("inputName").toVariant().toString());
-}
-
-void UserInputMapper::registerControllerTypes(QScriptEngine* engine) {
-    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
-    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
-    qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
-    qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
-    qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
-}
-
-UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) {
-    return Input(STANDARD_DEVICE, button, ChannelType::BUTTON);
-}
-
-UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) {
-    return Input(STANDARD_DEVICE, axis, ChannelType::AXIS);
-}
-
-UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
-    return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
-}
+//
+//  Created by Sam Gateau on 4/27/15.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "UserInputMapper.h"
+#include "StandardController.h"
+
+#include "Logging.h"
+
+const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - (uint16)1;
+const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
+
+// Default contruct allocate the poutput size with the current hardcoded action channels
+UserInputMapper::UserInputMapper() {
+    registerStandardDevice();
+    assignDefaulActionScales();
+    createActionNames();
+}
+
+UserInputMapper::~UserInputMapper() {
+}
+
+int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
+    if (!_deviceCounts.contains(deviceName)) {
+        _deviceCounts[deviceName] = 0;
+    }
+    _deviceCounts[deviceName] += 1;
+    return _deviceCounts[deviceName];
+}
+
+bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) {
+    int numberOfType = recordDeviceOfType(proxy->_name);
+    
+    if (numberOfType > 1) {
+        proxy->_name += QString::number(numberOfType);
+    }
+    
+    qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
+    _registeredDevices[deviceID] = proxy;
+    return true;
+    
+}
+
+
+bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) {
+    device->_name = "Standard"; // Just to make sure
+    _registeredDevices[getStandardDeviceID()] = device;
+    return true;
+}
+
+
+UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
+    auto device = _registeredDevices.find(input.getDevice());
+    if (device != _registeredDevices.end()) {
+        return (device->second);
+    } else {
+        return DeviceProxy::Pointer();
+    }
+}
+
+QString UserInputMapper::getDeviceName(uint16 deviceID) { 
+    if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
+        return _registeredDevices[deviceID]->_name;
+    }
+    return QString("unknown");
+}
+
+
+void UserInputMapper::resetAllDeviceBindings() {
+    for (auto device : _registeredDevices) {
+        device.second->resetDeviceBindings();
+    }
+}
+
+void UserInputMapper::resetDevice(uint16 deviceID) {
+    auto device = _registeredDevices.find(deviceID);
+    if (device != _registeredDevices.end()) {
+        device->second->resetDeviceBindings();
+    }
+}
+
+int UserInputMapper::findDevice(QString name) const {
+    for (auto device : _registeredDevices) {
+        if (device.second->_name.split(" (")[0] == name) {
+            return device.first;
+        } else if (device.second->_baseName == name) {
+            return device.first;
+        }
+    }
+    return Input::INVALID_DEVICE;
+}
+
+QVector<QString> UserInputMapper::getDeviceNames() {
+    QVector<QString> result;
+    for (auto device : _registeredDevices) {
+        QString deviceName = device.second->_name.split(" (")[0];
+        result << deviceName;
+    }
+    return result;
+}
+
+UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
+    
+    // Split the full input name as such: deviceName.inputName
+    auto names = inputName.split('.');
+
+    if (names.size() >= 2) {
+        // Get the device name:
+        auto deviceName = names[0];
+        auto inputName = names[1];
+
+        int deviceID = findDevice(deviceName);
+        if (deviceID != Input::INVALID_DEVICE) {
+            const auto& deviceProxy = _registeredDevices.at(deviceID);
+            auto deviceInputs = deviceProxy->getAvailabeInputs();
+
+            for (auto input : deviceInputs) {
+                if (input.second == inputName) {
+                    return input.first;
+                }
+            }
+
+            qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">";
+
+        } else if (deviceName == "Actions") {
+            deviceID = ACTIONS_DEVICE;
+            int actionNum = 0;
+            for (auto action : _actionNames) {
+                if (action == inputName) {
+                    return Input(ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
+                }
+                actionNum++;
+            }
+
+            qCDebug(controllers) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions";
+
+        } else {
+            qCDebug(controllers) << "Couldn\'t find InputDevice named <" << deviceName << ">";
+        }
+    } else {
+        qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
+    }
+
+    return Input::INVALID_INPUT;
+}
+
+
+
+bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
+    return addInputChannel(action, input, Input(), scale);
+}
+
+bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
+    // Check that the device is registered
+    if (!getDeviceProxy(input)) {
+        qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
+        return false;
+    }
+    
+    auto inputChannel = InputChannel(input, modifier, action, scale);
+
+    // Insert or replace the input to modifiers
+    if (inputChannel.hasModifier()) {
+        auto& modifiers = _inputToModifiersMap[input.getID()];
+        modifiers.push_back(inputChannel._modifier);
+        std::sort(modifiers.begin(), modifiers.end());
+    }
+
+    // Now update the action To Inputs side of things
+    _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
+
+    return true;
+}
+
+int UserInputMapper::addInputChannels(const InputChannels& channels) {
+    int nbAdded = 0;
+    for (auto& channel : channels) {
+        nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
+    }
+    return nbAdded;
+}
+
+bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
+    // Remove from Input to Modifiers map
+    if (inputChannel.hasModifier()) {
+        _inputToModifiersMap.erase(inputChannel._input.getID());
+    }
+    
+    // Remove from Action to Inputs map
+    std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
+    ret = _actionToInputsMap.equal_range(inputChannel._action);
+    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
+        if (it->second == inputChannel) {
+            _actionToInputsMap.erase(it);
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+void UserInputMapper::removeAllInputChannels() {
+    _inputToModifiersMap.clear();
+    _actionToInputsMap.clear();
+}
+
+void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
+    QVector<InputChannel> channels = getAllInputsForDevice(device);
+    for (auto& channel : channels) {
+        removeInputChannel(channel);
+    }
+}
+
+void UserInputMapper::removeDevice(int device) {
+    removeAllInputChannelsForDevice((uint16) device);
+    _registeredDevices.erase(device);
+}
+
+int UserInputMapper::getInputChannels(InputChannels& channels) const {
+    for (auto& channel : _actionToInputsMap) {
+        channels.push_back(channel.second);
+    }
+
+    return _actionToInputsMap.size();
+}
+
+QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
+    InputChannels allChannels;
+    getInputChannels(allChannels);
+    
+    QVector<InputChannel> channels;
+    for (InputChannel inputChannel : allChannels) {
+        if (inputChannel._input._device == device) {
+            channels.push_back(inputChannel);
+        }
+    }
+    
+    return channels;
+}
+
+void fixBisectedAxis(float& full, float& negative, float& positive) {
+    full = full + (negative * -1.0f) + positive;
+    negative = full >= 0.0f ? 0.0f : full * -1.0f;
+    positive = full <= 0.0f ? 0.0f : full;
+}
+
+void UserInputMapper::update(float deltaTime) {
+
+    // Reset the axis state for next loop
+    for (auto& channel : _actionStates) {
+        channel = 0.0f;
+    }
+    
+    for (auto& channel : _poseStates) {
+        channel = PoseValue();
+    }
+
+    int currentTimestamp = 0;
+    for (auto& channelInput : _actionToInputsMap) {
+        auto& inputMapping = channelInput.second;
+        auto& inputID = inputMapping._input;
+        bool enabled = true;
+        
+        // Check if this input channel has modifiers and collect the possibilities
+        auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
+        if (modifiersIt != _inputToModifiersMap.end()) {
+            Modifiers validModifiers;
+            bool isActiveModifier = false;
+            for (auto& modifier : modifiersIt->second) {
+                auto deviceProxy = getDeviceProxy(modifier);
+                if (deviceProxy->getButton(modifier, currentTimestamp)) {
+                    validModifiers.push_back(modifier);
+                    isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
+                }
+            }
+            enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
+        }
+
+        // if enabled: default input or all modifiers on
+        if (enabled) {
+            auto deviceProxy = getDeviceProxy(inputID);
+            switch (inputMapping._input.getType()) {
+                case ChannelType::BUTTON: {
+                    _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
+                    break;
+                }
+                case ChannelType::AXIS: {
+                    _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
+                    break;
+                }
+                case ChannelType::POSE: {
+                    if (!_poseStates[channelInput.first].isValid()) {
+                        _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
+                    }
+                    break;
+                }
+                default: {
+                    break; //silence please
+                }
+            }
+        } else{
+            // Channel input not enabled
+            enabled = false;
+        }
+    }
+
+    // Scale all the channel step with the scale
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        if (_externalActionStates[i] != 0) {
+            _actionStates[i] += _externalActionStates[i];
+            _externalActionStates[i] = 0.0f;
+        }
+    }
+
+    // merge the bisected and non-bisected axes for now
+    fixBisectedAxis(_actionStates[TRANSLATE_X], _actionStates[LATERAL_LEFT], _actionStates[LATERAL_RIGHT]);
+    fixBisectedAxis(_actionStates[TRANSLATE_Y], _actionStates[VERTICAL_DOWN], _actionStates[VERTICAL_UP]);
+    fixBisectedAxis(_actionStates[TRANSLATE_Z], _actionStates[LONGITUDINAL_FORWARD], _actionStates[LONGITUDINAL_BACKWARD]);
+    fixBisectedAxis(_actionStates[TRANSLATE_CAMERA_Z], _actionStates[BOOM_IN], _actionStates[BOOM_OUT]);
+    fixBisectedAxis(_actionStates[ROTATE_Y], _actionStates[YAW_LEFT], _actionStates[YAW_RIGHT]);
+    fixBisectedAxis(_actionStates[ROTATE_X], _actionStates[PITCH_UP], _actionStates[PITCH_DOWN]);
+
+
+    static const float EPSILON = 0.01f;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        _actionStates[i] *= _actionScales[i];
+        // Emit only on change, and emit when moving back to 0
+        if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
+            _lastActionStates[i] = _actionStates[i];
+            emit actionEvent(i, _actionStates[i]);
+        }
+        // TODO: emit signal for pose changes
+    }
+}
+
+QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
+    QVector<Action> actions;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        actions.append(Action(i));
+    }
+    return actions;
+}
+
+QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
+    QVector<InputChannel> inputChannels;
+    std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
+    ret = _actionToInputsMap.equal_range(action);
+    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
+        inputChannels.append(it->second);
+    }
+    return inputChannels;
+}
+
+int UserInputMapper::findAction(const QString& actionName) const {
+    auto actions = getAllActions();
+    for (auto action : actions) {
+        if (getActionName(action) == actionName) {
+            return action;
+        }
+    }
+    // If the action isn't found, return -1
+    return -1;
+}
+
+QVector<QString> UserInputMapper::getActionNames() const {
+    QVector<QString> result;
+    for (auto i = 0; i < NUM_ACTIONS; i++) {
+        result << _actionNames[i];
+    }
+    return result;
+}
+
+void UserInputMapper::assignDefaulActionScales() {
+    _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit
+    _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit
+    _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit
+    _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit
+    _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit
+    _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit
+    _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit
+    _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit
+    _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit
+    _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
+    _actionScales[BOOM_IN] = 0.5f; // .5m per unit
+    _actionScales[BOOM_OUT] = 0.5f; // .5m per unit
+    _actionScales[LEFT_HAND] = 1.0f; // default
+    _actionScales[RIGHT_HAND] = 1.0f; // default
+    _actionScales[LEFT_HAND_CLICK] = 1.0f; // on
+    _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
+    _actionScales[SHIFT] = 1.0f; // on
+    _actionScales[ACTION1] = 1.0f; // default
+    _actionScales[ACTION2] = 1.0f; // default
+    _actionScales[TRANSLATE_X] = 1.0f; // default
+    _actionScales[TRANSLATE_Y] = 1.0f; // default
+    _actionScales[TRANSLATE_Z] = 1.0f; // default
+    _actionScales[ROLL] = 1.0f; // default
+    _actionScales[PITCH] = 1.0f; // default
+    _actionScales[YAW] = 1.0f; // default
+}
+
+// This is only necessary as long as the actions are hardcoded
+// Eventually you can just add the string when you add the action
+void UserInputMapper::createActionNames() {
+    _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
+    _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
+    _actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
+    _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
+    _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
+    _actionNames[VERTICAL_UP] = "VERTICAL_UP";
+    _actionNames[YAW_LEFT] = "YAW_LEFT";
+    _actionNames[YAW_RIGHT] = "YAW_RIGHT";
+    _actionNames[PITCH_DOWN] = "PITCH_DOWN";
+    _actionNames[PITCH_UP] = "PITCH_UP";
+    _actionNames[BOOM_IN] = "BOOM_IN";
+    _actionNames[BOOM_OUT] = "BOOM_OUT";
+    _actionNames[LEFT_HAND] = "LEFT_HAND";
+    _actionNames[RIGHT_HAND] = "RIGHT_HAND";
+    _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
+    _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
+    _actionNames[SHIFT] = "SHIFT";
+    _actionNames[ACTION1] = "ACTION1";
+    _actionNames[ACTION2] = "ACTION2";
+    _actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
+    _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
+    _actionNames[TRANSLATE_X] = "TranslateX";
+    _actionNames[TRANSLATE_Y] = "TranslateY";
+    _actionNames[TRANSLATE_Z] = "TranslateZ";
+    _actionNames[ROLL] = "Roll";
+    _actionNames[PITCH] = "Pitch";
+    _actionNames[YAW] = "Yaw";
+}
+
+void UserInputMapper::registerStandardDevice() {
+    _standardController = std::make_shared<StandardController>();
+    _standardController->registerToUserInputMapper(*this);
+    _standardController->assignDefaultInputMapping(*this);
+}
+
+static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
+static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
+static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
+
+QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input);
+void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input);
+QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action);
+void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action);
+QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair);
+void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair);
+
+QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) {
+    QScriptValue obj = engine->newObject();
+    obj.setProperty("device", input.getDevice());
+    obj.setProperty("channel", input.getChannel());
+    obj.setProperty("type", (unsigned short)input.getType());
+    obj.setProperty("id", input.getID());
+    return obj;
+}
+
+void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) {
+    input.setDevice(object.property("device").toUInt16());
+    input.setChannel(object.property("channel").toUInt16());
+    input.setType(object.property("type").toUInt16());
+    input.setID(object.property("id").toInt32());
+}
+
+QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) {
+    QScriptValue obj = engine->newObject();
+    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    obj.setProperty("action", (int)action);
+    obj.setProperty("actionName", userInputMapper->getActionName(action));
+    return obj;
+}
+
+void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) {
+    action = UserInputMapper::Action(object.property("action").toVariant().toInt());
+}
+
+QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) {
+    QScriptValue obj = engine->newObject();
+    obj.setProperty("input", inputToScriptValue(engine, inputPair.first));
+    obj.setProperty("inputName", inputPair.second);
+    return obj;
+}
+
+void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) {
+    inputFromScriptValue(object.property("input"), inputPair.first);
+    inputPair.second = QString(object.property("inputName").toVariant().toString());
+}
+
+void UserInputMapper::registerControllerTypes(QScriptEngine* engine) {
+    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
+    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
+    qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
+    qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
+    qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
+}
+
+UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) {
+    return Input(STANDARD_DEVICE, button, ChannelType::BUTTON);
+}
+
+UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) {
+    return Input(STANDARD_DEVICE, axis, ChannelType::AXIS);
+}
+
+UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
+    return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
+}
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index 9d9ac8bc26..d3e4e7a629 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -1,207 +1,207 @@
-//
-//  Joystick.cpp
-//  input-plugins/src/input-plugins
-//
-//  Created by Stephen Birarda on 2014-09-23.
-//  Copyright 2014 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include "Joystick.h"
-
-#include <limits>
-#include <glm/glm.hpp>
-
-const float CONTROLLER_THRESHOLD = 0.3f;
-
-#ifdef HAVE_SDL2
-const float MAX_AXIS = 32768.0f;
-
-Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
-        InputDevice(name),
-    _sdlGameController(sdlGameController),
-    _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
-    _instanceId(instanceId)
-{
-    
-}
-
-#endif
-
-Joystick::~Joystick() {
-    closeJoystick();
-}
-
-void Joystick::closeJoystick() {
-#ifdef HAVE_SDL2
-    SDL_GameControllerClose(_sdlGameController);
-#endif
-}
-
-void Joystick::update(float deltaTime, bool jointsCaptured) {
-    for (auto axisState : _axisStateMap) {
-        if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
-            _axisStateMap[axisState.first] = 0.0f;
-        }
-    }
-}
-
-void Joystick::focusOutEvent() {
-    _axisStateMap.clear();
-    _buttonPressedMap.clear();
-};
-
-#ifdef HAVE_SDL2
-
-void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
-    SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
-    _axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
-}
-
-void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
-    auto input = makeInput((controller::StandardButtonChannel)event.button);
-    bool newValue = event.state == SDL_PRESSED;
-    if (newValue) {
-        _buttonPressedMap.insert(input.getChannel());
-    } else {
-        _buttonPressedMap.erase(input.getChannel());
-    }
-}
-
-#endif
-
-
-void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getFreeDeviceID();
-    
-    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
-    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
-        // Buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
-
-        // DPad
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
-
-        // Bumpers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
-
-        // Stick press
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
-
-        // Center buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
-
-        // Analog sticks
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
-
-        // Triggers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
-
-        // Aliases, PlayStation style names
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
-
-        return availableInputs;
-    };
-    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
-    mapper.registerDevice(_deviceID, proxy);
-}
-
-
-void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
-#if 0
-#ifdef HAVE_SDL2
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    const float DPAD_MOVE_SPEED = 0.5f;
-    const float JOYSTICK_YAW_SPEED = 0.5f;
-    const float JOYSTICK_PITCH_SPEED = 0.25f;
-    const float BOOM_SPEED = 0.1f;
-
-    // Y axes are flipped (up is negative)
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED);
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED);
-
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED);
-
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED);
-
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), BOOM_SPEED);
-
-    // Hold front right shoulder button for precision controls
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
-
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
-
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
-
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
-
-    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
-    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A)); 
-#endif
-#endif
+//
+//  Joystick.cpp
+//  input-plugins/src/input-plugins
+//
+//  Created by Stephen Birarda on 2014-09-23.
+//  Copyright 2014 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Joystick.h"
+
+#include <limits>
+#include <glm/glm.hpp>
+
+const float CONTROLLER_THRESHOLD = 0.3f;
+
+#ifdef HAVE_SDL2
+const float MAX_AXIS = 32768.0f;
+
+Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
+        InputDevice(name),
+    _sdlGameController(sdlGameController),
+    _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
+    _instanceId(instanceId)
+{
+    
+}
+
+#endif
+
+Joystick::~Joystick() {
+    closeJoystick();
+}
+
+void Joystick::closeJoystick() {
+#ifdef HAVE_SDL2
+    SDL_GameControllerClose(_sdlGameController);
+#endif
+}
+
+void Joystick::update(float deltaTime, bool jointsCaptured) {
+    for (auto axisState : _axisStateMap) {
+        if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
+            _axisStateMap[axisState.first] = 0.0f;
+        }
+    }
+}
+
+void Joystick::focusOutEvent() {
+    _axisStateMap.clear();
+    _buttonPressedMap.clear();
+};
+
+#ifdef HAVE_SDL2
+
+void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
+    SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
+    _axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
+}
+
+void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
+    auto input = makeInput((controller::StandardButtonChannel)event.button);
+    bool newValue = event.state == SDL_PRESSED;
+    if (newValue) {
+        _buttonPressedMap.insert(input.getChannel());
+    } else {
+        _buttonPressedMap.erase(input.getChannel());
+    }
+}
+
+#endif
+
+
+void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
+    // Grab the current free device ID
+    _deviceID = mapper.getFreeDeviceID();
+    
+    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
+    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
+    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
+    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
+        QVector<UserInputMapper::InputPair> availableInputs;
+        // Buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
+
+        // DPad
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
+
+        // Bumpers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
+
+        // Stick press
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
+
+        // Center buttons
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
+
+        // Analog sticks
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
+
+        // Triggers
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
+
+        // Aliases, PlayStation style names
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
+
+        return availableInputs;
+    };
+    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
+        mapper.removeAllInputChannelsForDevice(_deviceID);
+        this->assignDefaultInputMapping(mapper);
+        return true;
+    };
+    mapper.registerDevice(_deviceID, proxy);
+}
+
+
+void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
+#if 0
+#ifdef HAVE_SDL2
+    const float JOYSTICK_MOVE_SPEED = 1.0f;
+    const float DPAD_MOVE_SPEED = 0.5f;
+    const float JOYSTICK_YAW_SPEED = 0.5f;
+    const float JOYSTICK_PITCH_SPEED = 0.25f;
+    const float BOOM_SPEED = 0.1f;
+
+    // Y axes are flipped (up is negative)
+    // Left Joystick: Movement, strafing
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED);
+    // Right Joystick: Camera orientation
+    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED);
+    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED);
+
+    // Dpad movement
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED);
+
+    // Button controls
+    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED);
+    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED);
+
+    // Zoom
+    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED);
+    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), BOOM_SPEED);
+
+    // Hold front right shoulder button for precision controls
+    // Left Joystick: Movement, strafing
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
+
+    // Right Joystick: Camera orientation
+    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
+
+    // Dpad movement
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+
+    // Button controls
+    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+
+    // Zoom
+    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
+    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
+
+    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
+
+    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
+    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A)); 
+#endif
+#endif
 }
\ No newline at end of file
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h
index ad99774737..38f00f4f15 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.h
+++ b/libraries/input-plugins/src/input-plugins/Joystick.h
@@ -1,70 +1,70 @@
-//
-//  Joystick.h
-//  input-plugins/src/input-plugins
-//
-//  Created by Stephen Birarda on 2014-09-23.
-//  Copyright 2014 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#ifndef hifi_Joystick_h
-#define hifi_Joystick_h
-
-#include <qobject.h>
-#include <qvector.h>
-
-#ifdef HAVE_SDL2
-#include <SDL.h>
-#undef main
-#endif
-
-#include <controllers/InputDevice.h>
-#include <controllers/StandardControls.h>
-
-class Joystick : public QObject, public InputDevice {
-    Q_OBJECT
-    Q_PROPERTY(QString name READ getName)
-
-#ifdef HAVE_SDL2
-    Q_PROPERTY(int instanceId READ getInstanceId)
-#endif
-    
-public:
-
-    const QString& getName() const { return _name; }
-
-    // Device functions
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
-    virtual void update(float deltaTime, bool jointsCaptured) override;
-    virtual void focusOutEvent() override;
-    
-    Joystick() : InputDevice("Joystick") {}
-    ~Joystick();
-    
-#ifdef HAVE_SDL2
-    Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
-#endif
-    
-    void closeJoystick();
-
-#ifdef HAVE_SDL2
-    void handleAxisEvent(const SDL_ControllerAxisEvent& event);
-    void handleButtonEvent(const SDL_ControllerButtonEvent& event);
-#endif
-    
-#ifdef HAVE_SDL2
-    int getInstanceId() const { return _instanceId; }
-#endif
-    
-private:
-#ifdef HAVE_SDL2
-    SDL_GameController* _sdlGameController;
-    SDL_Joystick* _sdlJoystick;
-    SDL_JoystickID _instanceId;
-#endif
-};
-
-#endif // hifi_Joystick_h
+//
+//  Joystick.h
+//  input-plugins/src/input-plugins
+//
+//  Created by Stephen Birarda on 2014-09-23.
+//  Copyright 2014 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_Joystick_h
+#define hifi_Joystick_h
+
+#include <qobject.h>
+#include <qvector.h>
+
+#ifdef HAVE_SDL2
+#include <SDL.h>
+#undef main
+#endif
+
+#include <controllers/InputDevice.h>
+#include <controllers/StandardControls.h>
+
+class Joystick : public QObject, public InputDevice {
+    Q_OBJECT
+    Q_PROPERTY(QString name READ getName)
+
+#ifdef HAVE_SDL2
+    Q_PROPERTY(int instanceId READ getInstanceId)
+#endif
+    
+public:
+
+    const QString& getName() const { return _name; }
+
+    // Device functions
+    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
+    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
+    virtual void focusOutEvent() override;
+    
+    Joystick() : InputDevice("Joystick") {}
+    ~Joystick();
+    
+#ifdef HAVE_SDL2
+    Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
+#endif
+    
+    void closeJoystick();
+
+#ifdef HAVE_SDL2
+    void handleAxisEvent(const SDL_ControllerAxisEvent& event);
+    void handleButtonEvent(const SDL_ControllerButtonEvent& event);
+#endif
+    
+#ifdef HAVE_SDL2
+    int getInstanceId() const { return _instanceId; }
+#endif
+    
+private:
+#ifdef HAVE_SDL2
+    SDL_GameController* _sdlGameController;
+    SDL_Joystick* _sdlJoystick;
+    SDL_JoystickID _instanceId;
+#endif
+};
+
+#endif // hifi_Joystick_h

From 3d8b7f9d108721605821fbc853108261f88ecb70 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Mon, 19 Oct 2015 12:56:06 -0700
Subject: [PATCH 062/301] Avoid to create a route when the source is not
 defined

---
 .../src/controllers/ScriptingInterface.cpp    |  2 +-
 .../controllers/impl/MappingBuilderProxy.cpp  | 23 +++++++++++--------
 libraries/entities/src/PolyLineEntityItem.cpp |  2 +-
 3 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index c5c7969604..3e470fd365 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -300,7 +300,7 @@ namespace controller {
                     const auto& destination = route->_destination;
                     // THis could happen if the route destination failed to create
                     // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
-                    if (!destination) {
+                    if (!source || !destination) {
                         continue;
                     }
 
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index e75068b311..bde10defdc 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -39,9 +39,14 @@ QObject* MappingBuilderProxy::from(const QScriptValue& source) {
 }
 
 QObject* MappingBuilderProxy::from(const Endpoint::Pointer& source) {
-    auto route = Route::Pointer(new Route());
-    route->_source = source;
-    return new RouteBuilderProxy(_parent, _mapping, route);
+    if (source) {
+        auto route = Route::Pointer(new Route());
+        route->_source = source;
+        return new RouteBuilderProxy(_parent, _mapping, route);
+    } else {
+        qCDebug(controllers) << "MappingBuilderProxy::from : source is null so no route created";
+        return nullptr;
+    }
 }
 
 QObject* MappingBuilderProxy::makeAxis(const QJSValue& source1, const QJSValue& source2) {
@@ -60,16 +65,16 @@ const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
 void MappingBuilderProxy::parse(const QJsonObject& json) {
     _mapping->_name = json[JSON_NAME].toString();
 
-    _mapping->_channelMappings.clear();
-    const auto& jsonChannels = json[JSON_CHANNELS].toArray();
-    for (const auto& channelIt : jsonChannels) {
+    _mapping->_channelMappings.clear();
+    const auto& jsonChannels = json[JSON_CHANNELS].toArray();
+    for (const auto& channelIt : jsonChannels) {
         parseRoute(channelIt);
     }
 }
 
 void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
     if (json.isObject()) {
-        const auto& jsonChannel = json.toObject();
+        const auto& jsonChannel = json.toObject();
 
         auto newRoute = from(jsonChannel[JSON_CHANNEL_FROM]);
         if (newRoute) {
@@ -81,8 +86,8 @@ void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
 }
 
 QObject* MappingBuilderProxy::from(const QJsonValue& json) {
-    if (json.isString()) {
-        return from(_parent.endpointFor(_parent.inputFor(json.toString())));
+    if (json.isString()) {
+        return from(_parent.endpointFor(_parent.inputFor(json.toString())));
     } else if (json.isObject()) {
         // Endpoint is defined as an object, we expect a js function then
         return nullptr;
diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp
index 352d0425bf..e2b55302d1 100644
--- a/libraries/entities/src/PolyLineEntityItem.cpp
+++ b/libraries/entities/src/PolyLineEntityItem.cpp
@@ -108,7 +108,7 @@ bool PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths) {
 
 bool PolyLineEntityItem::setNormals(const QVector<glm::vec3>& normals) {
     _normals = normals;
-    if (_points.size() < 2 || _normals.size() < 2) {
+    if (_points.size() < 2 || _normals.size() < 2 || _strokeWidths.size() < 2) {
         return false;
     }
 

From 5a0bb4c31bd7717b959aae9d2219a74bc8ba0d93 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 19 Oct 2015 16:51:31 -0700
Subject: [PATCH 063/301] Fixing line endings

---
 tests/controllers/src/main.cpp | 300 ++++++++++++++++-----------------
 1 file changed, 150 insertions(+), 150 deletions(-)

diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index ccd670640c..eb080700fa 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -1,158 +1,158 @@
-//
-//  main.cpp
-//  tests/gpu-test/src
-//
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include <unordered_map>
-#include <memory>
-#include <cstdio>
-#include <mutex>
-#include <set>
-
-#include <glm/glm.hpp>
-#include <glm/gtc/matrix_transform.hpp>
-
-#include <QtCore/QTime>
-#include <QtCore/QTimer>
-#include <QtCore/QDir>
-#include <QtCore/QElapsedTimer>
-#include <QtCore/QFile>
-#include <QtCore/QLoggingCategory>
-
-#include <QtGui/QResizeEvent>
-#include <QtGui/QWindow>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QImage>
-
-#include <QtQuick/QQuickItem>
+//
+//  main.cpp
+//  tests/gpu-test/src
+//
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <unordered_map>
+#include <memory>
+#include <cstdio>
+#include <mutex>
+#include <set>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+
+#include <QtCore/QTime>
+#include <QtCore/QTimer>
+#include <QtCore/QDir>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QFile>
+#include <QtCore/QLoggingCategory>
+
+#include <QtGui/QResizeEvent>
+#include <QtGui/QWindow>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QImage>
+
+#include <QtQuick/QQuickItem>
 #include <QtQml/QQmlApplicationEngine>
 #include <QtQml/QQmlContext>
-
-#include <plugins/Plugin.h>
-#include <plugins/PluginContainer.h>
-#include <plugins/PluginManager.h>
-#include <input-plugins/InputPlugin.h>
-#include <input-plugins/KeyboardMouseDevice.h>
-#include <controllers/ScriptingInterface.h>
-
-#include <DependencyManager.h>
-#include <controllers/UserInputMapper.h>
-
-const QString& getResourcesDir() {
-    static QString dir;
-    if (dir.isEmpty()) {
-        QDir path(__FILE__);
-        path.cdUp();
-        dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/";
-        qDebug() << "Resources Path: " << dir;
-    }
-    return dir;
-}
-
-const QString& getQmlDir() {
-    static QString dir;
-    if (dir.isEmpty()) {
-        dir = getResourcesDir() + "qml/";
-        qDebug() << "Qml Path: " << dir;
-    }
-    return dir;
-}
-
-const QString& getTestQmlDir() {
-    static QString dir;
-    if (dir.isEmpty()) {
-        QDir path(__FILE__);
-        path.cdUp();
-        dir = path.cleanPath(path.absoluteFilePath("../")) + "/qml/";
-        qDebug() << "Qml Test Path: " << dir;
-    }
-    return dir;
-}
-
-using namespace controller;
-
-
-class PluginContainerProxy : public QObject, PluginContainer {
-    Q_OBJECT
-public:
-    PluginContainerProxy() {
-        Plugin::setContainer(this);
-    }
-    virtual ~PluginContainerProxy() {}
-    virtual void addMenu(const QString& menuName) override {}
-    virtual void removeMenu(const QString& menuName) override {}
-    virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr;  }
-    virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override {}
-    virtual bool isOptionChecked(const QString& name) override { return false;  }
-    virtual void setIsOptionChecked(const QString& path, bool checked) override {}
-    virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override {}
-    virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override {}
-    virtual void showDisplayPluginsTools() override {}
-    virtual void requestReset() override {}
-    virtual QGLWidget* getPrimarySurface() override { return nullptr; }
-    virtual bool isForeground() override { return true;  }
-    virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr;  }
-};
-
-class MyControllerScriptingInterface : public controller::ScriptingInterface {
-public:
-    virtual void registerControllerTypes(QScriptEngine* engine) {};
-};
-
-
-int main(int argc, char** argv) {
-    QGuiApplication app(argc, argv);
+
+#include <plugins/Plugin.h>
+#include <plugins/PluginContainer.h>
+#include <plugins/PluginManager.h>
+#include <input-plugins/InputPlugin.h>
+#include <input-plugins/KeyboardMouseDevice.h>
+#include <controllers/ScriptingInterface.h>
+
+#include <DependencyManager.h>
+#include <controllers/UserInputMapper.h>
+
+const QString& getResourcesDir() {
+    static QString dir;
+    if (dir.isEmpty()) {
+        QDir path(__FILE__);
+        path.cdUp();
+        dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/";
+        qDebug() << "Resources Path: " << dir;
+    }
+    return dir;
+}
+
+const QString& getQmlDir() {
+    static QString dir;
+    if (dir.isEmpty()) {
+        dir = getResourcesDir() + "qml/";
+        qDebug() << "Qml Path: " << dir;
+    }
+    return dir;
+}
+
+const QString& getTestQmlDir() {
+    static QString dir;
+    if (dir.isEmpty()) {
+        QDir path(__FILE__);
+        path.cdUp();
+        dir = path.cleanPath(path.absoluteFilePath("../")) + "/qml/";
+        qDebug() << "Qml Test Path: " << dir;
+    }
+    return dir;
+}
+
+using namespace controller;
+
+
+class PluginContainerProxy : public QObject, PluginContainer {
+    Q_OBJECT
+public:
+    PluginContainerProxy() {
+        Plugin::setContainer(this);
+    }
+    virtual ~PluginContainerProxy() {}
+    virtual void addMenu(const QString& menuName) override {}
+    virtual void removeMenu(const QString& menuName) override {}
+    virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr;  }
+    virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override {}
+    virtual bool isOptionChecked(const QString& name) override { return false;  }
+    virtual void setIsOptionChecked(const QString& path, bool checked) override {}
+    virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override {}
+    virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override {}
+    virtual void showDisplayPluginsTools() override {}
+    virtual void requestReset() override {}
+    virtual QGLWidget* getPrimarySurface() override { return nullptr; }
+    virtual bool isForeground() override { return true;  }
+    virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr;  }
+};
+
+class MyControllerScriptingInterface : public controller::ScriptingInterface {
+public:
+    virtual void registerControllerTypes(QScriptEngine* engine) {};
+};
+
+
+int main(int argc, char** argv) {
+    QGuiApplication app(argc, argv);
     QQmlApplicationEngine engine;
     auto rootContext = engine.rootContext();
     new PluginContainerProxy();
-
-    // Simulate our application idle loop
-    QTimer timer;
-    QObject::connect(&timer, &QTimer::timeout, [] {
-        static float last = secTimestampNow();
-        float now = secTimestampNow();
-        float delta = now - last;
-        last = now;
-
-        foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
-            inputPlugin->pluginUpdate(delta, false);
-        }
-
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        userInputMapper->update(delta);
-    });
-    timer.start(50);
 
-    {
-        DependencyManager::set<UserInputMapper>();
-        foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
-            QString name = inputPlugin->getName();
-            inputPlugin->activate();
-            auto userInputMapper = DependencyManager::get<UserInputMapper>();
-            if (name == KeyboardMouseDevice::NAME) {
-                auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
-                keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
-            }
-            inputPlugin->pluginUpdate(0, false);
-        }
+    // Simulate our application idle loop
+    QTimer timer;
+    QObject::connect(&timer, &QTimer::timeout, [] {
+        static float last = secTimestampNow();
+        float now = secTimestampNow();
+        float delta = now - last;
+        last = now;
+
+        foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
+            inputPlugin->pluginUpdate(delta, false);
+        }
+
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        userInputMapper->update(delta);
+    });
+    timer.start(50);
+
+    {
+        DependencyManager::set<UserInputMapper>();
+        foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
+            QString name = inputPlugin->getName();
+            inputPlugin->activate();
+            auto userInputMapper = DependencyManager::get<UserInputMapper>();
+            if (name == KeyboardMouseDevice::NAME) {
+                auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
+                keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
+            }
+            inputPlugin->pluginUpdate(0, false);
+        }
         rootContext->setContextProperty("Controllers", new MyControllerScriptingInterface());
-    }
-    qDebug() << getQmlDir();
+    }
+    qDebug() << getQmlDir();
     rootContext->setContextProperty("ResourcePath", getQmlDir());
-    engine.setBaseUrl(QUrl::fromLocalFile(getQmlDir()));
-    engine.addImportPath(getQmlDir());
-    engine.load(getTestQmlDir() + "main.qml");
-    for (auto pathItem : engine.importPathList()) {
-        qDebug() << pathItem;
-    }
-    app.exec();
-    return 0;
-}
-
-#include "main.moc"
-
+    engine.setBaseUrl(QUrl::fromLocalFile(getQmlDir()));
+    engine.addImportPath(getQmlDir());
+    engine.load(getTestQmlDir() + "main.qml");
+    for (auto pathItem : engine.importPathList()) {
+        qDebug() << pathItem;
+    }
+    app.exec();
+    return 0;
+}
+
+#include "main.moc"
+

From 7669f9ed2c82d26b7231de7b861099fa22a8212d Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Mon, 19 Oct 2015 17:26:57 -0700
Subject: [PATCH 064/301] fix several warnings

---
 interface/src/scripting/ControllerScriptingInterface.cpp     | 2 +-
 libraries/controllers/src/controllers/Filter.cpp             | 4 ++--
 libraries/controllers/src/controllers/ScriptingInterface.cpp | 5 ++---
 .../controllers/src/controllers/impl/RouteBuilderProxy.h     | 3 +--
 4 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp
index 1e35713e16..f05d1a41a6 100644
--- a/interface/src/scripting/ControllerScriptingInterface.cpp
+++ b/interface/src/scripting/ControllerScriptingInterface.cpp
@@ -154,7 +154,7 @@ controller::InputController::Pointer ControllerScriptingInterface::createInputCo
             if (trackerID >= 0) {
                 controller::InputController::Pointer inputController = std::make_shared<InputController>(deviceID, trackerID, this);
                 controller::InputController::Key key = inputController->getKey();
-                _inputControllers.insert(InputControllerMap::value_type(inputController->getKey(), inputController));
+                _inputControllers.insert(InputControllerMap::value_type(key, inputController));
                 return inputController;
             }
         }
diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
index 43317fd62d..c9ff24fa78 100644
--- a/libraries/controllers/src/controllers/Filter.cpp
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -89,9 +89,9 @@ PulseFilter::FactoryEntryBuilder PulseFilter::_factoryEntryBuilder;
 
 
 float PulseFilter::apply(float value) const {
-    float result = 0.0;
+    float result = 0.0f;
 
-    if (0.0 != value) {
+    if (0.0f != value) {
         float now = secTimestampNow();
         float delta = now - _lastEmitTime;
         if (delta >= _interval) {
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 3e470fd365..dc305c4c6e 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -96,7 +96,7 @@ namespace controller {
             : Endpoint(UserInputMapper::Input(UserInputMapper::Input::INVALID_INPUT)), Pair(first, second) { }
 
         virtual float value() {
-            float result = first->value() * -1.0 + second->value();
+            float result = first->value() * -1.0f + second->value();
             return result;
         }
 
@@ -324,7 +324,6 @@ namespace controller {
                     float value = getValue(source);
 
                     // Apply each of the filters.
-                    const auto& filters = route->_filters;
                     for (const auto& filter : route->_filters) {
                         value = filter->apply(value);
                     }
@@ -406,7 +405,7 @@ namespace controller {
     }
 
     bool ScriptingInterface::isButtonPressed(int buttonIndex) const {
-        return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0 ? false : true;
+        return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0f ? false : true;
     }
 
     int ScriptingInterface::getNumberOfTriggers() const {
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 8e3b3404cc..66b5e85394 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -52,10 +52,9 @@ class RouteBuilderProxy : public QObject {
         void to(const Endpoint::Pointer& destination);
         void addFilter(Filter::Lambda lambda);
         void addFilter(Filter::Pointer filter);
+        ScriptingInterface& _parent;
         Mapping::Pointer _mapping;
         Route::Pointer _route;
-
-        ScriptingInterface& _parent;
     };
 
 }

From 0068af4cb6f10849ad5d6d3286d90b602d308321 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Mon, 19 Oct 2015 17:31:42 -0700
Subject: [PATCH 065/301] fix several warnings

---
 .../controllers/src/controllers/Filter.cpp    |  2 +-
 .../controllers/src/controllers/Route.cpp     | 29 +------------------
 2 files changed, 2 insertions(+), 29 deletions(-)

diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
index c9ff24fa78..94fb87c48e 100644
--- a/libraries/controllers/src/controllers/Filter.cpp
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -72,7 +72,7 @@ DeadZoneFilter::FactoryEntryBuilder DeadZoneFilter::_factoryEntryBuilder;
 
 float DeadZoneFilter::apply(float value) const {
     float scale = 1.0f / (1.0f - _min);
-    if (abs(value) < _min) {
+    if (std::abs(value) < _min) {
         return 0.0f;
     }
     return (value - _min) * scale;
diff --git a/libraries/controllers/src/controllers/Route.cpp b/libraries/controllers/src/controllers/Route.cpp
index b9116d2813..08b6d1f4f2 100644
--- a/libraries/controllers/src/controllers/Route.cpp
+++ b/libraries/controllers/src/controllers/Route.cpp
@@ -6,32 +6,5 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#pragma once
-#ifndef hifi_Controllers_Route_h
-#define hifi_Controllers_Route_h
 
-#include "Endpoint.h"
-#include "Filter.h"
-#include "Logging.h"
-
-class QJsonObject;
-
-namespace controller {
-
-    /*
-    * encapsulates a source, destination and filters to apply
-    */
-    class Route {
-    public:
-        Endpoint::Pointer _source;
-        Endpoint::Pointer _destination;
-        Filter::List _filters;
-
-        using Pointer = std::shared_ptr<Route>;
-        using List = std::list<Pointer>;
-
-        void parse(const QJsonObject& json);
-    };
-}
-
-#endif
+#include "Route.h"

From 9acff9497ca3c9e0ad2311590a097736ef59e70f Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Mon, 19 Oct 2015 17:34:59 -0700
Subject: [PATCH 066/301] fix several warnings

---
 libraries/controllers/src/controllers/StandardController.cpp | 2 --
 libraries/input-plugins/src/input-plugins/SixenseManager.cpp | 4 ----
 2 files changed, 6 deletions(-)

diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index 6b1ada25ed..5c13c66a07 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -15,8 +15,6 @@
 
 #include "StandardController.h"
 
-const float CONTROLLER_THRESHOLD = 0.3f;
-
 StandardController::~StandardController() {
 }
 
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index e8cebd8e54..b304f260b3 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -32,10 +32,6 @@
 Q_DECLARE_LOGGING_CATEGORY(inputplugins)
 Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins")
 
-// These bits aren't used for buttons, so they can be used as masks:
-const unsigned int LEFT_MASK = 0;
-const unsigned int RIGHT_MASK = 1U << 1;
-
 #ifdef HAVE_SIXENSE
 
 const int CALIBRATION_STATE_IDLE = 0;

From 8701d73ee957f39c6d8e27e98b9a6b47198ac545 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Mon, 19 Oct 2015 19:05:37 -0700
Subject: [PATCH 067/301] DOing the groundwork to pass along the pose still not
 working

---
 examples/controllers/controllerMappings.js    | 178 +++++++++---------
 .../controllers/src/controllers/Endpoint.h    |   7 +-
 .../src/controllers/ScriptingInterface.cpp    | 121 ++++++++++--
 .../src/controllers/ScriptingInterface.h      |   3 +
 .../src/controllers/StandardController.cpp    |   4 +-
 .../src/controllers/StandardControls.h        |   4 +-
 .../src/controllers/UserInputMapper.cpp       |  36 +++-
 .../src/controllers/UserInputMapper.h         |   7 +-
 .../src/input-plugins/SixenseManager.cpp      |   8 +-
 9 files changed, 254 insertions(+), 114 deletions(-)

diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js
index 4de173f16c..66efa63676 100644
--- a/examples/controllers/controllerMappings.js
+++ b/examples/controllers/controllerMappings.js
@@ -1,90 +1,90 @@
-
-//
-//  controllerScriptingExamples.js
-//  examples
-//
-//  Created by Sam Gondelman on 6/2/15
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-// Assumes you only have the default keyboard connected
-
-/*myFirstMapping = function() {
-return {
-    "name": "example",
-    "channels": [
-        { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
-        { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
-
-        { "from": "Keyboard.Left", "to": "Actions.LATERAL_LEFT" },
-        { "from": "Keyboard.Right", "to": "Actions.LATERAL_RIGHT" },
-
-        { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" },
-        { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" },
-
-        { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" }, 
-        { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
-        {
-            "from": "Standard.LX",
-            "filters": [ {
-                    "type": "scale",
-                    "params": [2.0],
-                }
-            ],
-            "to": "Actions.LATERAL_LEFT",
-        }, {
-            "from": "Keyboard.B",
-            "to": "Actions.Yaw"
-        }
-    ]
-}
-}
-*/
-mySecondMapping = function() {
-return {
-    "name": "example2",
-    "channels": [
-        { "from": "Standard.LY", "to": "Actions.TranslateZ" },
-        { "from": "Standard.LX", "to": "Actions.Yaw" },
-    ]
-}
-}
-
-//Script.include('mapping-test0.json');
-/*var myFirstMappingJSON = myFirstMapping();
-print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
-
-var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON));
-
-
-Controller.enableMapping("example3");
-
-var mySecondMappingJSON = mySecondMapping();
-print('mySecondMappingJSON' + JSON.stringify(mySecondMappingJSON));
-
-var mapping2 = Controller.parseMapping(JSON.stringify(mySecondMappingJSON));
-mapping2.enable();
-
-Controller.enableMapping("example2");
-*/
-var mapping3 = Controller.loadMapping(Script.resolvePath("example3.json"));
-Controller.enableMapping("example3");
-
-/*
-Object.keys(Controller.Standard).forEach(function (input) {
-    print("Controller.Standard." + input + ":" + Controller.Standard[input]);
-});
-
-Object.keys(Controller.Hardware).forEach(function (deviceName) {
-    Object.keys(Controller.Hardware[deviceName]).forEach(function (input) {
-        print("Controller.Hardware." + deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]);
-    });
-});
-
-Object.keys(Controller.Actions).forEach(function (actionName) {
-    print("Controller.Actions." + actionName + ":" + Controller.Actions[actionName]);
-});
+
+//
+//  controllerScriptingExamples.js
+//  examples
+//
+//  Created by Sam Gondelman on 6/2/15
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+// Assumes you only have the default keyboard connected
+
+/*myFirstMapping = function() {
+return {
+    "name": "example",
+    "channels": [
+        { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
+        { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
+
+        { "from": "Keyboard.Left", "to": "Actions.LATERAL_LEFT" },
+        { "from": "Keyboard.Right", "to": "Actions.LATERAL_RIGHT" },
+
+        { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" },
+        { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" },
+
+        { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" }, 
+        { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
+        {
+            "from": "Standard.LX",
+            "filters": [ {
+                    "type": "scale",
+                    "params": [2.0],
+                }
+            ],
+            "to": "Actions.LATERAL_LEFT",
+        }, {
+            "from": "Keyboard.B",
+            "to": "Actions.Yaw"
+        }
+    ]
+}
+}
+*/
+mySecondMapping = function() {
+return {
+    "name": "example2",
+    "channels": [
+        { "from": "Standard.LY", "to": "Actions.TranslateZ" },
+        { "from": "Standard.LX", "to": "Actions.Yaw" },
+    ]
+}
+}
+
+//Script.include('mapping-test0.json');
+/*var myFirstMappingJSON = myFirstMapping();
+print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
+
+var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON));
+
+
+Controller.enableMapping("example3");
+
+var mySecondMappingJSON = mySecondMapping();
+print('mySecondMappingJSON' + JSON.stringify(mySecondMappingJSON));
+
+var mapping2 = Controller.parseMapping(JSON.stringify(mySecondMappingJSON));
+mapping2.enable();
+
+Controller.enableMapping("example2");
+*/
+var mapping3 = Controller.loadMapping(Script.resolvePath("example3.json"));
+Controller.enableMapping("example3");
+
+/*
+Object.keys(Controller.Standard).forEach(function (input) {
+    print("Controller.Standard." + input + ":" + Controller.Standard[input]);
+});
+
+Object.keys(Controller.Hardware).forEach(function (deviceName) {
+    Object.keys(Controller.Hardware[deviceName]).forEach(function (input) {
+        print("Controller.Hardware." + deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]);
+    });
+});
+
+Object.keys(Controller.Actions).forEach(function (actionName) {
+    print("Controller.Actions." + actionName + ":" + Controller.Actions[actionName]);
+});
 */
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index 923412ac6c..ee549b3af8 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -35,7 +35,12 @@ namespace controller {
         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& getInput() { return _input;  }
+        virtual Pose pose() { return Pose(); }
+        virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) {}
+
+        virtual const bool isPose() { return _input.isPose(); }
+
+        const UserInputMapper::Input& getInput() { return _input; }
     protected:
         UserInputMapper::Input _input;
     };
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 3e470fd365..1c753cf750 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -35,10 +35,16 @@ namespace controller {
         }
 
         virtual float value() override { return _currentValue; }
-        virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; }
-
+        virtual void apply(float newValue, float oldValue, const Pointer& source) override {
+            _currentValue = newValue;
+        }
+        virtual Pose pose() override { return _currentPose; }
+        virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
+            _currentPose = newValue;
+        }
     private:
         float _currentValue{ 0.0f };
+        Pose _currentPose{};
     };
 
 
@@ -109,6 +115,49 @@ namespace controller {
         Endpoint::Pointer _second;
     };
 
+    class InputEndpoint : public Endpoint {
+    public:
+        InputEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT)
+            : Endpoint(id) {
+        }
+
+        virtual float value() override {
+            _currentValue = 0.0f;
+            if (isPose()) {
+                return _currentValue;
+            }
+            auto userInputMapper = DependencyManager::get<UserInputMapper>();
+            auto deviceProxy = userInputMapper->getDeviceProxy(_input);
+            if (!deviceProxy) {
+                return _currentValue;
+            }
+            _currentValue = deviceProxy->getValue(_input, 0);
+            return _currentValue;
+        }
+        virtual void apply(float newValue, float oldValue, const Pointer& source) override {}
+
+        virtual Pose pose() override {
+            _currentPose = Pose();
+            if (!isPose()) {
+                return _currentPose;
+            }
+            auto userInputMapper = DependencyManager::get<UserInputMapper>();
+            auto deviceProxy = userInputMapper->getDeviceProxy(_input);
+            if (!deviceProxy) {
+                return _currentPose;
+            }
+            _currentPose = deviceProxy->getPose(_input, 0);
+            return _currentPose;
+        }
+
+        virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
+        }
+
+    private:
+        float _currentValue{ 0.0f };
+        Pose _currentPose{};
+    };
+
     class ActionEndpoint : public Endpoint {
     public:
         ActionEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT)
@@ -125,8 +174,18 @@ namespace controller {
             }
         }
 
+        virtual Pose pose() override { return _currentPose; }
+        virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
+            _currentPose = newValue;
+            if (!(_input == UserInputMapper::Input::INVALID_INPUT)) {
+                auto userInputMapper = DependencyManager::get<UserInputMapper>();
+                userInputMapper->setActionState(UserInputMapper::Action(_input.getChannel()), _currentPose);
+            }
+        }
+
     private:
         float _currentValue{ 0.0f };
+        Pose _currentPose{};
     };
 
     QRegularExpression ScriptingInterface::SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" };
@@ -263,8 +322,34 @@ namespace controller {
         return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID());
     }
 
+
+    Pose ScriptingInterface::getPoseValue(const int& source) const {
+        if (!Input(source).isPose()) {
+            return Pose();
+        }
+
+        UserInputMapper::Input input(source);
+        auto iterator = _endpoints.find(input);
+        if (_endpoints.end() == iterator) {
+            return Pose();
+        }
+
+        const auto& endpoint = iterator->second;
+        return getPoseValue(endpoint);
+    }
+
+    Pose ScriptingInterface::getPoseValue(const Endpoint::Pointer& endpoint) const {
+      
+        /*auto valuesIterator = _overrideValues.find(endpoint);
+        if (_overrideValues.end() != valuesIterator) {
+            return valuesIterator->second;
+        }*/
+
+        return endpoint->pose();
+    }
+
     Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
-        return Pose();
+        return getPoseValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::POSE).getID());
     }
 
     void ScriptingInterface::update() {
@@ -321,18 +406,25 @@ namespace controller {
                     }
 
                     // Fetch the value, may have been overriden by previous loopback routes
-                    float value = getValue(source);
+                    if (source->isPose()) {
+                        Pose value = getPoseValue(source);
 
-                    // Apply each of the filters.
-                    const auto& filters = route->_filters;
-                    for (const auto& filter : route->_filters) {
-                        value = filter->apply(value);
-                    }
 
-                    if (loopback) {
-                        _overrideValues[source] = value;
+                        destination->apply(value, Pose(), source);
                     } else {
-                        destination->apply(value, 0, source);
+                        float value = getValue(source);
+
+                        // Apply each of the filters.
+                        const auto& filters = route->_filters;
+                        for (const auto& filter : route->_filters) {
+                            value = filter->apply(value);
+                        }
+
+                        if (loopback) {
+                            _overrideValues[source] = value;
+                        } else {
+                            destination->apply(value, 0, source);
+                        }
                     }
                 }
             }
@@ -483,13 +575,14 @@ namespace controller {
                     if (_endpoints.count(input)) {
                         continue;
                     }
-                    _endpoints[input] = std::make_shared<LambdaEndpoint>([=] {
+                   /* _endpoints[input] = std::make_shared<LambdaEndpoint>([=] {
                         auto deviceProxy = userInputMapper->getDeviceProxy(input);
                         if (!deviceProxy) {
                             return 0.0f;
                         }
                         return deviceProxy->getValue(input, 0);
-                    });
+                    });*/
+                    _endpoints[input] = std::make_shared<InputEndpoint>(input);
                 }
             }
         }
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index f473562b9e..ac3cd6b6c8 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -79,7 +79,9 @@ namespace controller {
         Q_INVOKABLE float getValue(const int& source) const;
         Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
         Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const;
+        Q_INVOKABLE Pose getPoseValue(const int& source) const;
         Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
+
         Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
         Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
         Q_INVOKABLE void disableMapping(const QString& mappingName) { enableMapping(mappingName, false); }
@@ -148,6 +150,7 @@ namespace controller {
 
         void update(Mapping::Pointer& mapping, EndpointSet& consumed);
         float getValue(const Endpoint::Pointer& endpoint) const;
+        Pose getPoseValue(const Endpoint::Pointer& endpoint) const;
         Endpoint::Pointer endpointFor(const QJSValue& endpoint);
         Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
         Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint);
diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index 6b1ada25ed..c3261bc789 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -72,8 +72,8 @@ void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
         availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
 
         // Poses
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT), "LeftPose"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT), "RightPose"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT_HAND), "LeftHand"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT_HAND), "RightHand"));
 
         // Aliases, PlayStation style names
         availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h
index 0990e34224..dc39a8bbeb 100644
--- a/libraries/controllers/src/controllers/StandardControls.h
+++ b/libraries/controllers/src/controllers/StandardControls.h
@@ -50,8 +50,8 @@ namespace controller {
 
     // No correlation to SDL
     enum StandardPoseChannel {
-        LEFT = 0,
-        RIGHT,
+        LEFT_HAND = 0,
+        RIGHT_HAND,
         HEAD,
         NUM_STANDARD_POSES
     };
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 26e03b7719..520d19f83f 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -308,12 +308,17 @@ void UserInputMapper::update(float deltaTime) {
         }
     }
 
-    // Scale all the channel step with the scale
+    //manage the external action states changes coming from the Controllers Graph
     for (auto i = 0; i < NUM_ACTIONS; i++) {
         if (_externalActionStates[i] != 0) {
             _actionStates[i] += _externalActionStates[i];
             _externalActionStates[i] = 0.0f;
         }
+
+        if (_externalPoseStates[i].isValid()) {
+            _poseStates[i] = _externalPoseStates[i];
+            _externalPoseStates[i] = PoseValue();
+        }
     }
 
     // merge the bisected and non-bisected axes for now
@@ -432,6 +437,35 @@ void UserInputMapper::createActionNames() {
     _actionNames[ROLL] = "Roll";
     _actionNames[PITCH] = "Pitch";
     _actionNames[YAW] = "Yaw";
+
+    _actionInputs[LONGITUDINAL_BACKWARD] = Input(ACTIONS_DEVICE, LONGITUDINAL_BACKWARD, ChannelType::AXIS);
+    _actionInputs[LONGITUDINAL_FORWARD] = Input(ACTIONS_DEVICE, LONGITUDINAL_BACKWARD, ChannelType::AXIS);
+    _actionInputs[LATERAL_LEFT] = Input(ACTIONS_DEVICE, LATERAL_LEFT, ChannelType::AXIS);
+    _actionInputs[LATERAL_RIGHT] = Input(ACTIONS_DEVICE, LATERAL_RIGHT, ChannelType::AXIS);
+    _actionInputs[VERTICAL_DOWN] = Input(ACTIONS_DEVICE, VERTICAL_DOWN, ChannelType::AXIS);
+    _actionInputs[VERTICAL_UP] = Input(ACTIONS_DEVICE, VERTICAL_UP, ChannelType::AXIS);
+    _actionInputs[YAW_LEFT] = Input(ACTIONS_DEVICE, YAW_LEFT, ChannelType::AXIS);
+    _actionInputs[YAW_RIGHT] = Input(ACTIONS_DEVICE, YAW_RIGHT, ChannelType::AXIS);
+    _actionInputs[PITCH_DOWN] = Input(ACTIONS_DEVICE, PITCH_DOWN, ChannelType::AXIS);
+    _actionInputs[PITCH_UP] = Input(ACTIONS_DEVICE, PITCH_UP, ChannelType::AXIS);
+    _actionInputs[BOOM_IN] = Input(ACTIONS_DEVICE, BOOM_IN, ChannelType::AXIS);
+    _actionInputs[BOOM_OUT] = Input(ACTIONS_DEVICE, BOOM_OUT, ChannelType::AXIS);
+    _actionInputs[LEFT_HAND] = Input(ACTIONS_DEVICE, LEFT_HAND, ChannelType::POSE);
+    _actionInputs[RIGHT_HAND] = Input(ACTIONS_DEVICE, RIGHT_HAND, ChannelType::POSE);
+    _actionInputs[LEFT_HAND_CLICK] = Input(ACTIONS_DEVICE, LEFT_HAND_CLICK, ChannelType::AXIS);
+    _actionInputs[RIGHT_HAND_CLICK] = Input(ACTIONS_DEVICE, RIGHT_HAND_CLICK, ChannelType::AXIS);
+    _actionInputs[SHIFT] = Input(ACTIONS_DEVICE, SHIFT, ChannelType::BUTTON);
+    _actionInputs[ACTION1] = Input(ACTIONS_DEVICE, ACTION1, ChannelType::BUTTON);
+    _actionInputs[ACTION2] = Input(ACTIONS_DEVICE, ACTION2, ChannelType::BUTTON);
+    _actionInputs[CONTEXT_MENU] = Input(ACTIONS_DEVICE, CONTEXT_MENU, ChannelType::BUTTON);
+    _actionInputs[TOGGLE_MUTE] = Input(ACTIONS_DEVICE, TOGGLE_MUTE, ChannelType::AXIS);
+    _actionInputs[TRANSLATE_X] = Input(ACTIONS_DEVICE, TRANSLATE_X, ChannelType::AXIS);
+    _actionInputs[TRANSLATE_Y] = Input(ACTIONS_DEVICE, TRANSLATE_Y, ChannelType::AXIS);
+    _actionInputs[TRANSLATE_Z] = Input(ACTIONS_DEVICE, TRANSLATE_Z, ChannelType::AXIS);
+    _actionInputs[ROLL] = Input(ACTIONS_DEVICE, ROLL, ChannelType::AXIS);
+    _actionInputs[PITCH] = Input(ACTIONS_DEVICE, PITCH, ChannelType::AXIS);
+    _actionInputs[YAW] = Input(ACTIONS_DEVICE, YAW, ChannelType::AXIS);
+
 }
 
 void UserInputMapper::registerStandardDevice() {
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index d463ed0482..c9a6af3bd8 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -134,13 +134,15 @@ public:
     QVector<Action> getAllActions() const;
     QString getActionName(Action action) const { return UserInputMapper::_actionNames[(int) action]; }
     float getActionState(Action action) const { return _actionStates[action]; }
-    PoseValue getPoseState(Action action) const { return _poseStates[action]; }
+    const PoseValue& getPoseState(Action action) const { return _poseStates[action]; }
     int findAction(const QString& actionName) const;
     QVector<QString> getActionNames() const;
+    Input getActionInput(Action action) const { return _actionInputs[action]; }
     void assignDefaulActionScales();
 
     void setActionState(Action action, float value) { _externalActionStates[action] = value; }
     void deltaActionState(Action action, float delta) { _externalActionStates[action] += delta; }
+    void setActionState(Action action, const PoseValue& value) { _externalPoseStates[action] = value; }
 
     // Add input channel to the mapper and check that all the used channels are registered.
     // Return true if theinput channel is created correctly, false either
@@ -224,11 +226,14 @@ protected:
     typedef std::multimap<Action, InputChannel> ActionToInputsMap;
     ActionToInputsMap _actionToInputsMap;
  
+    std::vector<Input> _actionInputs = std::vector<Input>(NUM_ACTIONS, Input());
+
     std::vector<float> _actionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
     std::vector<float> _externalActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
     std::vector<float> _actionScales = std::vector<float>(NUM_ACTIONS, 1.0f);
     std::vector<float> _lastActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
     std::vector<PoseValue> _poseStates = std::vector<PoseValue>(NUM_ACTIONS);
+    std::vector<PoseValue> _externalPoseStates = std::vector<PoseValue>(NUM_ACTIONS);
 
     glm::mat4 _sensorToWorldMat;
 
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index e8cebd8e54..845c51019e 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -236,7 +236,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
                 _poseStateMap.clear();
             }
         } else {
-            _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = UserInputMapper::PoseValue();
+            _poseStateMap[left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND] = UserInputMapper::PoseValue();
         }
     }
 
@@ -444,7 +444,7 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, boo
     // TODO: find a shortcut with fewer rotations.
     rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand;
 
-    _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = 
+    _poseStateMap[left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND] = 
         UserInputMapper::PoseValue(position, rotation);
 #endif // HAVE_SIXENSE
 }
@@ -490,8 +490,8 @@ void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) {
         availableInputs.append(UserInputMapper::InputPair(makeInput(RX), "RX"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(RY), "RY"));
         availableInputs.append(UserInputMapper::InputPair(makeInput(RT), "RT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT), "LeftPose"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT), "RightPose"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_HAND), "LeftHand"));
+        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_HAND), "RightHand"));
         return availableInputs;
     };
     mapper.registerDevice(_deviceID, proxy);

From 2213a4bb021962ae38aa90f77d2dc0311aed2972 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Mon, 19 Oct 2015 20:09:48 -0700
Subject: [PATCH 068/301] Do not set (just rightHand) anim var if a script has
 done so.

---
 libraries/animation/src/Rig.cpp | 8 +++++---
 libraries/animation/src/Rig.h   | 1 +
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 05be18b4cc..9737e8ded5 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -621,8 +621,8 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
             QScriptValue outboundMap = _animVars.animVariantMapToScriptValue(engine);
             QScriptValueList args;
             args << outboundMap;
-            QScriptValue inboundMap = _stateHandlers.call(QScriptValue(), args);
-            _animVars.animVariantMapFromScriptValue(inboundMap);
+            _stateHandlersResults = _stateHandlers.call(QScriptValue(), args);
+            _animVars.animVariantMapFromScriptValue(_stateHandlersResults);
             //qCDebug(animation) << _animVars.lookup("foo", QString("not set"));
         }
         // evaluate the animation
@@ -1201,7 +1201,9 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
             _animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
         }
         if (params.isRightEnabled) {
-            _animVars.set("rightHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.rightPosition);
+            if (!_stateHandlersResults.property("rightHandPosition", QScriptValue::ResolveLocal).isValid()) {
+                _animVars.set("rightHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.rightPosition);
+            }
             _animVars.set("rightHandRotation", rootBindPose.rot * yFlipHACK * params.rightOrientation);
             _animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
         } else {
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index 69eedc2155..f13de90cba 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -246,6 +246,7 @@ public:
 
 private:
     QScriptValue _stateHandlers {};
+    QScriptValue _stateHandlersResults {};
 };
 
 #endif /* defined(__hifi__Rig__) */

From ef6c4f6f665c56bd37ae31dede4241a424a95762 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 19 Oct 2015 19:31:25 -0700
Subject: [PATCH 069/301] Working on JSON parsing and cleanup

Conflicts:
	libraries/controllers/src/controllers/Route.cpp
	libraries/controllers/src/controllers/ScriptingInterface.cpp
	libraries/controllers/src/controllers/StandardController.cpp
	libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
---
 .../resources/controllers/mapping-config.json |  48 ++--
 .../resources/controllers/mapping-test0.json  |  70 +++---
 interface/resources/qml/controller/Xbox.qml   | 208 +++++++++---------
 3 files changed, 163 insertions(+), 163 deletions(-)

diff --git a/interface/resources/controllers/mapping-config.json b/interface/resources/controllers/mapping-config.json
index dd3bc7b05e..2ccd216c2f 100644
--- a/interface/resources/controllers/mapping-config.json
+++ b/interface/resources/controllers/mapping-config.json
@@ -1,24 +1,24 @@
-{
-    "name": "Full Mapping config including the standard hydra and gamepad and one more thing",
-    "mappings": [
-        { "src": "./mapping-hydra.json" },
-        { "src": "./mapping-xbox.json" },
-        {
-            "name": "example mapping for standard to js function",
-            "channels": [ {
-                    "from": "Standard.B",
-                    "to": {
-                        "type":"js",
-                        "function": "function(value){  print(\"Standard.B = \" + value );}"
-                    }
-                }, {
-                    "from": "Standard.B",
-                    "to": {
-                        "type":"js",
-                        "src": "http://www.theNextBigThing.com/hifiInputSignalHandler.js"
-                    }
-                }
-            ]
-        }
-    ]
-}
+{
+    "name": "Full Mapping config including the standard hydra and gamepad and one more thing",
+    "mappings": [
+        { "src": "./mapping-hydra.json" },
+        { "src": "./mapping-xbox.json" },
+        {
+            "name": "example mapping for standard to js function",
+            "channels": [ {
+                    "from": "Standard.B",
+                    "to": {
+                        "type":"js",
+                        "function": "function(value){  print(\"Standard.B = \" + value );}"
+                    }
+                }, {
+                    "from": "Standard.B",
+                    "to": {
+                        "type":"js",
+                        "src": "http://www.theNextBigThing.com/hifiInputSignalHandler.js"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/interface/resources/controllers/mapping-test0.json b/interface/resources/controllers/mapping-test0.json
index d6a1de5313..5232c97f19 100644
--- a/interface/resources/controllers/mapping-test0.json
+++ b/interface/resources/controllers/mapping-test0.json
@@ -1,36 +1,36 @@
-{
-    "name": "example mapping from Standard to actions",
-    "channels": [ {
-            "from": "Standard.LY",
-            "filters": [ {
-                    "type": "clamp",
-                    "min": 0,
-                    "max": 1
-                }
-            ],
-            "to": "Actions.Forward"
-        }, {
-            "from": "Standard.LY",
-            "filters": [ {
-                    "type": "clamp",
-                    "min": -1,
-                    "max": 0
-                }, {
-                    "type": "invert"
-                }
-            ],
-            "to": "Actions.Backward"
-        }, {
-            "from": "Standard.LX",
-            "filters": [ {
-                    "type": "scale",
-                    "scale": 2.0
-                }
-            ],
-            "to": "Actions.Yaw"
-        }, {
-            "from": "Standard.A",
-            "to": "Actions.Action0"
-        }
-    ]
+{
+    "name": "example mapping from Standard to actions",
+    "channels": [ {
+            "from": "Standard.LY",
+            "filters": [ {
+                    "type": "clamp",
+                    "min": 0,
+                    "max": 1
+                }
+            ],
+            "to": "Actions.Forward"
+        }, {
+            "from": "Standard.LY",
+            "filters": [ {
+                    "type": "clamp",
+                    "min": -1,
+                    "max": 0
+                }, {
+                    "type": "invert"
+                }
+            ],
+            "to": "Actions.Backward"
+        }, {
+            "from": "Standard.LX",
+            "filters": [ {
+                    "type": "scale",
+                    "scale": 2.0
+                }
+            ],
+            "to": "Actions.Yaw"
+        }, {
+            "from": "Standard.A",
+            "to": "Actions.Action0"
+        }
+    ]
 }
\ No newline at end of file
diff --git a/interface/resources/qml/controller/Xbox.qml b/interface/resources/qml/controller/Xbox.qml
index 165ac596fe..4ff2959129 100644
--- a/interface/resources/qml/controller/Xbox.qml
+++ b/interface/resources/qml/controller/Xbox.qml
@@ -1,104 +1,104 @@
-import QtQuick 2.1
-import QtQuick.Controls 1.0
-import QtQuick.Layouts 1.0
-import QtQuick.Dialogs 1.0
-
-import "xbox"
-
-Item {
-    id: root
-    property real aspect: 300.0 / 215.0
-    width: 300
-    height: width / aspect
-    property var device
-    property string label: ""
-    property real scale: width / 300.0 
-    
-    Image {
-        Text {
-            anchors.left: parent.left
-            anchors.top: parent.top
-            text: root.label
-            visible: root.label != ""
-        }
-        anchors.fill: parent
-        source: "xbox/xbox360-controller-md.png"
-
-        LeftAnalogStick {
-            device: root.device
-            x: (65 * root.scale) - width / 2; y: (42 * root.scale) - height / 2
-        }
-
-        // Left stick press
-        ToggleButton {
-            controlId: root.device.LS
-            width: 16 * root.scale; height: 16 * root.scale
-            x: (65 * root.scale) - width / 2; y: (42 * root.scale) - height / 2
-        }
-
-
-        RightAnalogStick {
-            device: root.device
-            x: (193 * root.scale) - width / 2; y: (96 * root.scale) - height / 2
-        }
-
-        // Right stick press
-        ToggleButton {
-            controlId: root.device.RS
-            width: 16 * root.scale; height: 16 * root.scale
-            x: (193 * root.scale) - width / 2; y: (96 * root.scale) - height / 2
-        }
-
-        // Left trigger
-        AnalogButton {
-            controlId: root.device.LT
-            width: 8; height: 64
-            x: (20 * root.scale); y: (7 * root.scale)
-        }
-
-        // Right trigger
-        AnalogButton {
-            controlId: root.device.RT
-            width: 8; height: 64
-            x: (272 * root.scale); y: (7 * root.scale)
-        }
-
-        // Left bumper
-        ToggleButton {
-            controlId: root.device.LB
-            width: 32 * root.scale; height: 16 * root.scale
-            x: (40 * root.scale); y: (7 * root.scale)
-        }
-
-        // Right bumper
-        ToggleButton {
-            controlId: root.device.RB
-            width: 32 * root.scale; height: 16 * root.scale
-            x: (root.width - width) - (40 * root.scale); y: (7 * root.scale)
-        }
-
-        DPad {
-            device: root.device
-            size: 48 * root.scale
-            x: (80 * root.scale); y: (71 * root.scale)
-        }
-
-        XboxButtons {
-            device: root.device
-            size: 65 * root.scale
-            x: (206 * root.scale); y: (19 * root.scale)
-        }
-
-        ToggleButton {
-            controlId: root.device.Back
-            width: 16 * root.scale; height: 12 * root.scale
-            x: (112 * root.scale); y: (45 * root.scale)
-        }
-
-        ToggleButton {
-            controlId: root.device.Start
-            width: 16 * root.scale; height: 12 * root.scale
-            x: (177 * root.scale); y: (45 * root.scale)
-        }
-    }
-}
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "xbox"
+
+Item {
+    id: root
+    property real aspect: 300.0 / 215.0
+    width: 300
+    height: width / aspect
+    property var device
+    property string label: ""
+    property real scale: width / 300.0 
+    
+    Image {
+        Text {
+            anchors.left: parent.left
+            anchors.top: parent.top
+            text: root.label
+            visible: root.label != ""
+        }
+        anchors.fill: parent
+        source: "xbox/xbox360-controller-md.png"
+
+        LeftAnalogStick {
+            device: root.device
+            x: (65 * root.scale) - width / 2; y: (42 * root.scale) - height / 2
+        }
+
+        // Left stick press
+        ToggleButton {
+            controlId: root.device.LS
+            width: 16 * root.scale; height: 16 * root.scale
+            x: (65 * root.scale) - width / 2; y: (42 * root.scale) - height / 2
+        }
+
+
+        RightAnalogStick {
+            device: root.device
+            x: (193 * root.scale) - width / 2; y: (96 * root.scale) - height / 2
+        }
+
+        // Right stick press
+        ToggleButton {
+            controlId: root.device.RS
+            width: 16 * root.scale; height: 16 * root.scale
+            x: (193 * root.scale) - width / 2; y: (96 * root.scale) - height / 2
+        }
+
+        // Left trigger
+        AnalogButton {
+            controlId: root.device.LT
+            width: 8; height: 64
+            x: (20 * root.scale); y: (7 * root.scale)
+        }
+
+        // Right trigger
+        AnalogButton {
+            controlId: root.device.RT
+            width: 8; height: 64
+            x: (272 * root.scale); y: (7 * root.scale)
+        }
+
+        // Left bumper
+        ToggleButton {
+            controlId: root.device.LB
+            width: 32 * root.scale; height: 16 * root.scale
+            x: (40 * root.scale); y: (7 * root.scale)
+        }
+
+        // Right bumper
+        ToggleButton {
+            controlId: root.device.RB
+            width: 32 * root.scale; height: 16 * root.scale
+            x: (root.width - width) - (40 * root.scale); y: (7 * root.scale)
+        }
+
+        DPad {
+            device: root.device
+            size: 48 * root.scale
+            x: (80 * root.scale); y: (71 * root.scale)
+        }
+
+        XboxButtons {
+            device: root.device
+            size: 65 * root.scale
+            x: (206 * root.scale); y: (19 * root.scale)
+        }
+
+        ToggleButton {
+            controlId: root.device.Back
+            width: 16 * root.scale; height: 12 * root.scale
+            x: (112 * root.scale); y: (45 * root.scale)
+        }
+
+        ToggleButton {
+            controlId: root.device.Start
+            width: 16 * root.scale; height: 12 * root.scale
+            x: (177 * root.scale); y: (45 * root.scale)
+        }
+    }
+}

From bea6fdd8902327ad3e1d820d616a4e20d25692f2 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 19 Oct 2015 19:31:25 -0700
Subject: [PATCH 070/301] Working on JSON parsing and cleanup

Conflicts:
	libraries/controllers/src/controllers/Route.cpp
	libraries/controllers/src/controllers/ScriptingInterface.cpp
	libraries/controllers/src/controllers/StandardController.cpp
	libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
---
 .../resources/controllers/keyboardMouse.json  |  25 +
 interface/resources/controllers/standard.json |  41 +
 interface/resources/controllers/xbox.json     |  40 +-
 interface/resources/qml/TestControllers.qml   |   2 +-
 interface/src/Application.cpp                 |  66 +-
 interface/src/Application.h                   |   2 +-
 interface/src/devices/3DConnexionClient.cpp   | 153 ++--
 interface/src/devices/3DConnexionClient.h     |  28 +-
 .../ControllerScriptingInterface.cpp          |  25 -
 .../scripting/ControllerScriptingInterface.h  |   2 -
 interface/src/ui/ApplicationCompositor.cpp    |   2 +-
 interface/src/ui/PreferencesDialog.cpp        |   4 +-
 .../controllers/src/controllers/Actions.cpp   |  71 ++
 .../controllers/src/controllers/Actions.h     | 100 +++
 .../src/controllers/DeviceProxy.cpp           |   2 +-
 .../controllers/src/controllers/DeviceProxy.h |  24 +-
 .../controllers/src/controllers/Endpoint.h    |  14 +-
 libraries/controllers/src/controllers/Input.h |  39 +-
 .../src/controllers/InputDevice.cpp           | 107 +--
 .../controllers/src/controllers/InputDevice.h |  45 +-
 .../controllers/src/controllers/Mapping.cpp   |   8 -
 .../controllers/src/controllers/Mapping.h     |   8 +-
 .../controllers/src/controllers/Pose.cpp      |   8 +-
 libraries/controllers/src/controllers/Pose.h  |  20 +-
 .../controllers/src/controllers/Route.cpp     |   1 -
 libraries/controllers/src/controllers/Route.h |   9 +-
 .../src/controllers/ScriptingInterface.cpp    | 620 +++----------
 .../src/controllers/ScriptingInterface.h      |  83 +-
 .../src/controllers/StandardController.cpp    | 213 ++---
 .../src/controllers/StandardController.h      |  24 +-
 .../src/controllers/UserInputMapper.cpp       | 830 ++++++++++++------
 .../src/controllers/UserInputMapper.h         | 351 +++-----
 .../controllers/impl/MappingBuilderProxy.cpp  |  46 +-
 .../controllers/impl/MappingBuilderProxy.h    |  13 +-
 .../controllers/impl/RouteBuilderProxy.cpp    |  40 +-
 .../src/controllers/impl/RouteBuilderProxy.h  |  13 +-
 libraries/entities-renderer/CMakeLists.txt    |   2 +-
 .../src/input-plugins/Joystick.cpp            | 190 ++--
 .../src/input-plugins/Joystick.h              |  10 +-
 .../src/input-plugins/KeyboardMouseDevice.cpp | 240 +++--
 .../src/input-plugins/KeyboardMouseDevice.h   |  16 +-
 .../src/input-plugins/SDL2Manager.cpp         |  19 +-
 .../src/input-plugins/SixenseManager.cpp      | 168 ++--
 .../src/input-plugins/SixenseManager.h        |   6 +-
 .../input-plugins/ViveControllerManager.cpp   | 258 +++---
 .../src/input-plugins/ViveControllerManager.h |  39 +-
 libraries/script-engine/src/ScriptEngine.cpp  |   4 +-
 libraries/script-engine/src/ScriptEngine.h    |   2 -
 tests/controllers/src/main.cpp                |   8 +-
 49 files changed, 1925 insertions(+), 2116 deletions(-)
 create mode 100644 interface/resources/controllers/keyboardMouse.json
 create mode 100644 interface/resources/controllers/standard.json
 create mode 100644 libraries/controllers/src/controllers/Actions.cpp
 create mode 100644 libraries/controllers/src/controllers/Actions.h

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
new file mode 100644
index 0000000000..71450a0c48
--- /dev/null
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -0,0 +1,25 @@
+{
+    "name": "Keyboard/Mouse to Actions",
+    "channels": [
+        { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
+        { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" }, 
+        { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" }, 
+        { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" }, 
+        { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, 
+        { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, 
+        { "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" }, 
+        { "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" }, 
+        { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
+        { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
+        { "from": "Keyboard.Up", "to": "Actions.LONGITUDINAL_FORWARD" },
+        { "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" }, 
+        { "from": "Keyboard.Left", "to": "Actions.YAW_LEFT" }, 
+        { "from": "Keyboard.Right", "to": "Actions.YAW_RIGHT" }, 
+        { "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
+        { "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },
+        { "from": "Keyboard.MouseMoveLeft", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_LEFT" }, 
+        { "from": "Keyboard.MouseMoveRight", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_RIGHT" }, 
+        { "from": "Keyboard.MouseMoveUp", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_UP" },
+        { "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_DOWN" }
+    ]
+}
diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
new file mode 100644
index 0000000000..364d24ae16
--- /dev/null
+++ b/interface/resources/controllers/standard.json
@@ -0,0 +1,41 @@
+{
+    "name": "Standard to Action",
+    "channels": [
+        { "from": "Standard.LY", "to": "Actions.TranslateZ" },
+        { "from": "Standard.LX", "to": "Actions.TranslateX" },
+        { "from": "Standard.RX", "to": "Actions.Yaw" },
+        { "from": "Standard.RY", "to": "Actions.Pitch" },
+        {
+            "from": "Standard.DU", 
+            "to": "Actions.LONGITUDINAL_FORWARD",
+            "filters": [ { "type": "scale", "scale": 0.5 } ]
+        },
+        { 
+            "from": "Standard.DD", 
+            "to": "Actions.LONGITUDINAL_BACKWARD",
+            "filters": [ { "type": "scale", "scale": 0.5 } ]
+        },
+        { 
+            "from": "Standard.DR", 
+            "to": "Actions.LATERAL_RIGHT",
+            "filters": [ { "type": "scale", "scale": 0.5 } ]
+        },
+        { 
+            "from": "Standard.DL", 
+            "to": "Actions.LATERAL_LEFT",
+            "filters": [ { "type": "scale", "scale": 0.5 } ]
+        },
+        { "from": "Standard.Y", "to": "Actions.VERTICAL_UP" },
+        { "from": "Standard.X", "to": "Actions.VERTICAL_DOWN" },
+        { 
+            "from": "Standard.RT", 
+            "to": "Actions.BOOM_IN", 
+            "filters": [ { "type": "scale", "scale": 0.1 } ]
+        },
+        { 
+            "from": "Standard.LT", 
+            "to": "Actions.BOOM_OUT", 
+            "filters": [ { "type": "scale", "scale": 0.1 } ]
+        }
+    ]
+}
diff --git a/interface/resources/controllers/xbox.json b/interface/resources/controllers/xbox.json
index bf96320707..8c341dff83 100644
--- a/interface/resources/controllers/xbox.json
+++ b/interface/resources/controllers/xbox.json
@@ -1,29 +1,29 @@
 {
     "name": "XBox to Standard",
     "channels": [
-        { "from": "XBox.LY", "to": "Standard.LY" }, 
-        { "from": "XBox.LX", "to": "Standard.LX" },
-        { "from": "XBox.LT", "to": "Standard.LT" }, 
-        { "from": "XBox.LB", "to": "Standard.LB" }, 
-        { "from": "XBox.LS", "to": "Standard.LS" },
+        { "from": "GamePad.LY", "to": "Standard.LY" }, 
+        { "from": "GamePad.LX", "to": "Standard.LX" },
+        { "from": "GamePad.LT", "to": "Standard.LT" }, 
+        { "from": "GamePad.LB", "to": "Standard.LB" }, 
+        { "from": "GamePad.LS", "to": "Standard.LS" },
 
-        { "from": "XBox.RY", "to": "Standard.RY" }, 
-        { "from": "XBox.RX", "to": "Standard.RX" },
-        { "from": "XBox.RT", "to": "Standard.RT" }, 
-        { "from": "XBox.RB", "to": "Standard.RB" }, 
-        { "from": "XBox.RS", "to": "Standard.RS" },
+        { "from": "GamePad.RY", "to": "Standard.RY" }, 
+        { "from": "GamePad.RX", "to": "Standard.RX" },
+        { "from": "GamePad.RT", "to": "Standard.RT" }, 
+        { "from": "GamePad.RB", "to": "Standard.RB" }, 
+        { "from": "GamePad.RS", "to": "Standard.RS" },
 
-        { "from": "XBox.Back", "to": "Standard.Back" }, 
-        { "from": "XBox.Start", "to": "Standard.Start" }, 
+        { "from": "GamePad.Back", "to": "Standard.Back" }, 
+        { "from": "GamePad.Start", "to": "Standard.Start" }, 
         
-        { "from": "XBox.DU", "to": "Standard.DU" },
-        { "from": "XBox.DD", "to": "Standard.DD" }, 
-        { "from": "XBox.DL", "to": "Standard.DL" },
-        { "from": "XBox.DR", "to": "Standard.DR" }, 
+        { "from": "GamePad.DU", "to": "Standard.DU" },
+        { "from": "GamePad.DD", "to": "Standard.DD" }, 
+        { "from": "GamePad.DL", "to": "Standard.DL" },
+        { "from": "GamePad.DR", "to": "Standard.DR" }, 
 
-        { "from": "XBox.A", "to": "Standard.A" }, 
-        { "from": "XBox.B", "to": "Standard.B" }, 
-        { "from": "XBox.X", "to": "Standard.X" },
-        { "from": "XBox.Y", "to": "Standard.Y" }
+        { "from": "GamePad.A", "to": "Standard.A" }, 
+        { "from": "GamePad.B", "to": "Standard.B" }, 
+        { "from": "GamePad.X", "to": "Standard.X" },
+        { "from": "GamePad.Y", "to": "Standard.Y" }
     ]
 }
diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index 79be877aa3..e409b7a4a4 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -25,7 +25,7 @@ HifiControls.VrDialog {
 
     Component.onCompleted: {
         enabled = true
-        var xboxRegex = /^X360Controller/;
+        var xboxRegex = /^GamePad/;
         var hydraRegex = /^Hydra/;
         for (var prop in Controller.Hardware) {
             if(xboxRegex.test(prop)) {
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 77140fc0d3..c3eb3dfe7c 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -631,7 +631,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
         if (state) {
             switch (action) {
-            case UserInputMapper::Action::TOGGLE_MUTE:
+            case controller::Action::TOGGLE_MUTE:
                 DependencyManager::get<AudioClient>()->toggleMute();
                 break;
             }
@@ -639,8 +639,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     });
 
     // Setup the keyboardMouseDevice and the user input mapper with the default bindings
-    _keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
-    _keyboardMouseDevice->assignDefaultInputMapping(*userInputMapper);
+    userInputMapper->registerDevice(_keyboardMouseDevice);
 
     // check first run...
     if (_firstRun.get()) {
@@ -2182,7 +2181,7 @@ float Application::getAvatarSimrate() {
 }
 
 void Application::setLowVelocityFilter(bool lowVelocityFilter) {
-    InputDevice::setLowVelocityFilter(lowVelocityFilter);
+    controller::InputDevice::setLowVelocityFilter(lowVelocityFilter);
 }
 
 ivec2 Application::getMouse() const {
@@ -2710,19 +2709,28 @@ void Application::update(float deltaTime) {
     auto myAvatar = getMyAvatar();
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
-    // Dispatch input events
-    _controllerScriptingInterface->update();
+    userInputMapper->update(deltaTime);
+
+    bool jointsCaptured = false;
+    for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
+        if (inputPlugin->isActive()) {
+            inputPlugin->pluginUpdate(deltaTime, jointsCaptured);
+            if (inputPlugin->isJointController()) {
+                jointsCaptured = true;
+            }
+        }
+    }
 
     // Transfer the user inputs to the driveKeys
     myAvatar->clearDriveKeys();
     if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
         if (!_controllerScriptingInterface->areActionsCaptured()) {
-            myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
-            myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
-            myAvatar->setDriveKeys(UP, userInputMapper->getActionState(UserInputMapper::VERTICAL_UP));
-            myAvatar->setDriveKeys(DOWN, userInputMapper->getActionState(UserInputMapper::VERTICAL_DOWN));
-            myAvatar->setDriveKeys(LEFT, userInputMapper->getActionState(UserInputMapper::LATERAL_LEFT));
-            myAvatar->setDriveKeys(RIGHT, userInputMapper->getActionState(UserInputMapper::LATERAL_RIGHT));
+            myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(controller::LONGITUDINAL_FORWARD));
+            myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(controller::LONGITUDINAL_BACKWARD));
+            myAvatar->setDriveKeys(UP, userInputMapper->getActionState(controller::VERTICAL_UP));
+            myAvatar->setDriveKeys(DOWN, userInputMapper->getActionState(controller::VERTICAL_DOWN));
+            myAvatar->setDriveKeys(LEFT, userInputMapper->getActionState(controller::LATERAL_LEFT));
+            myAvatar->setDriveKeys(RIGHT, userInputMapper->getActionState(controller::LATERAL_RIGHT));
             if (deltaTime > FLT_EPSILON) {
                 // For rotations what we really want are meausures of "angles per second" (in order to prevent 
                 // fps-dependent spin rates) so we need to scale the units of the controller contribution.
@@ -2730,25 +2738,25 @@ void Application::update(float deltaTime) {
                 // controllers to provide a delta_per_second value rather than a raw delta.)
                 const float EXPECTED_FRAME_RATE = 60.0f;
                 float timeFactor = EXPECTED_FRAME_RATE * deltaTime;
-                myAvatar->setDriveKeys(ROT_UP, userInputMapper->getActionState(UserInputMapper::PITCH_UP) / timeFactor);
-                myAvatar->setDriveKeys(ROT_DOWN, userInputMapper->getActionState(UserInputMapper::PITCH_DOWN) / timeFactor);
-                myAvatar->setDriveKeys(ROT_LEFT, userInputMapper->getActionState(UserInputMapper::YAW_LEFT) / timeFactor);
-                myAvatar->setDriveKeys(ROT_RIGHT, userInputMapper->getActionState(UserInputMapper::YAW_RIGHT) / timeFactor);
+                myAvatar->setDriveKeys(ROT_UP, userInputMapper->getActionState(controller::PITCH_UP) / timeFactor);
+                myAvatar->setDriveKeys(ROT_DOWN, userInputMapper->getActionState(controller::PITCH_DOWN) / timeFactor);
+                myAvatar->setDriveKeys(ROT_LEFT, userInputMapper->getActionState(controller::YAW_LEFT) / timeFactor);
+                myAvatar->setDriveKeys(ROT_RIGHT, userInputMapper->getActionState(controller::YAW_RIGHT) / timeFactor);
             }
         }
-        myAvatar->setDriveKeys(BOOM_IN, userInputMapper->getActionState(UserInputMapper::BOOM_IN));
-        myAvatar->setDriveKeys(BOOM_OUT, userInputMapper->getActionState(UserInputMapper::BOOM_OUT));
+        myAvatar->setDriveKeys(BOOM_IN, userInputMapper->getActionState(controller::BOOM_IN));
+        myAvatar->setDriveKeys(BOOM_OUT, userInputMapper->getActionState(controller::BOOM_OUT));
     }
-    UserInputMapper::PoseValue leftHand = userInputMapper->getPoseState(UserInputMapper::LEFT_HAND);
-    UserInputMapper::PoseValue rightHand = userInputMapper->getPoseState(UserInputMapper::RIGHT_HAND);
+    controller::Pose leftHand = userInputMapper->getPoseState(controller::LEFT_HAND);
+    controller::Pose rightHand = userInputMapper->getPoseState(controller::RIGHT_HAND);
     Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
-    setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK));
-    setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK));
+    setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(controller::LEFT_HAND_CLICK));
+    setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(controller::RIGHT_HAND_CLICK));
     if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
-        emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK),
-            userInputMapper->getActionState(UserInputMapper::SHIFT), LEFT_HAND_INDEX);
-        emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK),
-            userInputMapper->getActionState(UserInputMapper::SHIFT), RIGHT_HAND_INDEX);
+        emulateMouse(hand, userInputMapper->getActionState(controller::LEFT_HAND_CLICK),
+            userInputMapper->getActionState(controller::SHIFT), LEFT_HAND_INDEX);
+        emulateMouse(hand, userInputMapper->getActionState(controller::RIGHT_HAND_CLICK),
+            userInputMapper->getActionState(controller::SHIFT), RIGHT_HAND_INDEX);
     }
 
     updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
@@ -4806,7 +4814,7 @@ mat4 Application::getHMDSensorPose() const {
     return mat4();
 }
 
-void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue) {
+void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue) {
     PalmData* palm;
     bool foundHand = false;
     for (size_t j = 0; j < hand->getNumPalms(); j++) {
@@ -4855,7 +4863,7 @@ void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float
         palm->setRawAngularVelocity(glm::vec3(0.0f));
     }
 
-    if (InputDevice::getLowVelocityFilter()) {
+    if (controller::InputDevice::getLowVelocityFilter()) {
         //  Use a velocity sensitive filter to damp small motions and preserve large ones with
         //  no latency.
         float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
@@ -4911,7 +4919,7 @@ void Application::emulateMouse(Hand* hand, float click, float shift, int index)
         float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)M_PI_2));
         auto canvasSize = getCanvasSize();
         // Get the pixel range over which the xAngle and yAngle are scaled
-        float cursorRange = canvasSize.x * InputDevice::getCursorPixelRangeMult();
+        float cursorRange = canvasSize.x * controller::InputDevice::getCursorPixelRangeMult();
 
         pos.setX(canvasSize.x / 2.0f + cursorRange * xAngle);
         pos.setY(canvasSize.y / 2.0f + cursorRange * yAngle);
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 829265c9fb..75cc418e94 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -352,7 +352,7 @@ private:
 
     void update(float deltaTime);
 
-    void setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue);
+    void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue);
     void emulateMouse(Hand* hand, float click, float shift, int index);
 
     // Various helper functions called during update()
diff --git a/interface/src/devices/3DConnexionClient.cpp b/interface/src/devices/3DConnexionClient.cpp
index 722fedcc3a..05795e87e9 100755
--- a/interface/src/devices/3DConnexionClient.cpp
+++ b/interface/src/devices/3DConnexionClient.cpp
@@ -10,8 +10,11 @@
 //
 
 #include "3DConnexionClient.h"
+
+#include <UserActivityLogger.h>
+#include <PathUtils.h>
+
 #include "Menu.h"
-#include "UserActivityLogger.h"
 
 const float MAX_AXIS = 75.0f;  // max forward = 2x speed
 
@@ -25,8 +28,9 @@ ConnexionData& ConnexionData::getInstance() {
     return sharedInstance;
 }
 
-ConnexionData::ConnexionData() {
-}
+
+ConnexionData::ConnexionData() : InputDevice("ConnexionClient") {}
+
 
 void ConnexionData::handleAxisEvent() {
     _axisStateMap[makeInput(ROTATION_AXIS_Y_POS).getChannel()] = (cc_rotation.y > 0.0f) ? cc_rotation.y / MAX_AXIS : 0.0f;
@@ -48,76 +52,71 @@ void ConnexionData::setButton(int lastButtonState) {
     _buttonPressedMap.insert(lastButtonState);
 }
 
-void ConnexionData::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getFreeDeviceID();
+void ConnexionData::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
+    proxy->_name = _name = "ConnexionClient";
+    proxy->getButton = [this](const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
+    proxy->getAxis = [this](const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
+    proxy->getAvailabeInputs = [this]() -> QVector<controller::Input::NamedPair> {
+        QVector<controller::Input::NamedPair> availableInputs;
 
-    auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("ConnexionClient"));
-    proxy->getButton = [this](const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this](const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this]() -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
-
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_1), "Left button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_2), "Right button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_3), "Both buttons"));
-
-        availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_NEG), "Move backward"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_POS), "Move forward"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_POS), "Move right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_NEG), "Move Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_POS), "Move up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_NEG), "Move down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_NEG), "Rotate backward"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_POS), "Rotate forward"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_POS), "Rotate right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_NEG), "Rotate left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_POS), "Rotate up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_NEG), "Rotate down"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_1), "Left button"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_2), "Right button"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_3), "Both buttons"));
 
+        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Y_NEG), "Move backward"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Y_POS), "Move forward"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_X_POS), "Move right"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_X_NEG), "Move Left"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Z_POS), "Move up"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Z_NEG), "Move down"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Y_NEG), "Rotate backward"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Y_POS), "Rotate forward"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_X_POS), "Rotate right"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_X_NEG), "Rotate left"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Z_POS), "Rotate up"));
+        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Z_NEG), "Rotate down"));
         return availableInputs;
     };
-    proxy->resetDeviceBindings = [this, &mapper]() -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
-    mapper.registerDevice(_deviceID, proxy);
 }
 
-void ConnexionData::assignDefaultInputMapping(UserInputMapper& mapper) {
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    //const float DPAD_MOVE_SPEED = 0.5f;
-    const float JOYSTICK_YAW_SPEED = 0.5f;
-    const float JOYSTICK_PITCH_SPEED = 0.25f;
-    const float BOOM_SPEED = 0.1f;
-
-    // Y axes are flipped (up is negative)
-    // postion: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED);
-
-    // Rotation: Camera orientation with button 1
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
-
-    // Button controls
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED);
-
-    // Zoom
-    //  mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED);
-    //  mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED);
-
+QString ConnexionData::getDefaultMappingConfig() {
+    static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
+    return MAPPING_JSON;
 }
 
+//void ConnexionData::assignDefaultInputMapping(UserInputMapper& mapper) {
+//    const float JOYSTICK_MOVE_SPEED = 1.0f;
+//    //const float DPAD_MOVE_SPEED = 0.5f;
+//    const float JOYSTICK_YAW_SPEED = 0.5f;
+//    const float JOYSTICK_PITCH_SPEED = 0.25f;
+//    const float BOOM_SPEED = 0.1f;
+//
+//    // Y axes are flipped (up is negative)
+//    // postion: Movement, strafing
+//    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED);
+//
+//    // Rotation: Camera orientation with button 1
+//    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED);
+//    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED);
+//    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
+//    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
+//
+//    // Button controls
+//    // Zoom
+//    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED);
+//    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED);
+//
+//    // Zoom
+//    //  mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED);
+//    //  mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED);
+//
+//}
+
 float ConnexionData::getButton(int channel) const {
     if (!_buttonPressedMap.empty()) {
         if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
@@ -138,15 +137,15 @@ float ConnexionData::getAxis(int channel) const {
     }
 }
 
-UserInputMapper::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) {
-    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
+controller::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) {
+    return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);
 }
 
-UserInputMapper::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) {
-    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
+controller::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) {
+    return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
 }
 
-void ConnexionData::update() {
+void ConnexionData::update(float deltaTime, bool jointsCaptured) {
     // the update is done in the ConnexionClient class.
     // for windows in the nativeEventFilter the inputmapper is connected or registed or removed when an 3Dconnnexion device is attached or detached
     // for osx the api will call DeviceAddedHandler or DeviceRemoveHandler when a 3Dconnexion device is attached or detached
@@ -187,7 +186,6 @@ void ConnexionClient::destroy() {
     QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
     ConnexionData& connexiondata = ConnexionData::getInstance();
     int deviceid = connexiondata.getDeviceID();
-    connexiondata.setDeviceID(0);
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     userInputMapper->removeDevice(deviceid);
 }
@@ -295,13 +293,10 @@ bool ConnexionClient::RawInputEventFilter(void* msg, long* result) {
     ConnexionData& connexiondata = ConnexionData::getInstance();
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) {
-        connexiondata.registerToUserInputMapper(*userInputMapper);
-        connexiondata.assignDefaultInputMapping(*userInputMapper);
+        userInputMapper->registerDevice(&connexiondata);
         UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
     } else if (!Is3dmouseAttached() && connexiondata.getDeviceID() != 0) {
-        int deviceid = connexiondata.getDeviceID();
-        connexiondata.setDeviceID(0);
-        userInputMapper->removeDevice(deviceid);
+        userInputMapper->removeDevice(connexiondata.getDeviceID());
     }
 
     if (!Is3dmouseAttached()) {
@@ -894,8 +889,7 @@ void ConnexionClient::init() {
 
         if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) {
             auto userInputMapper = DependencyManager::get<UserInputMapper>();
-            connexiondata.registerToUserInputMapper(*userInputMapper);
-            connexiondata.assignDefaultInputMapping(*userInputMapper);
+            userInputMapper->registerDevice(&connexiondata);
             UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
         }
         //let one axis be dominant
@@ -926,8 +920,7 @@ void DeviceAddedHandler(unsigned int connection) {
     if (connexiondata.getDeviceID() == 0) {
         qCWarning(interfaceapp) << "3Dconnexion device added ";
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        connexiondata.registerToUserInputMapper(*userInputMapper);
-        connexiondata.assignDefaultInputMapping(*userInputMapper);
+        userInputMapper->registerDevice(&connexiondata);
         UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
     }
 }
diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h
index bddb86a857..8f66a602a4 100755
--- a/interface/src/devices/3DConnexionClient.h
+++ b/interface/src/devices/3DConnexionClient.h
@@ -175,13 +175,12 @@ public slots:
 
 
 // connnects to the userinputmapper
-class ConnexionData : public QObject {
+class ConnexionData : public QObject, public controller::InputDevice {
     Q_OBJECT
 
 public:
     static ConnexionData& getInstance();
     ConnexionData();
-
     enum PositionChannel {
         POSITION_AXIS_X_POS = 1,
         POSITION_AXIS_X_NEG = 2,
@@ -209,19 +208,12 @@ public:
     float getButton(int channel) const;
     float getAxis(int channel) const;
 
-    UserInputMapper::Input makeInput(ConnexionData::PositionChannel axis);
-    UserInputMapper::Input makeInput(ConnexionData::ButtonChannel button);
-
-    void registerToUserInputMapper(UserInputMapper& mapper);
-    void assignDefaultInputMapping(UserInputMapper& mapper);
-
-    void update();
-    void focusOutEvent();
-
-    int getDeviceID() { return _deviceID; }
-    void setDeviceID(int deviceID) { _deviceID = deviceID; }
-
-    QString _name;
+    controller::Input makeInput(ConnexionData::PositionChannel axis);
+    controller::Input makeInput(ConnexionData::ButtonChannel button);
+    virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
+    virtual QString getDefaultMappingConfig() override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
+    virtual void focusOutEvent() override;
 
     glm::vec3 cc_position;
     glm::vec3 cc_rotation;
@@ -229,12 +221,6 @@ public:
 
     void setButton(int lastButtonState);
     void handleAxisEvent();
-
-protected:
-    int _deviceID = 0;
-
-    ButtonPressedMap _buttonPressedMap;
-    AxisStateMap _axisStateMap;
 };
 
 #endif // defined(hifi_3DConnexionClient_h)
diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp
index f05d1a41a6..31f823de8b 100644
--- a/interface/src/scripting/ControllerScriptingInterface.cpp
+++ b/interface/src/scripting/ControllerScriptingInterface.cpp
@@ -167,31 +167,6 @@ void ControllerScriptingInterface::releaseInputController(controller::InputContr
     _inputControllers.erase(input->getKey());
 }
 
-void ControllerScriptingInterface::update() {
-    static float last = secTimestampNow();
-    float now = secTimestampNow();
-    float delta = now - last;
-    last = now;
-
-    DependencyManager::get<UserInputMapper>()->update(delta);
-
-    bool jointsCaptured = false;
-    for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
-        if (inputPlugin->isActive()) {
-            inputPlugin->pluginUpdate(delta, jointsCaptured);
-            if (inputPlugin->isJointController()) {
-                jointsCaptured = true;
-            }
-        }
-    }
-
-    for (auto entry : _inputControllers) {
-        entry.second->update();
-    }
-
-    controller::ScriptingInterface::update();
-}
-
 InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
     _deviceTrackerId(deviceTrackerId),
     _subTrackerId(subTrackerId),
diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h
index 24065e6799..8be530c6ce 100644
--- a/interface/src/scripting/ControllerScriptingInterface.h
+++ b/interface/src/scripting/ControllerScriptingInterface.h
@@ -85,8 +85,6 @@ public:
     bool isKeyCaptured(const KeyEvent& event) const;
     bool isJoystickCaptured(int joystickIndex) const;
 
-    virtual void update() override;
-
 public slots:
 
     virtual void captureKeyEvents(const KeyEvent& event);
diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp
index 4fc2f3ddb4..ca5c60dc04 100644
--- a/interface/src/ui/ApplicationCompositor.cpp
+++ b/interface/src/ui/ApplicationCompositor.cpp
@@ -521,7 +521,7 @@ void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) {
         float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)PI_OVER_TWO));
 
         // Get the pixel range over which the xAngle and yAngle are scaled
-        float cursorRange = canvasSize.x * InputDevice::getCursorPixelRangeMult();
+        float cursorRange = canvasSize.x * controller::InputDevice::getCursorPixelRangeMult();
 
         mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle);
         mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle);
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 4ba248c76c..d4bab86126 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -198,7 +198,7 @@ void PreferencesDialog::loadPreferences() {
     ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationCompositor().getHmdUIAngularSize());
 #endif
 
-    ui.sixenseReticleMoveSpeedSpin->setValue(InputDevice::getReticleMoveSpeed());
+    ui.sixenseReticleMoveSpeedSpin->setValue(controller::InputDevice::getReticleMoveSpeed());
 
     // LOD items
     auto lodManager = DependencyManager::get<LODManager>();
@@ -273,7 +273,7 @@ void PreferencesDialog::savePreferences() {
 
     qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
     
-    InputDevice::setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
+    controller::InputDevice::setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
 
     auto audio = DependencyManager::get<AudioClient>();
     MixedProcessedAudioStream& stream = audio->getReceivedAudioStream();
diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp
new file mode 100644
index 0000000000..2c5cf84931
--- /dev/null
+++ b/libraries/controllers/src/controllers/Actions.cpp
@@ -0,0 +1,71 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/19
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Actions.h"
+
+#include "UserInputMapper.h"
+
+namespace controller {
+
+    // Device functions
+    void ActionsDevice::buildDeviceProxy(DeviceProxy::Pointer proxy) {
+        proxy->_name = _name;
+        proxy->getButton = [this](const Input& input, int timestamp) -> bool { return false; };
+        proxy->getAxis = [this](const Input& input, int timestamp) -> float { return 0; };
+        proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
+            QVector<Input::NamedPair> availableInputs{
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LONGITUDINAL_BACKWARD, ChannelType::AXIS), "LONGITUDINAL_BACKWARD"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LONGITUDINAL_FORWARD, ChannelType::AXIS), "LONGITUDINAL_FORWARD"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LATERAL_LEFT, ChannelType::AXIS), "LATERAL_LEFT"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LATERAL_RIGHT, ChannelType::AXIS), "LATERAL_RIGHT"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, VERTICAL_DOWN, ChannelType::AXIS), "VERTICAL_DOWN"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, VERTICAL_UP, ChannelType::AXIS), "VERTICAL_UP"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, YAW_LEFT, ChannelType::AXIS), "YAW_LEFT"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, YAW_RIGHT, ChannelType::AXIS), "YAW_RIGHT"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, PITCH_DOWN, ChannelType::AXIS), "PITCH_DOWN"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, PITCH_UP, ChannelType::AXIS), "PITCH_UP"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, BOOM_IN, ChannelType::AXIS), "BOOM_IN"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, BOOM_OUT, ChannelType::AXIS), "BOOM_OUT"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LEFT_HAND, ChannelType::POSE), "LEFT_HAND"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, RIGHT_HAND, ChannelType::POSE), "RIGHT_HAND"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LEFT_HAND_CLICK, ChannelType::BUTTON), "LEFT_HAND_CLICK"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, RIGHT_HAND_CLICK, ChannelType::BUTTON), "RIGHT_HAND_CLICK"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, SHIFT, ChannelType::BUTTON), "SHIFT"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, ACTION1, ChannelType::BUTTON), "ACTION1"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, ACTION2, ChannelType::BUTTON), "ACTION2"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, CONTEXT_MENU, ChannelType::BUTTON), "CONTEXT_MENU"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TOGGLE_MUTE, ChannelType::AXIS), "TOGGLE_MUTE"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TRANSLATE_X, ChannelType::AXIS), "TranslateX"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TRANSLATE_Y, ChannelType::AXIS), "TranslateY"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TRANSLATE_Z, ChannelType::AXIS), "TranslateZ"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, ROLL, ChannelType::AXIS), "Roll"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, PITCH, ChannelType::AXIS), "Pitch"),
+                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, YAW, ChannelType::AXIS), "Yaw")
+            };
+            return availableInputs;
+        };
+
+    }
+
+    QString ActionsDevice::getDefaultMappingConfig() {
+        return QString();
+    }
+
+    void ActionsDevice::update(float deltaTime, bool jointsCaptured) {
+    }
+
+    void ActionsDevice::focusOutEvent() {
+    }
+
+    ActionsDevice::ActionsDevice() : InputDevice("Actions") {
+        _deviceID = UserInputMapper::ACTIONS_DEVICE;
+    }
+
+    ActionsDevice::~ActionsDevice() {}
+
+}
diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h
new file mode 100644
index 0000000000..f4e9f665e2
--- /dev/null
+++ b/libraries/controllers/src/controllers/Actions.h
@@ -0,0 +1,100 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/19
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_controller_Actions_h
+#define hifi_controller_Actions_h
+
+#include <QtCore/QObject>
+#include <QtCore/QVector>
+
+#include "InputDevice.h"
+
+namespace controller {
+
+// Actions are the output channels of the Mapper, that's what the InputChannel map to
+// For now the Actions are hardcoded, this is bad, but we will fix that in the near future
+enum Action {
+    TRANSLATE_X = 0,
+    TRANSLATE_Y,
+    TRANSLATE_Z,
+    ROTATE_X, PITCH = ROTATE_X,
+    ROTATE_Y, YAW = ROTATE_Y,
+    ROTATE_Z, ROLL = ROTATE_Z,
+
+    TRANSLATE_CAMERA_Z,
+    NUM_COMBINED_AXES,
+
+    LEFT_HAND = NUM_COMBINED_AXES,
+    RIGHT_HAND,
+
+    LEFT_HAND_CLICK,
+    RIGHT_HAND_CLICK,
+
+    ACTION1,
+    ACTION2,
+
+    CONTEXT_MENU,
+    TOGGLE_MUTE,
+
+    SHIFT,
+
+    // Biseced aliases for TRANSLATE_Z
+    LONGITUDINAL_BACKWARD,
+    LONGITUDINAL_FORWARD,
+
+    // Biseced aliases for TRANSLATE_X
+    LATERAL_LEFT,
+    LATERAL_RIGHT,
+
+    // Biseced aliases for TRANSLATE_Y
+    VERTICAL_DOWN,
+    VERTICAL_UP,
+
+    // Biseced aliases for ROTATE_Y
+    YAW_LEFT,
+    YAW_RIGHT,
+
+    // Biseced aliases for ROTATE_X
+    PITCH_DOWN,
+    PITCH_UP,
+
+    // Biseced aliases for TRANSLATE_CAMERA_Z
+    BOOM_IN,
+    BOOM_OUT,
+
+    NUM_ACTIONS,
+};
+
+
+class ActionsDevice : public QObject, public InputDevice {
+    Q_OBJECT
+    Q_PROPERTY(QString name READ getName)
+
+public:
+    const QString& getName() const { return _name; }
+
+    // Device functions
+    virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override;
+    virtual QString getDefaultMappingConfig() override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
+    virtual void focusOutEvent() override;
+
+    ActionsDevice();
+    virtual ~ActionsDevice();
+};
+
+}
+
+
+
+
+#include "StandardControls.h"
+
+
+#endif // hifi_StandardController_h
diff --git a/libraries/controllers/src/controllers/DeviceProxy.cpp b/libraries/controllers/src/controllers/DeviceProxy.cpp
index 9ac701e80d..6cbfc1048d 100644
--- a/libraries/controllers/src/controllers/DeviceProxy.cpp
+++ b/libraries/controllers/src/controllers/DeviceProxy.cpp
@@ -20,7 +20,7 @@ namespace controller {
             return getAxis(input, timestamp);
 
         case ChannelType::POSE:
-            return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
+            return getPose(input, timestamp).valid ? 1.0f : 0.0f;
 
         default:
             return NAN;
diff --git a/libraries/controllers/src/controllers/DeviceProxy.h b/libraries/controllers/src/controllers/DeviceProxy.h
index 78d13fe5c4..064abdbc7f 100644
--- a/libraries/controllers/src/controllers/DeviceProxy.h
+++ b/libraries/controllers/src/controllers/DeviceProxy.h
@@ -35,23 +35,15 @@ namespace controller {
 
     class DeviceProxy {
     public:
-       DeviceProxy(QString name) : _baseName(name), _name(name) {}
-       const QString& getBaseName() const { return _baseName; }
-       const QString& getName() const { return _name; }
-
-       ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
-       AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; };
-       PoseGetter getPose = [](const Input& input, int timestamp) -> Pose { return Pose(); };
-       AvailableInputGetter getAvailabeInputs = []() -> Input::NamedVector { return Input::NamedVector(); };
-       ResetBindings resetDeviceBindings = [] () -> bool { return true; };
-       float getValue(const Input& input, int timestamp = 0) const;
-
-       using Pointer = std::shared_ptr<DeviceProxy>;
-
-       QString _baseName;
-       QString _name;
+        using Pointer = std::shared_ptr<DeviceProxy>;
+        const QString& getName() const { return _name; }
+        ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
+        AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; };
+        PoseGetter getPose = [](const Input& input, int timestamp) -> Pose { return Pose(); };
+        AvailableInputGetter getAvailabeInputs = []() -> Input::NamedVector const { return Input::NamedVector(); };
+        float getValue(const Input& input, int timestamp = 0) const;
+        QString _name;
     };
-
 }
 
 #endif
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index 923412ac6c..3e4ce94490 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -14,7 +14,9 @@
 #include <memory>
 #include <functional>
 
-#include "UserInputMapper.h"
+#include <QtCore/QObject>
+
+#include "Input.h"
 
 class QScriptValue;
 
@@ -24,7 +26,7 @@ namespace controller {
     * i.e. Hydra.Button0, Standard.X, Action.Yaw
     */
     class Endpoint : public QObject {
-    Q_OBJECT;
+        Q_OBJECT;
     public:
         using Pointer = std::shared_ptr<Endpoint>;
         using List = std::list<Pointer>;
@@ -32,18 +34,18 @@ namespace controller {
         using ReadLambda = std::function<float()>;
         using WriteLambda = std::function<void(float)>;
 
-        Endpoint(const UserInputMapper::Input& input) : _input(input) {}
+        Endpoint(const Input& input) : _input(input) {}
         virtual float value() = 0;
         virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
-        const UserInputMapper::Input& getInput() { return _input;  }
+        const Input& getInput() { return _input;  }
     protected:
-        UserInputMapper::Input _input;
+        Input _input;
     };
 
     class LambdaEndpoint : public Endpoint {
     public:
         LambdaEndpoint(ReadLambda readLambda, WriteLambda writeLambda = [](float) {})
-            : Endpoint(UserInputMapper::Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
+            : Endpoint(Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
 
         virtual float value() override { return _readLambda(); }
         virtual void apply(float newValue, float oldValue, const Pointer& source) override { _writeLambda(newValue); }
diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h
index 8cc682df70..98377b7434 100644
--- a/libraries/controllers/src/controllers/Input.h
+++ b/libraries/controllers/src/controllers/Input.h
@@ -27,26 +27,21 @@ enum class ChannelType {
 // to the Action channels
 struct Input {
     union {
+        uint32_t id{ 0 }; // by default Input is 0 meaning invalid
         struct {
-            uint16_t _device; // Up to 64K possible devices
-            uint16_t _channel : 13; // 2^13 possible channel per Device
-            uint16_t _type : 2; // 2 bits to store the Type directly in the ID
-            uint16_t _padding : 1; // 2 bits to store the Type directly in the ID
+            uint16_t device; // Up to 64K possible devices
+            uint16_t channel : 13 ; // 2^13 possible channel per Device
+            uint16_t type : 2; // 2 bits to store the Type directly in the ID
+            uint16_t padding : 1; // 2 bits to store the Type directly in the ID
         };
-        uint32_t _id = 0; // by default Input is 0 meaning invalid
     };
 
-    bool isValid() const { return (_id != 0); }
+    bool isValid() const { return (id != INVALID_INPUT.id); }
 
-    uint16_t getDevice() const { return _device; }
-    uint16_t getChannel() const { return _channel; }
-    uint32_t getID() const { return _id; }
-    ChannelType getType() const { return (ChannelType) _type; }
-
-    void setDevice(uint16_t device) { _device = device; }
-    void setChannel(uint16_t channel) { _channel = channel; }
-    void setType(uint16_t type) { _type = type; }
-    void setID(uint32_t ID) { _id = ID; }
+    uint16_t getDevice() const { return device; }
+    uint16_t getChannel() const { return channel; }
+    uint32_t getID() const { return id; }
+    ChannelType getType() const { return (ChannelType) type; }
 
     bool isButton() const { return getType() == ChannelType::BUTTON; }
     bool isAxis() const { return getType() == ChannelType::AXIS; }
@@ -54,13 +49,13 @@ struct Input {
 
     // WORKAROUND: the explicit initializer here avoids a bug in GCC-4.8.2 (but not found in 4.9.2)
     // where the default initializer (a C++-11ism) for the union data above is not applied.
-    explicit Input() : _id(0) {}
-    explicit Input(uint32_t id) : _id(id) {}
-    explicit Input(uint16_t device, uint16_t channel, ChannelType type) : _device(device), _channel(channel), _type(uint16_t(type)), _padding(0) {}
-    Input(const Input& src) : _id(src._id) {}
-    Input& operator = (const Input& src) { _id = src._id; return (*this); }
-    bool operator ==(const Input& right) const { return _id == right._id; }
-    bool operator < (const Input& src) const { return _id < src._id; }
+    explicit Input() {}
+    explicit Input(uint32_t id) : id(id) {}
+    explicit Input(uint16_t device, uint16_t channel, ChannelType type) : device(device), channel(channel), type(uint16_t(type)), padding(0) {}
+    Input(const Input& src) : id(src.id) {}
+    Input& operator = (const Input& src) { id = src.id; return (*this); }
+    bool operator ==(const Input& right) const { return INVALID_INPUT.id != id && INVALID_INPUT.id != right.id && id == right.id; }
+    bool operator < (const Input& src) const { return id < src.id; }
 
     static const Input INVALID_INPUT;
     static const uint16_t INVALID_DEVICE;
diff --git a/libraries/controllers/src/controllers/InputDevice.cpp b/libraries/controllers/src/controllers/InputDevice.cpp
index 1f86741b88..78e920d4b5 100644
--- a/libraries/controllers/src/controllers/InputDevice.cpp
+++ b/libraries/controllers/src/controllers/InputDevice.cpp
@@ -10,75 +10,78 @@
 //
 #include "InputDevice.h"
 
-bool InputDevice::_lowVelocityFilter = false;
+#include "Input.h"
 
-const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
-float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
+namespace controller {
 
-//Constants for getCursorPixelRangeMultiplier()
-const float MIN_PIXEL_RANGE_MULT = 0.4f;
-const float MAX_PIXEL_RANGE_MULT = 2.0f;
-const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f;
+    bool InputDevice::_lowVelocityFilter = false;
 
-//Returns a multiplier to be applied to the cursor range for the controllers
-float InputDevice::getCursorPixelRangeMult() {
-    //scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT)
-    return InputDevice::_reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
-}
+    const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
+    float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
 
-float InputDevice::getButton(int channel) const {
-    if (!_buttonPressedMap.empty()) {
-        if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
-            return 1.0f;
+    //Constants for getCursorPixelRangeMultiplier()
+    const float MIN_PIXEL_RANGE_MULT = 0.4f;
+    const float MAX_PIXEL_RANGE_MULT = 2.0f;
+    const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f;
+
+    //Returns a multiplier to be applied to the cursor range for the controllers
+    float InputDevice::getCursorPixelRangeMult() {
+        //scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT)
+        return InputDevice::_reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
+    }
+
+    float InputDevice::getButton(int channel) const {
+        if (!_buttonPressedMap.empty()) {
+            if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
+                return 1.0f;
+            } else {
+                return 0.0f;
+            }
         }
-        else {
+        return 0.0f;
+    }
+
+    float InputDevice::getAxis(int channel) const {
+        auto axis = _axisStateMap.find(channel);
+        if (axis != _axisStateMap.end()) {
+            return (*axis).second;
+        } else {
             return 0.0f;
         }
     }
-    return 0.0f;
-}
 
-float InputDevice::getAxis(int channel) const {
-    auto axis = _axisStateMap.find(channel);
-    if (axis != _axisStateMap.end()) {
-        return (*axis).second;
+    Pose InputDevice::getPose(int channel) const {
+        auto pose = _poseStateMap.find(channel);
+        if (pose != _poseStateMap.end()) {
+            return (*pose).second;
+        } else {
+            return Pose();
+        }
     }
-    else {
-        return 0.0f;
+
+    Input InputDevice::makeInput(controller::StandardButtonChannel button) {
+        return Input(_deviceID, button, ChannelType::BUTTON);
     }
-}
 
-UserInputMapper::PoseValue InputDevice::getPose(int channel) const {
-    auto pose = _poseStateMap.find(channel);
-    if (pose != _poseStateMap.end()) {
-        return (*pose).second;
+    Input InputDevice::makeInput(controller::StandardAxisChannel axis) {
+        return Input(_deviceID, axis, ChannelType::AXIS);
     }
-    else {
-        return UserInputMapper::PoseValue();
+
+    Input InputDevice::makeInput(controller::StandardPoseChannel pose) {
+        return Input(_deviceID, pose, ChannelType::POSE);
     }
-}
 
-UserInputMapper::Input InputDevice::makeInput(controller::StandardButtonChannel button) {
-    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
-}
+    Input::NamedPair InputDevice::makePair(controller::StandardButtonChannel button, const QString& name) {
+        return Input::NamedPair(makeInput(button), name);
+    }
 
-UserInputMapper::Input InputDevice::makeInput(controller::StandardAxisChannel axis) {
-    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
-}
+    Input::NamedPair InputDevice::makePair(controller::StandardAxisChannel axis, const QString& name) {
+        return Input::NamedPair(makeInput(axis), name);
+    }
 
-UserInputMapper::Input InputDevice::makeInput(controller::StandardPoseChannel pose) {
-    return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
-}
+    Input::NamedPair InputDevice::makePair(controller::StandardPoseChannel pose, const QString& name) {
+        return Input::NamedPair(makeInput(pose), name);
+    }
 
-UserInputMapper::InputPair InputDevice::makePair(controller::StandardButtonChannel button, const QString& name) {
-    return UserInputMapper::InputPair(makeInput(button), name);
-}
 
-UserInputMapper::InputPair InputDevice::makePair(controller::StandardAxisChannel axis, const QString& name) {
-    return UserInputMapper::InputPair(makeInput(axis), name);
 }
-
-UserInputMapper::InputPair InputDevice::makePair(controller::StandardPoseChannel pose, const QString& name) {
-    return UserInputMapper::InputPair(makeInput(pose), name);
-}
-
diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h
index 4854df0ada..e01def2368 100644
--- a/libraries/controllers/src/controllers/InputDevice.h
+++ b/libraries/controllers/src/controllers/InputDevice.h
@@ -10,13 +10,23 @@
 //
 #pragma once
 
-#include "UserInputMapper.h"
+#include <memory>
+#include <map>
+#include <unordered_set>
+
+#include <QtCore/QString>
+
+#include "Pose.h"
+#include "Input.h"
 #include "StandardControls.h"
+#include "DeviceProxy.h"
 
 // Event types for each controller
 const unsigned int CONTROLLER_0_EVENT = 1500U;
 const unsigned int CONTROLLER_1_EVENT = 1501U;
 
+namespace controller {
+
 // NOTE: If something inherits from both InputDevice and InputPlugin, InputPlugin must go first.
 // e.g. class Example : public InputPlugin, public InputDevice
 // instead of class Example : public InputDevice, public InputPlugin
@@ -24,17 +34,19 @@ class InputDevice {
 public:
     InputDevice(const QString& name) : _name(name) {}
 
+    using Pointer = std::shared_ptr<InputDevice>;
+
     typedef std::unordered_set<int> ButtonPressedMap;
     typedef std::map<int, float> AxisStateMap;
-    typedef std::map<int, UserInputMapper::PoseValue> PoseStateMap;
+    typedef std::map<int, Pose> PoseStateMap;
 
     // Get current state for each channel
     float getButton(int channel) const;
     float getAxis(int channel) const;
-    UserInputMapper::PoseValue getPose(int channel) const;
+    Pose getPose(int channel) const;
 
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) = 0;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) = 0;
+    virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) = 0;
+    virtual QString getDefaultMappingConfig() = 0;
 
     // Update call MUST be called once per simulation loop
     // It takes care of updating the action states and deltas
@@ -43,6 +55,7 @@ public:
     virtual void focusOutEvent() = 0;
 
     int getDeviceID() { return _deviceID; }
+    void setDeviceID(int deviceID) { _deviceID = deviceID; }
 
     static float getCursorPixelRangeMult();
     static float getReticleMoveSpeed() { return _reticleMoveSpeed; }
@@ -50,18 +63,18 @@ public:
 
     static bool getLowVelocityFilter() { return _lowVelocityFilter; };
 
-    UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
-    UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
-    UserInputMapper::Input makeInput(controller::StandardPoseChannel pose);
-    UserInputMapper::InputPair makePair(controller::StandardButtonChannel button, const QString& name);
-    UserInputMapper::InputPair makePair(controller::StandardAxisChannel button, const QString& name);
-    UserInputMapper::InputPair makePair(controller::StandardPoseChannel button, const QString& name);
-public slots:
+    Input makeInput(StandardButtonChannel button);
+    Input makeInput(StandardAxisChannel axis);
+    Input makeInput(StandardPoseChannel pose);
+    Input::NamedPair makePair(StandardButtonChannel button, const QString& name);
+    Input::NamedPair makePair(StandardAxisChannel button, const QString& name);
+    Input::NamedPair makePair(StandardPoseChannel button, const QString& name);
+    public slots:
     static void setLowVelocityFilter(bool newLowVelocityFilter) { _lowVelocityFilter = newLowVelocityFilter; };
 
 protected:
-
-    int _deviceID = 0;
+    friend class UserInputMapper;
+    uint16_t _deviceID{ Input::INVALID_DEVICE };
 
     QString _name;
 
@@ -73,4 +86,6 @@ protected:
 
 private:
     static float _reticleMoveSpeed;
-};
\ No newline at end of file
+};
+
+}
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/Mapping.cpp
index 08e8aef9e8..68c43da393 100644
--- a/libraries/controllers/src/controllers/Mapping.cpp
+++ b/libraries/controllers/src/controllers/Mapping.cpp
@@ -6,11 +6,3 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 #include "Mapping.h"
-
-namespace controller {
-    Mapping::Mapping(const QString& name ) : _name(name) {
-
-    }
-
-}
-
diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h
index e9c8e7a323..ff988bf1b1 100644
--- a/libraries/controllers/src/controllers/Mapping.h
+++ b/libraries/controllers/src/controllers/Mapping.h
@@ -27,13 +27,11 @@ namespace controller {
         using Map = std::map<Endpoint::Pointer, Route::List>;
         using Pointer = std::shared_ptr<Mapping>;
 
-        Mapping(const QString& name);
+        Mapping(const QString& name) : name(name) {}
 
-        Map _channelMappings;
+        Map channelMappings;
 
-        QString _name;
-
-    protected:
+        QString name;
     };
 
 }
diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp
index a716955d70..e4674735b0 100644
--- a/libraries/controllers/src/controllers/Pose.cpp
+++ b/libraries/controllers/src/controllers/Pose.cpp
@@ -12,17 +12,17 @@ namespace controller {
 
     Pose::Pose(const vec3& translation, const quat& rotation,
             const vec3& velocity, const quat& angularVelocity) :
-            _translation(translation), _rotation(rotation), _velocity(velocity), _angularVelocity(angularVelocity) { }
+            translation(translation), rotation(rotation), velocity(velocity), angularVelocity(angularVelocity) { }
 
     bool Pose::operator==(const Pose& right) const {
         // invalid poses return false for comparison, even against identical invalid poses, like NaN
-        if (_valid || !right._valid) {
+        if (!valid || !right.valid) {
             return false;
         }
 
         // FIXME add margin of error?  Or add an additional withinEpsilon function?
-        return _translation == right.getTranslation() && _rotation == right.getRotation() && 
-            _velocity == right.getVelocity() && _angularVelocity == right.getAngularVelocity();
+        return translation == right.getTranslation() && rotation == right.getRotation() && 
+            velocity == right.getVelocity() && angularVelocity == right.getAngularVelocity();
     }
 
 
diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h
index b77064f2c1..9243ceb734 100644
--- a/libraries/controllers/src/controllers/Pose.h
+++ b/libraries/controllers/src/controllers/Pose.h
@@ -17,11 +17,11 @@ namespace controller {
 
     struct Pose {
     public:
-        vec3 _translation;
-        quat _rotation;
-        vec3 _velocity;
-        quat _angularVelocity;
-        bool _valid{ false };
+        vec3 translation;
+        quat rotation;
+        vec3 velocity;
+        quat angularVelocity;
+        bool valid{ false };
 
         Pose() {}
         Pose(const vec3& translation, const quat& rotation,
@@ -30,11 +30,11 @@ namespace controller {
         Pose(const Pose&) = default;
         Pose& operator = (const Pose&) = default;
         bool operator ==(const Pose& right) const;
-        bool isValid() const { return _valid; }
-        vec3 getTranslation() const { return _translation; }
-        quat getRotation() const { return _rotation; }
-        vec3 getVelocity() const { return _velocity; }
-        quat getAngularVelocity() const { return _angularVelocity; }
+        bool isValid() const { return valid; }
+        vec3 getTranslation() const { return translation; }
+        quat getRotation() const { return rotation; }
+        vec3 getVelocity() const { return velocity; }
+        quat getAngularVelocity() const { return angularVelocity; }
     };
 
 
diff --git a/libraries/controllers/src/controllers/Route.cpp b/libraries/controllers/src/controllers/Route.cpp
index 08b6d1f4f2..56590e564a 100644
--- a/libraries/controllers/src/controllers/Route.cpp
+++ b/libraries/controllers/src/controllers/Route.cpp
@@ -6,5 +6,4 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-
 #include "Route.h"
diff --git a/libraries/controllers/src/controllers/Route.h b/libraries/controllers/src/controllers/Route.h
index 01770a87d1..8b0e70050f 100644
--- a/libraries/controllers/src/controllers/Route.h
+++ b/libraries/controllers/src/controllers/Route.h
@@ -16,20 +16,17 @@
 class QJsonObject;
 
 namespace controller {
-
     /*
     * encapsulates a source, destination and filters to apply
     */
     class Route {
     public:
-        Endpoint::Pointer _source;
-        Endpoint::Pointer _destination;
-        Filter::List _filters;
+        Endpoint::Pointer source;
+        Endpoint::Pointer destination;
+        Filter::List filters;
 
         using Pointer = std::shared_ptr<Route>;
         using List = std::list<Pointer>;
-
-        void parse(const QJsonObject);
     };
 }
 
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index dc305c4c6e..0f9b5678ca 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -12,8 +12,6 @@
 
 #include <QtCore/QRegularExpression>
 
-#include <QJsonDocument>
-#include <QJsonObject>
 #include <QEventLoop>
 #include <QThread>
 
@@ -26,475 +24,146 @@
 #include "Logging.h"
 #include "InputDevice.h"
 
+static QRegularExpression SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" };
+
+static QVariantMap createDeviceMap(const controller::DeviceProxy::Pointer device) {
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+    QVariantMap deviceMap;
+    for (const auto& inputMapping : device->getAvailabeInputs()) {
+        const auto& input = inputMapping.first;
+        const auto inputName = QString(inputMapping.second).remove(SANITIZE_NAME_EXPRESSION);
+        qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType()
+            << QString::number(input.getID(), 16) << ": " << inputName;
+        deviceMap.insert(inputName, input.getID());
+    }
+    return deviceMap;
+}
+
+// FIXME this throws a hissy fit on MSVC if I put it in the main controller namespace block
+controller::ScriptingInterface::ScriptingInterface() {
+    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+
+    // FIXME make this thread safe
+    connect(userInputMapper.data(), &UserInputMapper::hardwareChanged, [=] {
+        updateMaps();
+    });
+
+
+    qCDebug(controllers) << "Setting up standard controller abstraction";
+    _standard = createDeviceMap(userInputMapper->getStandardDevice());
+
+    // FIXME allow custom user actions?
+    auto actionNames = userInputMapper->getActionNames();
+    int actionNumber = 0;
+    qCDebug(controllers) << "Setting up standard actions";
+    for (const auto& namedInput : userInputMapper->getActionInputs()) {
+        const QString& actionName = namedInput.second;
+        const Input& actionInput = namedInput.first;
+        qCDebug(controllers) << "\tAction: " << actionName << " " << actionInput.getChannel();
+
+        // Expose the IDs to JS
+        QString cleanActionName = QString(actionName).remove(SANITIZE_NAME_EXPRESSION);
+        _actions.insert(cleanActionName, actionInput.getID());
+    }
+
+    updateMaps();
+}
+
 namespace controller {
 
-    class VirtualEndpoint : public Endpoint {
-    public:
-        VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT)
-            : Endpoint(id) {
-        }
-
-        virtual float value() override { return _currentValue; }
-        virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; }
-
-    private:
-        float _currentValue{ 0.0f };
-    };
-
-
-    class JSEndpoint : public Endpoint {
-    public:
-        JSEndpoint(const QJSValue& callable) 
-            : Endpoint(UserInputMapper::Input::INVALID_INPUT), _callable(callable) {}
-
-        virtual float value() {
-            float result = (float)_callable.call().toNumber();;
-            return result;
-        }
-
-        virtual void apply(float newValue, float oldValue, const Pointer& source) {
-            _callable.call(QJSValueList({ QJSValue(newValue) }));
-        }
-
-    private:
-        QJSValue _callable;
-    };
-
-    float ScriptEndpoint::value() {
-        updateValue();
-        return _lastValue;
-    }
-
-    void ScriptEndpoint::updateValue() {
-        if (QThread::currentThread() != thread()) {
-            QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
-            return;
-        }
-
-        _lastValue = (float)_callable.call().toNumber();
-    }
-
-    void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
-        internalApply(newValue, oldValue, source->getInput().getID());
-    }
-
-    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:
-        CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
-            : Endpoint(UserInputMapper::Input(UserInputMapper::Input::INVALID_INPUT)), Pair(first, second) { }
-
-        virtual float value() {
-            float result = first->value() * -1.0f + second->value();
-            return result;
-        }
-
-        virtual void apply(float newValue, float oldValue, const Pointer& source) {
-            // Composites are read only
-        }
-
-    private:
-        Endpoint::Pointer _first;
-        Endpoint::Pointer _second;
-    };
-
-    class ActionEndpoint : public Endpoint {
-    public:
-        ActionEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT)
-            : Endpoint(id) {
-        }
-
-        virtual float value() override { return _currentValue; }
-        virtual void apply(float newValue, float oldValue, const Pointer& source) override { 
-            
-            _currentValue += newValue;
-            if (!(_input == UserInputMapper::Input::INVALID_INPUT)) {
-                auto userInputMapper = DependencyManager::get<UserInputMapper>();
-                userInputMapper->deltaActionState(UserInputMapper::Action(_input.getChannel()), newValue);
-            }
-        }
-
-    private:
-        float _currentValue{ 0.0f };
-    };
-
-    QRegularExpression ScriptingInterface::SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" };
-
-    QVariantMap createDeviceMap(const UserInputMapper::DeviceProxy* device) {
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        QVariantMap deviceMap;
-        for (const auto& inputMapping : device->getAvailabeInputs()) {
-            const auto& input = inputMapping.first;
-            const auto inputName = QString(inputMapping.second).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
-            qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType()
-                << QString::number(input.getID(), 16) << ": " << inputName;
-            deviceMap.insert(inputName, input.getID());
-        }
-        return deviceMap;
-    }
-    
-
-    ScriptingInterface::~ScriptingInterface() {
-    }
-
     QObject* ScriptingInterface::newMapping(const QString& mappingName) {
-        if (_mappingsByName.count(mappingName)) {
-            qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
-        }
-        qDebug() << "Creating new Mapping " << mappingName;
-        auto mapping = std::make_shared<Mapping>(mappingName); 
-        _mappingsByName[mappingName] = mapping;
-        return new MappingBuilderProxy(*this, mapping);
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        return new MappingBuilderProxy(*userInputMapper, userInputMapper->newMapping(mappingName));
     }
 
-    QObject* ScriptingInterface::parseMapping(const QString& json) {
-
-        QJsonObject obj;
-        QJsonParseError error;
-        QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error);
-        // check validity of the document
-        if (!doc.isNull()) {
-            if (doc.isObject()) {
-                obj = doc.object();
-
-                auto mapping = std::make_shared<Mapping>("default");
-                auto mappingBuilder = new MappingBuilderProxy(*this, mapping);
-
-                mappingBuilder->parse(obj);
-
-                _mappingsByName[mapping->_name] = mapping;
-
-                return mappingBuilder;
-            } else {
-                qDebug() << "Mapping json Document is not an object" << endl;
-            }
-        } else {
-            qDebug() << "Invalid JSON...\n";
-            qDebug() << error.errorString();
-            qDebug() << "JSON was:\n" << json << endl;
-
-        }
-
-        return nullptr;
-    }
-
-    QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) {
-        QObject* result = nullptr;
-        auto request = ResourceManager::createResourceRequest(nullptr, QUrl(jsonUrl));
-        if (request) {
-            QEventLoop eventLoop;
-            request->setCacheEnabled(false);
-            connect(request, &ResourceRequest::finished, &eventLoop, &QEventLoop::quit);
-            request->send();
-            if (request->getState() != ResourceRequest::Finished) {
-                eventLoop.exec();
-            }
-
-            if (request->getResult() == ResourceRequest::Success) {
-                result = parseMapping(QString(request->getData()));
-            } else {
-                qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl;
-            }
-            request->deleteLater();
-        }
-        return result;
-    }
-
-    Q_INVOKABLE QObject* newMapping(const QJsonObject& json);
-
     void ScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
-        qCDebug(controllers) << "Attempting to enable mapping " << mappingName;
-        auto iterator = _mappingsByName.find(mappingName);
-        if (_mappingsByName.end() == iterator) {
-            qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName;
-            return;
-        }
-
-        auto mapping = iterator->second;
-        if (enable) {
-            _activeMappings.push_front(mapping);
-        } else {
-            auto activeIterator = std::find(_activeMappings.begin(), _activeMappings.end(), mapping);
-            if (_activeMappings.end() == activeIterator) {
-                qCWarning(controllers) << "Attempted to disable inactive mapping " << mappingName;
-                return;
-            }
-            _activeMappings.erase(activeIterator);
-        }
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        userInputMapper->enableMapping(mappingName, enable);
     }
 
     float ScriptingInterface::getValue(const int& source) const {
-        // return (sin(secTimestampNow()) + 1.0f) / 2.0f;
-        UserInputMapper::Input input(source);
-        auto iterator = _endpoints.find(input);
-        if (_endpoints.end() == iterator) {
-            return 0.0;
-        }
-
-        const auto& endpoint = iterator->second;
-        return getValue(endpoint);
-    }
-
-    float ScriptingInterface::getValue(const Endpoint::Pointer& endpoint) const {
-        auto valuesIterator = _overrideValues.find(endpoint);
-        if (_overrideValues.end() != valuesIterator) {
-            return valuesIterator->second;
-        }
-
-        return endpoint->value();
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        return userInputMapper->getValue(Input((uint32_t)source));
     }
 
     float ScriptingInterface::getButtonValue(StandardButtonChannel source, uint16_t device) const {
-        return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::BUTTON).getID());
+        return getValue(Input(device, source, ChannelType::BUTTON).getID());
     }
 
     float ScriptingInterface::getAxisValue(StandardAxisChannel source, uint16_t device) const {
-        return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID());
+        return getValue(Input(device, source, ChannelType::AXIS).getID());
     }
 
     Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
         return Pose();
     }
 
-    void ScriptingInterface::update() {
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        static auto deviceNames = userInputMapper->getDeviceNames();
+    //bool ScriptingInterface::isPrimaryButtonPressed() const {
+    //    return isButtonPressed(StandardButtonChannel::A);
+    //}
+    //    
+    //glm::vec2 ScriptingInterface::getPrimaryJoystickPosition() const {
+    //    return getJoystickPosition(0);
+    //}
 
-        if (deviceNames != userInputMapper->getDeviceNames()) {
-            updateMaps();
-            deviceNames = userInputMapper->getDeviceNames();
-        }
+    //int ScriptingInterface::getNumberOfButtons() const {
+    //    return StandardButtonChannel::NUM_STANDARD_BUTTONS;
+    //}
 
-        _overrideValues.clear();
-        EndpointSet readEndpoints;
-        EndpointSet writtenEndpoints;
-        // Now process the current values for each level of the stack
-        for (auto& mapping : _activeMappings) {
-            for (const auto& mappingEntry : mapping->_channelMappings) {
-                const auto& source = mappingEntry.first;
+    //bool ScriptingInterface::isButtonPressed(int buttonIndex) const {
+    //    return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0 ? false : true;
+    //}
 
-                // Endpoints can only be read once (though a given mapping can route them to 
-                // multiple places).  Consider... If the default is to wire the A button to JUMP
-                // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
-                // I press the button.  The exception is if I'm wiring a control back to itself
-                // in order to adjust my interface, like inverting the Y axis on an analog stick
-                if (readEndpoints.count(source)) {
-                    continue;
-                }
+    //int ScriptingInterface::getNumberOfTriggers() const {
+    //    return StandardCounts::TRIGGERS;
+    //}
 
-                // Apply the value to all the routes
-                const auto& routes = mappingEntry.second;
+    //float ScriptingInterface::getTriggerValue(int triggerIndex) const {
+    //    return getAxisValue(triggerIndex == 0 ? StandardAxisChannel::LT : StandardAxisChannel::RT);
+    //}
 
-                for (const auto& route : routes) {
-                    const auto& destination = route->_destination;
-                    // THis could happen if the route destination failed to create
-                    // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
-                    if (!source || !destination) {
-                        continue;
-                    }
+    //int ScriptingInterface::getNumberOfJoysticks() const {
+    //    return StandardCounts::ANALOG_STICKS;
+    //}
 
-                    if (writtenEndpoints.count(destination)) {
-                        continue;
-                    }
+    //glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const {
+    //    StandardAxisChannel xid = StandardAxisChannel::LX; 
+    //    StandardAxisChannel yid = StandardAxisChannel::LY;
+    //    if (joystickIndex != 0) {
+    //        xid = StandardAxisChannel::RX;
+    //        yid = StandardAxisChannel::RY;
+    //    }
+    //    vec2 result;
+    //    result.x = getAxisValue(xid);
+    //    result.y = getAxisValue(yid);
+    //    return result;
+    //}
 
-                    // Standard controller destinations can only be can only be used once.
-                    if (userInputMapper->getStandardDeviceID() == destination->getInput().getDevice()) {
-                        writtenEndpoints.insert(destination);
-                    }
+    //int ScriptingInterface::getNumberOfSpatialControls() const {
+    //    return StandardCounts::POSES;
+    //}
 
-                    // Only consume the input if the route isn't a loopback.
-                    // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
-                    bool loopback = source == destination;
-                    if (!loopback) {
-                        readEndpoints.insert(source);
-                    }
+    //glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const {
+    //    // FIXME extract the position from the standard pose
+    //    return vec3();
+    //}
 
-                    // Fetch the value, may have been overriden by previous loopback routes
-                    float value = getValue(source);
+    //glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
+    //    // FIXME extract the velocity from the standard pose
+    //    return vec3();
+    //}
 
-                    // Apply each of the filters.
-                    for (const auto& filter : route->_filters) {
-                        value = filter->apply(value);
-                    }
+    //glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const {
+    //    // FIXME extract the normal from the standard pose
+    //    return vec3();
+    //}
+    //
+    //glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
+    //    // FIXME extract the rotation from the standard pose
+    //    return quat();
+    //}
 
-                    if (loopback) {
-                        _overrideValues[source] = value;
-                    } else {
-                        destination->apply(value, 0, source);
-                    }
-                }
-            }
-        }
-    }
-
-    Endpoint::Pointer ScriptingInterface::endpointFor(const QJSValue& endpoint) {
-        if (endpoint.isNumber()) {
-            return endpointFor(UserInputMapper::Input(endpoint.toInt()));
-        }
-
-        if (endpoint.isCallable()) {
-            auto result = std::make_shared<JSEndpoint>(endpoint);
-            return result;
-        }
-
-        qWarning() << "Unsupported input type " << endpoint.toString();
-        return Endpoint::Pointer();
-    }
-
-    Endpoint::Pointer ScriptingInterface::endpointFor(const QScriptValue& endpoint) {
-        if (endpoint.isNumber()) {
-            return endpointFor(UserInputMapper::Input(endpoint.toInt32()));
-        }
-
-        if (endpoint.isFunction()) {
-            auto result = std::make_shared<ScriptEndpoint>(endpoint);
-            return result;
-        }
-
-        qWarning() << "Unsupported input type " << endpoint.toString();
-        return Endpoint::Pointer();
-    }
-
-    UserInputMapper::Input ScriptingInterface::inputFor(const QString& inputName) {
-        return DependencyManager::get<UserInputMapper>()->findDeviceInput(inputName);
-    }
-
-    Endpoint::Pointer ScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) {
-        auto iterator = _endpoints.find(inputId);
-        if (_endpoints.end() == iterator) {
-            qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
-            return Endpoint::Pointer();
-        }
-        return iterator->second;
-    }
-
-    Endpoint::Pointer ScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) {
-        EndpointPair pair(first, second);
-        Endpoint::Pointer result;
-        auto iterator = _compositeEndpoints.find(pair);
-        if (_compositeEndpoints.end() == iterator) {
-            result = std::make_shared<CompositeEndpoint>(first, second);
-            _compositeEndpoints[pair] = result;
-        } else {
-            result = iterator->second;
-        }
-        return result;
-    }
-
-    bool ScriptingInterface::isPrimaryButtonPressed() const {
-        return isButtonPressed(StandardButtonChannel::A);
-    }
-        
-    glm::vec2 ScriptingInterface::getPrimaryJoystickPosition() const {
-        return getJoystickPosition(0);
-    }
-
-    int ScriptingInterface::getNumberOfButtons() const {
-        return StandardButtonChannel::NUM_STANDARD_BUTTONS;
-    }
-
-    bool ScriptingInterface::isButtonPressed(int buttonIndex) const {
-        return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0f ? false : true;
-    }
-
-    int ScriptingInterface::getNumberOfTriggers() const {
-        return StandardCounts::TRIGGERS;
-    }
-
-    float ScriptingInterface::getTriggerValue(int triggerIndex) const {
-        return getAxisValue(triggerIndex == 0 ? StandardAxisChannel::LT : StandardAxisChannel::RT);
-    }
-
-    int ScriptingInterface::getNumberOfJoysticks() const {
-        return StandardCounts::ANALOG_STICKS;
-    }
-
-    glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const {
-        StandardAxisChannel xid = StandardAxisChannel::LX; 
-        StandardAxisChannel yid = StandardAxisChannel::LY;
-        if (joystickIndex != 0) {
-            xid = StandardAxisChannel::RX;
-            yid = StandardAxisChannel::RY;
-        }
-        vec2 result;
-        result.x = getAxisValue(xid);
-        result.y = getAxisValue(yid);
-        return result;
-    }
-
-    int ScriptingInterface::getNumberOfSpatialControls() const {
-        return StandardCounts::POSES;
-    }
-
-    glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const {
-        // FIXME extract the position from the standard pose
-        return vec3();
-    }
-
-    glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
-        // FIXME extract the velocity from the standard pose
-        return vec3();
-    }
-
-    glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const {
-        // FIXME extract the normal from the standard pose
-        return vec3();
-    }
-    
-    glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
-        // FIXME extract the rotation from the standard pose
-        return quat();
-    }
-
-    void ScriptingInterface::updateMaps() {
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        auto devices = userInputMapper->getDevices();
-        QSet<QString> foundDevices;
-        for (const auto& deviceMapping : devices) {
-            auto deviceID = deviceMapping.first;
-            if (deviceID != userInputMapper->getStandardDeviceID()) {
-                auto device = deviceMapping.second.get();
-                auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
-                qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
-                foundDevices.insert(device->getName());
-                if (_hardware.contains(deviceName)) {
-                    continue;
-                }
-
-                // Expose the IDs to JS
-                _hardware.insert(deviceName, createDeviceMap(device));
-
-                // Create the endpoints
-                for (const auto& inputMapping : device->getAvailabeInputs()) {
-                    const auto& input = inputMapping.first;
-                    // Ignore aliases
-                    if (_endpoints.count(input)) {
-                        continue;
-                    }
-                    _endpoints[input] = std::make_shared<LambdaEndpoint>([=] {
-                        auto deviceProxy = userInputMapper->getDeviceProxy(input);
-                        if (!deviceProxy) {
-                            return 0.0f;
-                        }
-                        return deviceProxy->getValue(input, 0);
-                    });
-                }
-            }
-        }
-    }
-
-    QVector<UserInputMapper::Action> ScriptingInterface::getAllActions() {
+    QVector<Action> ScriptingInterface::getAllActions() {
         return DependencyManager::get<UserInputMapper>()->getAllActions();
     }
 
@@ -502,7 +171,7 @@ namespace controller {
         return DependencyManager::get<UserInputMapper>()->getDeviceName((unsigned short)device);
     }
 
-    QVector<UserInputMapper::InputPair> ScriptingInterface::getAvailableInputs(unsigned int device) {
+    QVector<InputPair> ScriptingInterface::getAvailableInputs(unsigned int device) {
         return DependencyManager::get<UserInputMapper>()->getAvailableInputs((unsigned short)device);
     }
 
@@ -515,7 +184,7 @@ namespace controller {
     }
 
     float ScriptingInterface::getActionValue(int action) {
-        return DependencyManager::get<UserInputMapper>()->getActionState(UserInputMapper::Action(action));
+        return DependencyManager::get<UserInputMapper>()->getActionState(Action(action));
     }
 
     int ScriptingInterface::findAction(QString actionName) {
@@ -526,41 +195,40 @@ namespace controller {
         return DependencyManager::get<UserInputMapper>()->getActionNames();
     }
 
+    void ScriptingInterface::updateMaps() {
+        auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+        auto devices = userInputMapper->getDevices();
+        QSet<QString> foundDevices;
+        for (const auto& deviceMapping : devices) {
+            auto deviceID = deviceMapping.first;
+            if (deviceID != userInputMapper->getStandardDeviceID()) {
+                auto device = deviceMapping.second;
+                auto deviceName = QString(device->getName()).remove(SANITIZE_NAME_EXPRESSION);
+                qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
+                foundDevices.insert(device->getName());
+                if (_hardware.contains(deviceName)) {
+                    continue;
+                }
+
+                // Expose the IDs to JS
+                _hardware.insert(deviceName, createDeviceMap(device));
+            }
+
+        }
+    }
+
+
+    QObject* ScriptingInterface::parseMapping(const QString& json) {
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        auto mapping = userInputMapper->parseMapping(json);
+        return new MappingBuilderProxy(*userInputMapper, mapping);
+    }
+
+    QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) {
+        return nullptr;
+    }
+
+
 } // namespace controllers
 
 
-using namespace controller;
-// FIXME this throws a hissy fit on MSVC if I put it in the main controller namespace block
-ScriptingInterface::ScriptingInterface() {
-    auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    qCDebug(controllers) << "Setting up standard controller abstraction";
-    auto standardDevice = userInputMapper->getStandardDevice();
-    // Expose the IDs to JS
-    _standard = createDeviceMap(standardDevice.get());
-    // Create the endpoints
-    for (const auto& inputMapping : standardDevice->getAvailabeInputs()) {
-        const auto& standardInput = inputMapping.first;
-        // Ignore aliases
-        if (_endpoints.count(standardInput)) {
-            continue;
-        }
-        _endpoints[standardInput] = std::make_shared<VirtualEndpoint>(standardInput);
-    }
-
-    // FIXME allow custom user actions?
-    auto actionNames = userInputMapper->getActionNames();
-    int actionNumber = 0;
-    qCDebug(controllers) << "Setting up standard actions";
-    for (const auto& actionName : actionNames) {
-        UserInputMapper::Input actionInput(UserInputMapper::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
-        qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16);
-        // Expose the IDs to JS
-        QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
-        _actions.insert(cleanActionName, actionInput.getID());
-
-        // Create the action endpoints
-        _endpoints[actionInput] = std::make_shared<ActionEndpoint>(actionInput);
-    }
-
-    updateMaps();
-}
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index f473562b9e..b43e065822 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -32,7 +32,6 @@
 
 #include "UserInputMapper.h"
 #include "StandardControls.h"
-#include "Mapping.h"
 
 namespace controller {
     class InputController : public QObject {
@@ -65,10 +64,10 @@ namespace controller {
 
     public:
         ScriptingInterface();
-        virtual ~ScriptingInterface();
+        virtual ~ScriptingInterface() {};
 
-        Q_INVOKABLE QVector<UserInputMapper::Action> getAllActions();
-        Q_INVOKABLE QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
+        Q_INVOKABLE QVector<Action> getAllActions();
+        Q_INVOKABLE QVector<Input::NamedPair> getAvailableInputs(unsigned int device);
         Q_INVOKABLE QString getDeviceName(unsigned int device);
         Q_INVOKABLE float getActionValue(int action);
         Q_INVOKABLE int findDevice(QString name);
@@ -87,23 +86,23 @@ namespace controller {
         Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl);
 
 
-        Q_INVOKABLE bool isPrimaryButtonPressed() const;
-        Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const;
+        //Q_INVOKABLE bool isPrimaryButtonPressed() const;
+        //Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const;
 
-        Q_INVOKABLE int getNumberOfButtons() const;
-        Q_INVOKABLE bool isButtonPressed(int buttonIndex) const;
+        //Q_INVOKABLE int getNumberOfButtons() const;
+        //Q_INVOKABLE bool isButtonPressed(int buttonIndex) const;
 
-        Q_INVOKABLE int getNumberOfTriggers() const;
-        Q_INVOKABLE float getTriggerValue(int triggerIndex) const;
+        //Q_INVOKABLE int getNumberOfTriggers() const;
+        //Q_INVOKABLE float getTriggerValue(int triggerIndex) const;
 
-        Q_INVOKABLE int getNumberOfJoysticks() const;
-        Q_INVOKABLE glm::vec2 getJoystickPosition(int joystickIndex) const;
+        //Q_INVOKABLE int getNumberOfJoysticks() const;
+        //Q_INVOKABLE glm::vec2 getJoystickPosition(int joystickIndex) const;
 
-        Q_INVOKABLE int getNumberOfSpatialControls() const;
-        Q_INVOKABLE glm::vec3 getSpatialControlPosition(int controlIndex) const;
-        Q_INVOKABLE glm::vec3 getSpatialControlVelocity(int controlIndex) const;
-        Q_INVOKABLE glm::vec3 getSpatialControlNormal(int controlIndex) const;
-        Q_INVOKABLE glm::quat getSpatialControlRawRotation(int controlIndex) const;
+        //Q_INVOKABLE int getNumberOfSpatialControls() const;
+        //Q_INVOKABLE glm::vec3 getSpatialControlPosition(int controlIndex) const;
+        //Q_INVOKABLE glm::vec3 getSpatialControlVelocity(int controlIndex) const;
+        //Q_INVOKABLE glm::vec3 getSpatialControlNormal(int controlIndex) const;
+        //Q_INVOKABLE glm::quat getSpatialControlRawRotation(int controlIndex) const;
 
         Q_INVOKABLE const QVariantMap& getHardware() { return _hardware; }
         Q_INVOKABLE const QVariantMap& getActions() { return _actions; }
@@ -114,11 +113,7 @@ namespace controller {
         bool isWheelCaptured() const { return _wheelCaptured; }
         bool areActionsCaptured() const { return _actionsCaptured; }
 
-        static QRegularExpression SANITIZE_NAME_EXPRESSION;
-
     public slots:
-        virtual void update();
-        virtual void updateMaps();
 
         virtual void captureMouseEvents() { _mouseCaptured = true; }
         virtual void releaseMouseEvents() { _mouseCaptured = false; }
@@ -134,61 +129,19 @@ namespace controller {
 
 
     private:
-        friend class MappingBuilderProxy;
-        friend class RouteBuilderProxy;
-
-        // FIXME move to unordered set / map
-        using MappingMap = std::map<QString, Mapping::Pointer>;
-        using MappingStack = std::list<Mapping::Pointer>;
-        using InputToEndpointMap = std::map<UserInputMapper::Input, Endpoint::Pointer>;
-        using EndpointSet = std::unordered_set<Endpoint::Pointer>;
-        using ValueMap = std::map<Endpoint::Pointer, float>;
-        using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
-        using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
-
-        void update(Mapping::Pointer& mapping, EndpointSet& consumed);
-        float getValue(const Endpoint::Pointer& endpoint) const;
-        Endpoint::Pointer endpointFor(const QJSValue& endpoint);
-        Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
-        Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint);
-        Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
- 
-        UserInputMapper::Input inputFor(const QString& inputName);
+        // Update the exposed variant maps reporting active hardware
+        void updateMaps();
 
         QVariantMap _hardware;
         QVariantMap _actions;
         QVariantMap _standard;
 
-        InputToEndpointMap _endpoints;
-        EndpointPairMap _compositeEndpoints;
-
-        ValueMap _overrideValues;
-        MappingMap _mappingsByName;
-        MappingStack _activeMappings;
-
         bool _mouseCaptured{ false };
         bool _touchCaptured{ false };
         bool _wheelCaptured{ false };
         bool _actionsCaptured{ false };
     };
 
-    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;
-    };
 
 }
 
diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index 5c13c66a07..f5389d1518 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -9,12 +9,21 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include <limits>
-
-#include <glm/glm.hpp>
-
 #include "StandardController.h"
 
+#include <PathUtils.h>
+
+#include "DeviceProxy.h"
+#include "UserInputMapper.h"
+
+namespace controller {
+
+const float CONTROLLER_THRESHOLD = 0.3f;
+
+StandardController::StandardController() : InputDevice("Standard") { 
+    _deviceID = UserInputMapper::STANDARD_DEVICE; 
+}
+
 StandardController::~StandardController() {
 }
 
@@ -26,143 +35,111 @@ void StandardController::focusOutEvent() {
     _buttonPressedMap.clear();
 };
 
-void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getStandardDeviceID();
-    
-    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
-    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
+void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
+    proxy->_name = _name;
+    proxy->getButton = [this] (const Input& input, int timestamp) -> bool { return getButton(input.getChannel()); };
+    proxy->getAxis = [this] (const Input& input, int timestamp) -> float { return getAxis(input.getChannel()); };
+    proxy->getAvailabeInputs = [this] () -> QVector<Input::NamedPair> {
+        QVector<Input::NamedPair> availableInputs;
         // Buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::A), "A"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::B), "B"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::X), "X"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::Y), "Y"));
 
         // DPad
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::DU), "DU"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::DD), "DD"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::DL), "DL"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::DR), "DR"));
 
         // Bumpers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::LB), "LB"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::RB), "RB"));
 
         // Stick press
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::LS), "LS"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::RS), "RS"));
 
         // Center buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::START), "Start"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::BACK), "Back"));
 
         // Analog sticks
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::LY), "LY"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::LX), "LX"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::RY), "RY"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::RX), "RX"));
 
         // Triggers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::LT), "LT"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::RT), "RT"));
 
         // Poses
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT), "LeftPose"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT), "RightPose"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::LEFT), "LeftPose"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::RIGHT), "RightPose"));
 
         // Aliases, PlayStation style names
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
-
-
+        availableInputs.append(Input::NamedPair(makeInput(controller::LB), "L1"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::RB), "R1"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::LT), "L2"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::RT), "R2"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::LS), "L3"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::RS), "R3"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::BACK), "Select"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::A), "Cross"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::B), "Circle"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::X), "Square"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::Y), "Triangle"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::DU), "Up"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::DD), "Down"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::DL), "Left"));
+        availableInputs.append(Input::NamedPair(makeInput(controller::DR), "Right"));
         return availableInputs;
     };
-
-    mapper.registerStandardDevice(proxy);
 }
 
-void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    const float DPAD_MOVE_SPEED = 0.5f;
-    const float JOYSTICK_YAW_SPEED = 0.5f;
-    const float JOYSTICK_PITCH_SPEED = 0.25f;
-    const float BOOM_SPEED = 0.1f;
 
-    // Y axes are flipped (up is negative)
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED);
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED);
-
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED);
-
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED);
-
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LB), BOOM_SPEED);
-
-    // Hold front right shoulder button for precision controls
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
-
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
-
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
-
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
-
-    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
-    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A));
+QString StandardController::getDefaultMappingConfig() {
+    static const QString DEFAULT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard.json";
+    return DEFAULT_MAPPING_JSON;
 }
 
-UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) {
-    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
-}
+// FIXME figure out how to move the shifted version to JSON
+//void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
+//    const float JOYSTICK_MOVE_SPEED = 1.0f;
+//    const float DPAD_MOVE_SPEED = 0.5f;
+//    const float JOYSTICK_YAW_SPEED = 0.5f;
+//    const float JOYSTICK_PITCH_SPEED = 0.25f;
+//    const float BOOM_SPEED = 0.1f;
+//
+//    // Hold front right shoulder button for precision controls
+//    // Left Joystick: Movement, strafing
+//    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
+//    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
+//
+//    // Right Joystick: Camera orientation
+//    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
+//    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
+//
+//    // Dpad movement
+//    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+//    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+//    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+//    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+//
+//    // Button controls
+//    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+//    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
+//
+//    // Zoom
+//    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
+//    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
+//
+//    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
+//
+//    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
+//    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A));
+//}
 
-UserInputMapper::Input StandardController::makeInput(controller::StandardAxisChannel axis) {
-    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
-}
-
-UserInputMapper::Input StandardController::makeInput(controller::StandardPoseChannel pose) {
-    return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
 }
diff --git a/libraries/controllers/src/controllers/StandardController.h b/libraries/controllers/src/controllers/StandardController.h
index c393af80f4..4aad513553 100644
--- a/libraries/controllers/src/controllers/StandardController.h
+++ b/libraries/controllers/src/controllers/StandardController.h
@@ -12,37 +12,31 @@
 #ifndef hifi_StandardController_h
 #define hifi_StandardController_h
 
-#include <qobject.h>
-#include <qvector.h>
+#include <QtCore/QObject>
+#include <QtCore/QVector>
 
 #include "InputDevice.h"
-
 #include "StandardControls.h"
 
-typedef std::shared_ptr<StandardController> StandardControllerPointer;
+namespace controller {
 
 class StandardController : public QObject, public InputDevice {
     Q_OBJECT
     Q_PROPERTY(QString name READ getName)
 
 public:
-
     const QString& getName() const { return _name; }
 
     // Device functions
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+    virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override;
+    virtual QString getDefaultMappingConfig() override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
-    
-    StandardController() : InputDevice("Standard") {}
-    ~StandardController();
-    
-    UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
-    UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
-    UserInputMapper::Input makeInput(controller::StandardPoseChannel pose);
 
-private:
+    StandardController(); 
+    virtual ~StandardController();
 };
 
+}
+
 #endif // hifi_StandardController_h
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 26e03b7719..7b009273a1 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -7,20 +7,156 @@
 //
 
 #include "UserInputMapper.h"
-#include "StandardController.h"
 
+#include <QtCore/QThread>
+#include <QtCore/QFile>
+
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
+#include <PathUtils.h>
+
+#include "StandardController.h"
 #include "Logging.h"
 
-const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - (uint16)1;
-const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
+namespace controller {
+    const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
+    const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
+}
 
 // Default contruct allocate the poutput size with the current hardcoded action channels
-UserInputMapper::UserInputMapper() {
-    registerStandardDevice();
+controller::UserInputMapper::UserInputMapper() {
+    _activeMappings.push_back(_defaultMapping);
+    _standardController = std::make_shared<StandardController>();
+    registerDevice(new ActionsDevice());
+    registerDevice(_standardController.get());
     assignDefaulActionScales();
-    createActionNames();
 }
 
+namespace controller {
+
+class ScriptEndpoint : public Endpoint {
+    Q_OBJECT;
+public:
+    ScriptEndpoint(const QScriptValue& callable)
+        : Endpoint(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;
+};
+
+class VirtualEndpoint : public Endpoint {
+public:
+    VirtualEndpoint(const Input& id = Input::INVALID_INPUT)
+        : Endpoint(id) {
+    }
+
+    virtual float value() override { return _currentValue; }
+    virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; }
+
+private:
+    float _currentValue{ 0.0f };
+};
+
+
+class JSEndpoint : public Endpoint {
+public:
+    JSEndpoint(const QJSValue& callable)
+        : Endpoint(Input::INVALID_INPUT), _callable(callable) {
+    }
+
+    virtual float value() {
+        float result = (float)_callable.call().toNumber();;
+        return result;
+    }
+
+    virtual void apply(float newValue, float oldValue, const Pointer& source) {
+        _callable.call(QJSValueList({ QJSValue(newValue) }));
+    }
+
+private:
+    QJSValue _callable;
+};
+
+float ScriptEndpoint::value() {
+    updateValue();
+    return _lastValue;
+}
+
+void ScriptEndpoint::updateValue() {
+    if (QThread::currentThread() != thread()) {
+        QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
+        return;
+    }
+
+    _lastValue = (float)_callable.call().toNumber();
+}
+
+void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
+    internalApply(newValue, oldValue, source->getInput().getID());
+}
+
+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:
+    CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
+        : Endpoint(Input(Input::INVALID_INPUT)), Pair(first, second) { }
+
+    virtual float value() {
+        float result = first->value() * -1.0f + second->value();
+        return result;
+    }
+
+    virtual void apply(float newValue, float oldValue, const Pointer& source) {
+        // Composites are read only
+    }
+
+private:
+    Endpoint::Pointer _first;
+    Endpoint::Pointer _second;
+};
+
+class ActionEndpoint : public Endpoint {
+public:
+    ActionEndpoint(const Input& id = Input::INVALID_INPUT)
+        : Endpoint(id) {
+    }
+
+    virtual float value() override { return _currentValue; }
+    virtual void apply(float newValue, float oldValue, const Pointer& source) override {
+
+        _currentValue += newValue;
+        if (!(_input == Input::INVALID_INPUT)) {
+            auto userInputMapper = DependencyManager::get<UserInputMapper>();
+            userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
+        }
+    }
+
+private:
+    float _currentValue{ 0.0f };
+};
+
+
 UserInputMapper::~UserInputMapper() {
 }
 
@@ -32,28 +168,58 @@ int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
     return _deviceCounts[deviceName];
 }
 
-bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) {
+void UserInputMapper::registerDevice(InputDevice* device) {
+    if (device->_deviceID == Input::INVALID_DEVICE) {
+        device->_deviceID = getFreeDeviceID();
+    }
+    const auto& deviceID = device->_deviceID;
+    DeviceProxy::Pointer proxy = std::make_shared<DeviceProxy>();
+    proxy->_name = device->_name;
+    device->buildDeviceProxy(proxy);
+
     int numberOfType = recordDeviceOfType(proxy->_name);
-    
     if (numberOfType > 1) {
         proxy->_name += QString::number(numberOfType);
     }
-    
+
     qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
+
+    for (const auto& inputMapping : proxy->getAvailabeInputs()) {
+        const auto& input = inputMapping.first;
+        // Ignore aliases
+        if (_endpointsByInput.count(input)) {
+            continue;
+        }
+        Endpoint::Pointer endpoint;
+        if (input.device == STANDARD_DEVICE) {
+             endpoint = std::make_shared<VirtualEndpoint>(input);
+        } else if (input.device == ACTIONS_DEVICE) {
+            endpoint = std::make_shared<ActionEndpoint>(input);
+        } else {
+            endpoint = std::make_shared<LambdaEndpoint>([=] {
+                return proxy->getValue(input, 0);
+            });
+        }
+        _inputsByEndpoint[endpoint] = input;
+        _endpointsByInput[input] = endpoint;
+    }
+
     _registeredDevices[deviceID] = proxy;
-    return true;
-    
+    auto mapping = loadMapping(device->getDefaultMappingConfig());
+    if (mapping) {
+        _mappingsByDevice[deviceID] = mapping;
+        for (const auto& entry : mapping->channelMappings) {
+            const auto& source = entry.first;
+            const auto& routes = entry.second;
+            auto& list = _defaultMapping->channelMappings[source];
+            list.insert(list.end(), routes.begin(), routes.end());
+        }
+    }
+
+    emit hardwareChanged();
 }
 
-
-bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) {
-    device->_name = "Standard"; // Just to make sure
-    _registeredDevices[getStandardDeviceID()] = device;
-    return true;
-}
-
-
-UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
+DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
     auto device = _registeredDevices.find(input.getDevice());
     if (device != _registeredDevices.end()) {
         return (device->second);
@@ -69,25 +235,9 @@ QString UserInputMapper::getDeviceName(uint16 deviceID) {
     return QString("unknown");
 }
 
-
-void UserInputMapper::resetAllDeviceBindings() {
-    for (auto device : _registeredDevices) {
-        device.second->resetDeviceBindings();
-    }
-}
-
-void UserInputMapper::resetDevice(uint16 deviceID) {
-    auto device = _registeredDevices.find(deviceID);
-    if (device != _registeredDevices.end()) {
-        device->second->resetDeviceBindings();
-    }
-}
-
 int UserInputMapper::findDevice(QString name) const {
     for (auto device : _registeredDevices) {
-        if (device.second->_name.split(" (")[0] == name) {
-            return device.first;
-        } else if (device.second->_baseName == name) {
+        if (device.second->_name == name) {
             return device.first;
         }
     }
@@ -103,8 +253,11 @@ QVector<QString> UserInputMapper::getDeviceNames() {
     return result;
 }
 
-UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
-    
+int UserInputMapper::findAction(const QString& actionName) const {
+    return findDeviceInput("Actions." + actionName).getChannel();
+}
+
+Input UserInputMapper::findDeviceInput(const QString& inputName) const {
     // Split the full input name as such: deviceName.inputName
     auto names = inputName.split('.');
 
@@ -126,20 +279,9 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName
 
             qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">";
 
-        } else if (deviceName == "Actions") {
-            deviceID = ACTIONS_DEVICE;
-            int actionNum = 0;
-            for (auto action : _actionNames) {
-                if (action == inputName) {
-                    return Input(ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
-                }
-                actionNum++;
-            }
-
-            qCDebug(controllers) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions";
-
         } else {
             qCDebug(controllers) << "Couldn\'t find InputDevice named <" << deviceName << ">";
+            findDevice(deviceName);
         }
     } else {
         qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
@@ -148,100 +290,11 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName
     return Input::INVALID_INPUT;
 }
 
-
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
-    return addInputChannel(action, input, Input(), scale);
-}
-
-bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
-    // Check that the device is registered
-    if (!getDeviceProxy(input)) {
-        qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
-        return false;
-    }
-    
-    auto inputChannel = InputChannel(input, modifier, action, scale);
-
-    // Insert or replace the input to modifiers
-    if (inputChannel.hasModifier()) {
-        auto& modifiers = _inputToModifiersMap[input.getID()];
-        modifiers.push_back(inputChannel._modifier);
-        std::sort(modifiers.begin(), modifiers.end());
-    }
-
-    // Now update the action To Inputs side of things
-    _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
-
-    return true;
-}
-
-int UserInputMapper::addInputChannels(const InputChannels& channels) {
-    int nbAdded = 0;
-    for (auto& channel : channels) {
-        nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
-    }
-    return nbAdded;
-}
-
-bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
-    // Remove from Input to Modifiers map
-    if (inputChannel.hasModifier()) {
-        _inputToModifiersMap.erase(inputChannel._input.getID());
-    }
-    
-    // Remove from Action to Inputs map
-    std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
-    ret = _actionToInputsMap.equal_range(inputChannel._action);
-    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
-        if (it->second == inputChannel) {
-            _actionToInputsMap.erase(it);
-            return true;
-        }
-    }
-    
-    return false;
-}
-
-void UserInputMapper::removeAllInputChannels() {
-    _inputToModifiersMap.clear();
-    _actionToInputsMap.clear();
-}
-
-void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
-    QVector<InputChannel> channels = getAllInputsForDevice(device);
-    for (auto& channel : channels) {
-        removeInputChannel(channel);
-    }
-}
-
+// FIXME remove the associated device mappings
 void UserInputMapper::removeDevice(int device) {
-    removeAllInputChannelsForDevice((uint16) device);
     _registeredDevices.erase(device);
 }
 
-int UserInputMapper::getInputChannels(InputChannels& channels) const {
-    for (auto& channel : _actionToInputsMap) {
-        channels.push_back(channel.second);
-    }
-
-    return _actionToInputsMap.size();
-}
-
-QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
-    InputChannels allChannels;
-    getInputChannels(allChannels);
-    
-    QVector<InputChannel> channels;
-    for (InputChannel inputChannel : allChannels) {
-        if (inputChannel._input._device == device) {
-            channels.push_back(inputChannel);
-        }
-    }
-    
-    return channels;
-}
-
 void fixBisectedAxis(float& full, float& negative, float& positive) {
     full = full + (negative * -1.0f) + positive;
     negative = full >= 0.0f ? 0.0f : full * -1.0f;
@@ -249,64 +302,17 @@ void fixBisectedAxis(float& full, float& negative, float& positive) {
 }
 
 void UserInputMapper::update(float deltaTime) {
-
     // Reset the axis state for next loop
     for (auto& channel : _actionStates) {
         channel = 0.0f;
     }
     
     for (auto& channel : _poseStates) {
-        channel = PoseValue();
+        channel = Pose();
     }
 
-    int currentTimestamp = 0;
-    for (auto& channelInput : _actionToInputsMap) {
-        auto& inputMapping = channelInput.second;
-        auto& inputID = inputMapping._input;
-        bool enabled = true;
-        
-        // Check if this input channel has modifiers and collect the possibilities
-        auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
-        if (modifiersIt != _inputToModifiersMap.end()) {
-            Modifiers validModifiers;
-            bool isActiveModifier = false;
-            for (auto& modifier : modifiersIt->second) {
-                auto deviceProxy = getDeviceProxy(modifier);
-                if (deviceProxy->getButton(modifier, currentTimestamp)) {
-                    validModifiers.push_back(modifier);
-                    isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
-                }
-            }
-            enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
-        }
-
-        // if enabled: default input or all modifiers on
-        if (enabled) {
-            auto deviceProxy = getDeviceProxy(inputID);
-            switch (inputMapping._input.getType()) {
-                case ChannelType::BUTTON: {
-                    _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
-                    break;
-                }
-                case ChannelType::AXIS: {
-                    _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
-                    break;
-                }
-                case ChannelType::POSE: {
-                    if (!_poseStates[channelInput.first].isValid()) {
-                        _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
-                    }
-                    break;
-                }
-                default: {
-                    break; //silence please
-                }
-            }
-        } else{
-            // Channel input not enabled
-            enabled = false;
-        }
-    }
+    // Run the mappings code
+    update();
 
     // Scale all the channel step with the scale
     for (auto i = 0; i < NUM_ACTIONS; i++) {
@@ -337,7 +343,12 @@ void UserInputMapper::update(float deltaTime) {
     }
 }
 
-QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
+Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const {
+    auto iterator = _registeredDevices.find(deviceID);
+    return iterator->second->getAvailabeInputs();
+}
+
+QVector<Action> UserInputMapper::getAllActions() const {
     QVector<Action> actions;
     for (auto i = 0; i < NUM_ACTIONS; i++) {
         actions.append(Action(i));
@@ -345,31 +356,20 @@ QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
     return actions;
 }
 
-QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
-    QVector<InputChannel> inputChannels;
-    std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
-    ret = _actionToInputsMap.equal_range(action);
-    for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
-        inputChannels.append(it->second);
-    }
-    return inputChannels;
-}
-
-int UserInputMapper::findAction(const QString& actionName) const {
-    auto actions = getAllActions();
-    for (auto action : actions) {
-        if (getActionName(action) == actionName) {
-            return action;
+QString UserInputMapper::getActionName(Action action) const {
+    for (auto actionPair : getActionInputs()) {
+        if (actionPair.first.channel == action) {
+            return actionPair.second;
         }
     }
-    // If the action isn't found, return -1
-    return -1;
+    return QString();
 }
 
+
 QVector<QString> UserInputMapper::getActionNames() const {
     QVector<QString> result;
-    for (auto i = 0; i < NUM_ACTIONS; i++) {
-        result << _actionNames[i];
+    for (auto actionPair : getActionInputs()) {
+        result << actionPair.second;
     }
     return result;
 }
@@ -402,56 +402,18 @@ void UserInputMapper::assignDefaulActionScales() {
     _actionScales[YAW] = 1.0f; // default
 }
 
-// This is only necessary as long as the actions are hardcoded
-// Eventually you can just add the string when you add the action
-void UserInputMapper::createActionNames() {
-    _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
-    _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
-    _actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
-    _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
-    _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
-    _actionNames[VERTICAL_UP] = "VERTICAL_UP";
-    _actionNames[YAW_LEFT] = "YAW_LEFT";
-    _actionNames[YAW_RIGHT] = "YAW_RIGHT";
-    _actionNames[PITCH_DOWN] = "PITCH_DOWN";
-    _actionNames[PITCH_UP] = "PITCH_UP";
-    _actionNames[BOOM_IN] = "BOOM_IN";
-    _actionNames[BOOM_OUT] = "BOOM_OUT";
-    _actionNames[LEFT_HAND] = "LEFT_HAND";
-    _actionNames[RIGHT_HAND] = "RIGHT_HAND";
-    _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
-    _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
-    _actionNames[SHIFT] = "SHIFT";
-    _actionNames[ACTION1] = "ACTION1";
-    _actionNames[ACTION2] = "ACTION2";
-    _actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
-    _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
-    _actionNames[TRANSLATE_X] = "TranslateX";
-    _actionNames[TRANSLATE_Y] = "TranslateY";
-    _actionNames[TRANSLATE_Z] = "TranslateZ";
-    _actionNames[ROLL] = "Roll";
-    _actionNames[PITCH] = "Pitch";
-    _actionNames[YAW] = "Yaw";
-}
+static int actionMetaTypeId = qRegisterMetaType<Action>();
+static int inputMetaTypeId = qRegisterMetaType<Input>();
+static int inputPairMetaTypeId = qRegisterMetaType<InputPair>();
 
-void UserInputMapper::registerStandardDevice() {
-    _standardController = std::make_shared<StandardController>();
-    _standardController->registerToUserInputMapper(*this);
-    _standardController->assignDefaultInputMapping(*this);
-}
+QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input);
+void inputFromScriptValue(const QScriptValue& object, Input& input);
+QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action);
+void actionFromScriptValue(const QScriptValue& object, Action& action);
+QScriptValue inputPairToScriptValue(QScriptEngine* engine, const InputPair& inputPair);
+void inputPairFromScriptValue(const QScriptValue& object, InputPair& inputPair);
 
-static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
-static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
-static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
-
-QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input);
-void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input);
-QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action);
-void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action);
-QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair);
-void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair);
-
-QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) {
+QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input) {
     QScriptValue obj = engine->newObject();
     obj.setProperty("device", input.getDevice());
     obj.setProperty("channel", input.getChannel());
@@ -460,14 +422,11 @@ QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::In
     return obj;
 }
 
-void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) {
-    input.setDevice(object.property("device").toUInt16());
-    input.setChannel(object.property("channel").toUInt16());
-    input.setType(object.property("type").toUInt16());
-    input.setID(object.property("id").toInt32());
+void inputFromScriptValue(const QScriptValue& object, Input& input) {
+    input.id = object.property("id").toInt32();
 }
 
-QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) {
+QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action) {
     QScriptValue obj = engine->newObject();
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     obj.setProperty("action", (int)action);
@@ -475,38 +434,361 @@ QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::A
     return obj;
 }
 
-void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) {
-    action = UserInputMapper::Action(object.property("action").toVariant().toInt());
+void actionFromScriptValue(const QScriptValue& object, Action& action) {
+    action = Action(object.property("action").toVariant().toInt());
 }
 
-QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) {
+QScriptValue inputPairToScriptValue(QScriptEngine* engine, const InputPair& inputPair) {
     QScriptValue obj = engine->newObject();
     obj.setProperty("input", inputToScriptValue(engine, inputPair.first));
     obj.setProperty("inputName", inputPair.second);
     return obj;
 }
 
-void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) {
+void inputPairFromScriptValue(const QScriptValue& object, InputPair& inputPair) {
     inputFromScriptValue(object.property("input"), inputPair.first);
     inputPair.second = QString(object.property("inputName").toVariant().toString());
 }
 
 void UserInputMapper::registerControllerTypes(QScriptEngine* engine) {
-    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
-    qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
+    qScriptRegisterSequenceMetaType<QVector<Action> >(engine);
+    qScriptRegisterSequenceMetaType<QVector<InputPair> >(engine);
     qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
     qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
     qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
 }
 
-UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) {
+Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) {
     return Input(STANDARD_DEVICE, button, ChannelType::BUTTON);
 }
 
-UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) {
+Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) {
     return Input(STANDARD_DEVICE, axis, ChannelType::AXIS);
 }
 
-UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
+Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
     return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
 }
+
+
+
+void UserInputMapper::update() {
+    static auto deviceNames = getDeviceNames();
+    _overrideValues.clear();
+
+    EndpointSet readEndpoints;
+    EndpointSet writtenEndpoints;
+
+    static const int HARDWARE_PASS = 0;
+    static const int STANDARD_PASS = 1;
+
+    // Now process the current values for each level of the stack
+    for (auto& mapping : _activeMappings) {
+        for (int pass = 0; pass < 2; ++pass) {
+            for (const auto& mappingEntry : mapping->channelMappings) {
+                const auto& source = mappingEntry.first;
+                if (_inputsByEndpoint.count(source)) {
+                    auto sourceInput = _inputsByEndpoint[source];
+                    if ((sourceInput.device == STANDARD_DEVICE) ^ (pass == STANDARD_PASS)) {
+                        continue;
+                    }
+                }
+
+                // Endpoints can only be read once (though a given mapping can route them to 
+                // multiple places).  Consider... If the default is to wire the A button to JUMP
+                // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
+                // I press the button.  The exception is if I'm wiring a control back to itself
+                // in order to adjust my interface, like inverting the Y axis on an analog stick
+                if (readEndpoints.count(source)) {
+                    continue;
+                }
+
+                // Apply the value to all the routes
+                const auto& routes = mappingEntry.second;
+
+                for (const auto& route : routes) {
+                    const auto& destination = route->destination;
+                    // THis could happen if the route destination failed to create
+                    // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
+                    if (!destination) {
+                        continue;
+                    }
+
+                    if (writtenEndpoints.count(destination)) {
+                        continue;
+                    }
+
+                    // Standard controller destinations can only be can only be used once.
+                    if (getStandardDeviceID() == destination->getInput().getDevice()) {
+                        writtenEndpoints.insert(destination);
+                    }
+
+                    // Only consume the input if the route isn't a loopback.
+                    // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
+                    bool loopback = source == destination;
+                    if (!loopback) {
+                        readEndpoints.insert(source);
+                    }
+
+                    // Fetch the value, may have been overriden by previous loopback routes
+                    float value = getValue(source);
+
+                    // Apply each of the filters.
+                    const auto& filters = route->filters;
+                    for (const auto& filter : route->filters) {
+                        value = filter->apply(value);
+                    }
+
+                    if (loopback) {
+                        _overrideValues[source] = value;
+                    } else {
+                        destination->apply(value, 0, source);
+                    }
+                }
+            }
+        }
+    }
+}
+
+Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) {
+    if (endpoint.isNumber()) {
+        return endpointFor(Input(endpoint.toInt()));
+    }
+
+    if (endpoint.isCallable()) {
+        auto result = std::make_shared<JSEndpoint>(endpoint);
+        return result;
+    }
+
+    qWarning() << "Unsupported input type " << endpoint.toString();
+    return Endpoint::Pointer();
+}
+
+Endpoint::Pointer UserInputMapper::endpointFor(const QScriptValue& endpoint) {
+    if (endpoint.isNumber()) {
+        return endpointFor(Input(endpoint.toInt32()));
+    }
+
+    if (endpoint.isFunction()) {
+        auto result = std::make_shared<ScriptEndpoint>(endpoint);
+        return result;
+    }
+
+    qWarning() << "Unsupported input type " << endpoint.toString();
+    return Endpoint::Pointer();
+}
+
+Endpoint::Pointer UserInputMapper::endpointFor(const Input& inputId) const {
+    auto iterator = _endpointsByInput.find(inputId);
+    if (_endpointsByInput.end() == iterator) {
+        qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
+        return Endpoint::Pointer();
+    }
+    return iterator->second;
+}
+
+Endpoint::Pointer UserInputMapper::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) {
+    EndpointPair pair(first, second);
+    Endpoint::Pointer result;
+    auto iterator = _compositeEndpoints.find(pair);
+    if (_compositeEndpoints.end() == iterator) {
+        result = std::make_shared<CompositeEndpoint>(first, second);
+        _compositeEndpoints[pair] = result;
+    } else {
+        result = iterator->second;
+    }
+    return result;
+}
+
+
+Mapping::Pointer UserInputMapper::newMapping(const QString& mappingName) {
+    if (_mappingsByName.count(mappingName)) {
+        qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
+    }
+    qDebug() << "Creating new Mapping " << mappingName;
+    auto mapping = std::make_shared<Mapping>(mappingName);
+    _mappingsByName[mappingName] = mapping;
+    return mapping;
+}
+
+// FIXME handle asynchronous loading in the UserInputMapper
+//QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) {
+//    QObject* result = nullptr;
+//    auto request = ResourceManager::createResourceRequest(nullptr, QUrl(jsonUrl));
+//    if (request) {
+//        QEventLoop eventLoop;
+//        request->setCacheEnabled(false);
+//        connect(request, &ResourceRequest::finished, &eventLoop, &QEventLoop::quit);
+//        request->send();
+//        if (request->getState() != ResourceRequest::Finished) {
+//            eventLoop.exec();
+//        }
+//
+//        if (request->getResult() == ResourceRequest::Success) {
+//            result = parseMapping(QString(request->getData()));
+//        } else {
+//            qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl;
+//        }
+//        request->deleteLater();
+//    }
+//    return result;
+//}
+
+
+void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
+    qCDebug(controllers) << "Attempting to enable mapping " << mappingName;
+    auto iterator = _mappingsByName.find(mappingName);
+    if (_mappingsByName.end() == iterator) {
+        qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName;
+        return;
+    }
+
+    auto mapping = iterator->second;
+    if (enable) {
+        _activeMappings.push_front(mapping);
+    } else {
+        auto activeIterator = std::find(_activeMappings.begin(), _activeMappings.end(), mapping);
+        if (_activeMappings.end() == activeIterator) {
+            qCWarning(controllers) << "Attempted to disable inactive mapping " << mappingName;
+            return;
+        }
+        _activeMappings.erase(activeIterator);
+    }
+}
+
+float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const {
+    auto valuesIterator = _overrideValues.find(endpoint);
+    if (_overrideValues.end() != valuesIterator) {
+        return valuesIterator->second;
+    }
+
+    return endpoint->value();
+}
+
+float UserInputMapper::getValue(const Input& input) const {
+    auto endpoint = endpointFor(input);
+    if (!endpoint) {
+        return 0;
+    }
+    return endpoint->value();
+}
+
+
+Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) {
+    if (jsonFile.isEmpty()) {
+        return Mapping::Pointer();
+    }
+    QString json;
+    {
+        QFile file(jsonFile);
+        if (file.open(QFile::ReadOnly | QFile::Text)) {
+            json = QTextStream(&file).readAll();
+        }
+        file.close();
+    }
+    return parseMapping(json);
+}
+
+
+const QString JSON_NAME = QStringLiteral("name");
+const QString JSON_CHANNELS = QStringLiteral("channels");
+const QString JSON_CHANNEL_FROM = QStringLiteral("from");
+const QString JSON_CHANNEL_TO = QStringLiteral("to");
+const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
+
+Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) {
+    if (value.isString()) {
+        auto input = findDeviceInput(value.toString());
+        return endpointFor(input);
+    } else if (value.isObject()) {
+        // Endpoint is defined as an object, we expect a js function then
+        return Endpoint::Pointer();
+    }
+    return Endpoint::Pointer();
+}
+
+Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
+    if (!value.isObject()) {
+        return Route::Pointer();
+    }
+
+    const auto& obj = value.toObject();
+    Route::Pointer result = std::make_shared<Route>();
+    result->source = parseEndpoint(obj[JSON_CHANNEL_FROM]);
+    if (!result->source) {
+        qWarning() << "Invalid route source " << obj[JSON_CHANNEL_FROM];
+        return Route::Pointer();
+    }
+    result->destination = parseEndpoint(obj[JSON_CHANNEL_TO]);
+    if (!result->destination) {
+        qWarning() << "Invalid route destination " << obj[JSON_CHANNEL_TO];
+        return Route::Pointer();
+    }
+
+    const auto& filtersValue = obj[JSON_CHANNEL_FILTERS];
+    if (filtersValue.isArray()) {
+        auto filtersArray = filtersValue.toArray();
+        for (auto filterValue : filtersArray) {
+            if (filterValue.isObject()) {
+                qWarning() << "Invalid filter " << filterValue;
+                return Route::Pointer();
+            }
+            Filter::Pointer filter = Filter::parse(filterValue.toObject());
+            if (!filter) {
+                qWarning() << "Invalid filter " << filterValue;
+                return Route::Pointer();
+            }
+            result->filters.push_back(filter);
+        }
+    }
+    return result;
+}
+
+Mapping::Pointer UserInputMapper::parseMapping(const QJsonValue& json) {
+    if (!json.isObject()) {
+        return Mapping::Pointer();
+    }
+
+    auto obj = json.toObject();
+    auto mapping = std::make_shared<Mapping>("default");
+    mapping->name = obj[JSON_NAME].toString();
+    mapping->channelMappings.clear();
+    const auto& jsonChannels = obj[JSON_CHANNELS].toArray();
+    Mapping::Map map;
+    for (const auto& channelIt : jsonChannels) {
+        Route::Pointer route = parseRoute(channelIt);
+        if (!route) {
+            qWarning() << "Couldn't parse route";
+            continue;
+        }
+        mapping->channelMappings[route->source].push_back(route);
+    }
+    return mapping;
+}
+
+Mapping::Pointer UserInputMapper::parseMapping(const QString& json) {
+    Mapping::Pointer result;
+    QJsonObject obj;
+    QJsonParseError error;
+    QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error);
+    // check validity of the document
+    if (doc.isNull()) {
+        return Mapping::Pointer();
+    }
+
+    if (!doc.isObject()) {
+        qWarning() << "Mapping json Document is not an object" << endl;
+        return Mapping::Pointer();
+    }
+
+    // FIXME how did we detect this?
+    //    qDebug() << "Invalid JSON...\n";
+    //    qDebug() << error.errorString();
+    //    qDebug() << "JSON was:\n" << json << endl;
+    //}
+    return parseMapping(doc.object());
+}
+
+}
+
+#include "UserInputMapper.moc"
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index d463ed0482..1c1a9506df 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -15,234 +15,155 @@
 #include <unordered_set>
 #include <functional>
 #include <memory>
+
+#include <QtQml/QJSValue>
+#include <QtScript/QScriptValue>
+
 #include <DependencyManager.h>
 #include <RegisteredMetaTypes.h>
 
 #include "Pose.h"
 #include "Input.h"
+#include "InputDevice.h"
 #include "DeviceProxy.h"
 #include "StandardControls.h"
+#include "Mapping.h"
+#include "Endpoint.h"
+#include "Actions.h"
 
-class StandardController;    
-typedef std::shared_ptr<StandardController> StandardControllerPointer;
+namespace controller {
+    class UserInputMapper : public QObject, public Dependency {
+        Q_OBJECT
+            SINGLETON_DEPENDENCY
+            Q_ENUMS(Action)
 
-class UserInputMapper : public QObject, public Dependency {
-    Q_OBJECT
-    SINGLETON_DEPENDENCY
-    Q_ENUMS(Action)
-public:
-    ~UserInputMapper();
-
-    using DeviceProxy = controller::DeviceProxy;
-    using PoseValue = controller::Pose;
-    using Input = controller::Input;
-    using ChannelType = controller::ChannelType;
-
-    typedef unsigned short uint16;
-    typedef unsigned int uint32;
-
-    static void registerControllerTypes(QScriptEngine* engine);
-
-    static const uint16 ACTIONS_DEVICE;
-    static const uint16 STANDARD_DEVICE;
-
-
-    // Modifiers are just button inputID
-    typedef std::vector< Input > Modifiers;
-    typedef std::function<bool (const Input& input, int timestamp)> ButtonGetter;
-    typedef std::function<float (const Input& input, int timestamp)> AxisGetter;
-    typedef std::function<PoseValue (const Input& input, int timestamp)> PoseGetter;
-    typedef QPair<Input, QString> InputPair;
-    typedef std::function<QVector<InputPair> ()> AvailableInputGetter;
-    typedef std::function<bool ()> ResetBindings;
-    
-    typedef QVector<InputPair> AvailableInput;
-
-    // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
-    uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
-
-    bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device);
-    bool registerStandardDevice(const DeviceProxy::Pointer& device);
-    DeviceProxy::Pointer getDeviceProxy(const Input& input);
-    QString getDeviceName(uint16 deviceID);
-    QVector<InputPair> getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); }
-    void resetAllDeviceBindings();
-    void resetDevice(uint16 deviceID);
-    int findDevice(QString name) const;
-    QVector<QString> getDeviceNames();
-
-    Input findDeviceInput(const QString& inputName) const;
-
-
-    // Actions are the output channels of the Mapper, that's what the InputChannel map to
-    // For now the Actions are hardcoded, this is bad, but we will fix that in the near future
-    enum Action {
-        TRANSLATE_X = 0,
-        TRANSLATE_Y,
-        TRANSLATE_Z,
-        ROTATE_X, PITCH = ROTATE_X,
-        ROTATE_Y, YAW = ROTATE_Y,
-        ROTATE_Z, ROLL = ROTATE_Z,
-
-        TRANSLATE_CAMERA_Z,
-        NUM_COMBINED_AXES,
-
-        LEFT_HAND = NUM_COMBINED_AXES,
-        RIGHT_HAND,
-
-        LEFT_HAND_CLICK,
-        RIGHT_HAND_CLICK,
-
-        ACTION1,
-        ACTION2,
-
-        CONTEXT_MENU,
-        TOGGLE_MUTE,
-
-        SHIFT,
-
-        // Biseced aliases for TRANSLATE_Z
-        LONGITUDINAL_BACKWARD,
-        LONGITUDINAL_FORWARD,
-
-        // Biseced aliases for TRANSLATE_X
-        LATERAL_LEFT,
-        LATERAL_RIGHT,
-
-        // Biseced aliases for TRANSLATE_Y
-        VERTICAL_DOWN,
-        VERTICAL_UP,
-
-        // Biseced aliases for ROTATE_Y
-        YAW_LEFT,
-        YAW_RIGHT,
- 
-        // Biseced aliases for ROTATE_X
-        PITCH_DOWN,
-        PITCH_UP,
-
-        // Biseced aliases for TRANSLATE_CAMERA_Z
-        BOOM_IN,
-        BOOM_OUT,
-
-        NUM_ACTIONS,
-    };
-    
-    std::vector<QString> _actionNames = std::vector<QString>(NUM_ACTIONS);
-    void createActionNames();
-
-    QVector<Action> getAllActions() const;
-    QString getActionName(Action action) const { return UserInputMapper::_actionNames[(int) action]; }
-    float getActionState(Action action) const { return _actionStates[action]; }
-    PoseValue getPoseState(Action action) const { return _poseStates[action]; }
-    int findAction(const QString& actionName) const;
-    QVector<QString> getActionNames() const;
-    void assignDefaulActionScales();
-
-    void setActionState(Action action, float value) { _externalActionStates[action] = value; }
-    void deltaActionState(Action action, float delta) { _externalActionStates[action] += delta; }
-
-    // Add input channel to the mapper and check that all the used channels are registered.
-    // Return true if theinput channel is created correctly, false either
-    bool addInputChannel(Action action, const Input& input, float scale = 1.0f);
-    bool addInputChannel(Action action, const Input& input, const Input& modifer, float scale = 1.0f);
-
-    UserInputMapper::Input makeStandardInput(controller::StandardButtonChannel button);
-    UserInputMapper::Input makeStandardInput(controller::StandardAxisChannel axis);
-    UserInputMapper::Input makeStandardInput(controller::StandardPoseChannel pose);
-
-    // Under the hood, the input channels are organized in map sorted on the _output
-    // The InputChannel class is just the full values describing the input channel in one object 
-    class InputChannel {
     public:
-        Input _input;
-        Input _modifier = Input(); // make it invalid by default, meaning no modifier
-        Action _action = LONGITUDINAL_BACKWARD;
-        float _scale = 0.0f;
-        
-        Input getInput() const { return _input; }
-        Input getModifier() const { return _modifier; }
-        Action getAction() const { return _action; }
-        float getScale() const { return _scale; }
-        
-        void setInput(Input input) { _input = input; }
-        void setModifier(Input modifier) { _modifier = modifier; }
-        void setAction(Action action) { _action = action; }
-        void setScale(float scale) { _scale = scale; }
+        using InputPair = Input::NamedPair;
+        // FIXME move to unordered set / map
+        using EndpointToInputMap = std::map<Endpoint::Pointer, Input>;
+        using MappingNameMap = std::map<QString, Mapping::Pointer>;
+        using MappingDeviceMap = std::map<uint16_t, Mapping::Pointer>;
+        using MappingStack = std::list<Mapping::Pointer>;
+        using InputToEndpointMap = std::map<Input, Endpoint::Pointer>;
+        using EndpointSet = std::unordered_set<Endpoint::Pointer>;
+        using ValueMap = std::map<Endpoint::Pointer, float>;
+        using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
+        using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
+        using DevicesMap = std::map<int, DeviceProxy::Pointer>;
+        using uint16 = uint16_t;
+        using uint32 = uint32_t;
 
-        InputChannel() {}
-        InputChannel(const Input& input, const Input& modifier, Action action, float scale = 1.0f) :
-            _input(input), _modifier(modifier), _action(action), _scale(scale) {}
-        InputChannel(const InputChannel& src) : InputChannel(src._input, src._modifier, src._action, src._scale) {}
-        InputChannel& operator = (const InputChannel& src) { _input = src._input; _modifier = src._modifier; _action = src._action; _scale = src._scale; return (*this); }
-        bool operator ==(const InputChannel& right) const { return _input == right._input && _modifier == right._modifier && _action == right._action && _scale == right._scale; }
-        bool hasModifier() { return _modifier.isValid(); }
+        static const uint16_t ACTIONS_DEVICE;
+        static const uint16_t STANDARD_DEVICE;
+
+        UserInputMapper();
+        virtual ~UserInputMapper();
+
+
+        static void registerControllerTypes(QScriptEngine* engine);
+
+
+        void registerDevice(InputDevice* device);
+        DeviceProxy::Pointer getDeviceProxy(const Input& input);
+        QString getDeviceName(uint16 deviceID);
+
+        Input::NamedVector getAvailableInputs(uint16 deviceID) const;
+        Input::NamedVector getActionInputs() const { return getAvailableInputs(ACTIONS_DEVICE); }
+        Input::NamedVector getStandardInputs() const { return getAvailableInputs(STANDARD_DEVICE); }
+
+        int findDevice(QString name) const;
+        QVector<QString> getDeviceNames();
+        Input findDeviceInput(const QString& inputName) const;
+
+        QVector<Action> getAllActions() const;
+        QString getActionName(Action action) const;
+        float getActionState(Action action) const { return _actionStates[action]; }
+        Pose getPoseState(Action action) const { return _poseStates[action]; }
+        int findAction(const QString& actionName) const;
+        QVector<QString> getActionNames() const;
+        void assignDefaulActionScales();
+
+        void setActionState(Action action, float value) { _externalActionStates[action] = value; }
+        void deltaActionState(Action action, float delta) { _externalActionStates[action] += delta; }
+
+        static Input makeStandardInput(controller::StandardButtonChannel button);
+        static Input makeStandardInput(controller::StandardAxisChannel axis);
+        static Input makeStandardInput(controller::StandardPoseChannel pose);
+
+        void removeDevice(int device);
+
+        // Update means go grab all the device input channels and update the output channel values
+        void update(float deltaTime);
+
+        void setSensorToWorldMat(glm::mat4 sensorToWorldMat) { _sensorToWorldMat = sensorToWorldMat; }
+        glm::mat4 getSensorToWorldMat() { return _sensorToWorldMat; }
+
+        DevicesMap getDevices() { return _registeredDevices; }
+        uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
+        DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
+
+        Mapping::Pointer newMapping(const QString& mappingName);
+        Mapping::Pointer parseMapping(const QString& json);
+        Mapping::Pointer loadMapping(const QString& jsonFile);
+
+        void enableMapping(const QString& mappingName, bool enable = true);
+        float getValue(const Input& input) const;
+
+    signals:
+        void actionEvent(int action, float state);
+        void hardwareChanged();
+
+    protected:
+        virtual void update();
+        // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
+        uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
+
+        InputDevice::Pointer _standardController;
+        DevicesMap _registeredDevices;
+        uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
+
+        std::vector<float> _actionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
+        std::vector<float> _externalActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
+        std::vector<float> _actionScales = std::vector<float>(NUM_ACTIONS, 1.0f);
+        std::vector<float> _lastActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
+        std::vector<Pose> _poseStates = std::vector<Pose>(NUM_ACTIONS);
+
+        glm::mat4 _sensorToWorldMat;
+
+        int recordDeviceOfType(const QString& deviceName);
+        QHash<const QString&, int> _deviceCounts;
+
+        float getValue(const Endpoint::Pointer& endpoint) const;
+        friend class RouteBuilderProxy;
+        friend class MappingBuilderProxy;
+        Endpoint::Pointer endpointFor(const QJSValue& endpoint);
+        Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
+        Endpoint::Pointer endpointFor(const Input& endpoint) const;
+        Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
+        Mapping::Pointer parseMapping(const QJsonValue& json);
+        Route::Pointer parseRoute(const QJsonValue& value);
+        Endpoint::Pointer parseEndpoint(const QJsonValue& value);
+
+        InputToEndpointMap _endpointsByInput;
+        EndpointToInputMap _inputsByEndpoint;
+        EndpointPairMap _compositeEndpoints;
+
+        ValueMap _overrideValues;
+        MappingNameMap _mappingsByName;
+        Mapping::Pointer _defaultMapping{ std::make_shared<Mapping>("Default") };
+        MappingDeviceMap _mappingsByDevice;
+        MappingStack _activeMappings;
     };
-    typedef std::vector< InputChannel > InputChannels;
+}
 
-    // Add a bunch of input channels, return the true number of channels that successfully were added
-    int addInputChannels(const InputChannels& channels);
-    // Remove the first found instance of the input channel from the input mapper, true if found
-    bool removeInputChannel(InputChannel channel);
-    void removeAllInputChannels();
-    void removeAllInputChannelsForDevice(uint16 device);
-    void removeDevice(int device);
-    //Grab all the input channels currently in use, return the number
-    int getInputChannels(InputChannels& channels) const;
-    QVector<InputChannel> getAllInputsForDevice(uint16 device);
-    QVector<InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
-    std::multimap<Action, InputChannel> getActionToInputsMap() { return _actionToInputsMap; }
+Q_DECLARE_METATYPE(controller::UserInputMapper::InputPair)
+Q_DECLARE_METATYPE(controller::Pose)
+Q_DECLARE_METATYPE(QVector<controller::UserInputMapper::InputPair>)
+Q_DECLARE_METATYPE(controller::Input)
+Q_DECLARE_METATYPE(controller::Action)
+Q_DECLARE_METATYPE(QVector<controller::Action>)
 
-    // Update means go grab all the device input channels and update the output channel values
-    void update(float deltaTime);
-    
-    void setSensorToWorldMat(glm::mat4 sensorToWorldMat) { _sensorToWorldMat = sensorToWorldMat; }
-    glm::mat4 getSensorToWorldMat() { return _sensorToWorldMat; }
-    
-    UserInputMapper();
-
-    typedef std::map<int, DeviceProxy::Pointer> DevicesMap;
-    DevicesMap getDevices() { return _registeredDevices; }
-
-    uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
-    DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
-
-signals:
-    void actionEvent(int action, float state);
-
-
-protected:
-    void registerStandardDevice();
-    StandardControllerPointer _standardController;
-        
-    DevicesMap _registeredDevices;
-    uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
-
-    typedef std::map<int, Modifiers> InputToMoModifiersMap;
-    InputToMoModifiersMap _inputToModifiersMap;
-
-    typedef std::multimap<Action, InputChannel> ActionToInputsMap;
-    ActionToInputsMap _actionToInputsMap;
- 
-    std::vector<float> _actionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
-    std::vector<float> _externalActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
-    std::vector<float> _actionScales = std::vector<float>(NUM_ACTIONS, 1.0f);
-    std::vector<float> _lastActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
-    std::vector<PoseValue> _poseStates = std::vector<PoseValue>(NUM_ACTIONS);
-
-    glm::mat4 _sensorToWorldMat;
-
-    int recordDeviceOfType(const QString& deviceName);
-    QHash<const QString&, int> _deviceCounts;
-};
-
-Q_DECLARE_METATYPE(UserInputMapper::InputPair)
-Q_DECLARE_METATYPE(UserInputMapper::PoseValue)
-Q_DECLARE_METATYPE(QVector<UserInputMapper::InputPair>)
-Q_DECLARE_METATYPE(UserInputMapper::Input)
-Q_DECLARE_METATYPE(UserInputMapper::InputChannel)
-Q_DECLARE_METATYPE(QVector<UserInputMapper::InputChannel>)
-Q_DECLARE_METATYPE(UserInputMapper::Action)
-Q_DECLARE_METATYPE(QVector<UserInputMapper::Action>)
+// Cheating.
+using UserInputMapper = controller::UserInputMapper;
 
 #endif // hifi_UserInputMapper_h
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index bde10defdc..462a319a90 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -22,7 +22,7 @@ using namespace controller;
 
 QObject* MappingBuilderProxy::from(int input) {
     qCDebug(controllers) << "Creating new Route builder proxy from " << input;
-    auto sourceEndpoint = _parent.endpointFor(UserInputMapper::Input(input));
+    auto sourceEndpoint = _parent.endpointFor(Input(input));
     return from(sourceEndpoint);
 }
 
@@ -41,7 +41,7 @@ QObject* MappingBuilderProxy::from(const QScriptValue& source) {
 QObject* MappingBuilderProxy::from(const Endpoint::Pointer& source) {
     if (source) {
         auto route = Route::Pointer(new Route());
-        route->_source = source;
+        route->source = source;
         return new RouteBuilderProxy(_parent, _mapping, route);
     } else {
         qCDebug(controllers) << "MappingBuilderProxy::from : source is null so no route created";
@@ -55,48 +55,8 @@ QObject* MappingBuilderProxy::makeAxis(const QJSValue& source1, const QJSValue&
     return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint));
 }
 
-const QString JSON_NAME = QStringLiteral("name");
-const QString JSON_CHANNELS = QStringLiteral("channels");
-const QString JSON_CHANNEL_FROM = QStringLiteral("from");
-const QString JSON_CHANNEL_TO = QStringLiteral("to");
-const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
-
-
-void MappingBuilderProxy::parse(const QJsonObject& json) {
-    _mapping->_name = json[JSON_NAME].toString();
-
-    _mapping->_channelMappings.clear();
-    const auto& jsonChannels = json[JSON_CHANNELS].toArray();
-    for (const auto& channelIt : jsonChannels) {
-        parseRoute(channelIt);
-    }
-}
-
-void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
-    if (json.isObject()) {
-        const auto& jsonChannel = json.toObject();
-
-        auto newRoute = from(jsonChannel[JSON_CHANNEL_FROM]);
-        if (newRoute) {
-            auto route = dynamic_cast<RouteBuilderProxy*>(newRoute);
-            route->filters(jsonChannel[JSON_CHANNEL_FILTERS]);
-            route->to(jsonChannel[JSON_CHANNEL_TO]);
-        }
-    }
-}
-
-QObject* MappingBuilderProxy::from(const QJsonValue& json) {
-    if (json.isString()) {
-        return from(_parent.endpointFor(_parent.inputFor(json.toString())));
-    } else if (json.isObject()) {
-        // Endpoint is defined as an object, we expect a js function then
-        return nullptr;
-    }
-    return nullptr;
-}
-
 QObject* MappingBuilderProxy::enable(bool enable) {
-    _parent.enableMapping(_mapping->_name, enable);
+    _parent.enableMapping(_mapping->name, enable);
     return this;
 }
 
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index 53db901436..07c1730836 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -22,13 +22,14 @@ class QJsonValue;
 namespace controller {
 
 class ScriptingInterface;
+class UserInputMapper;
 
 // TODO migrate functionality to a MappingBuilder class and make the proxy defer to that 
 // (for easier use in both C++ and JS)
 class MappingBuilderProxy : public QObject {
     Q_OBJECT
 public:
-    MappingBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping)
+    MappingBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping)
         : _parent(parent), _mapping(mapping) { }
 
     Q_INVOKABLE QObject* from(int sourceInput);
@@ -39,19 +40,11 @@ public:
     Q_INVOKABLE QObject* enable(bool enable = true);
     Q_INVOKABLE QObject* disable() { return enable(false); }
 
-
-    // JSON route creation point
-    Q_INVOKABLE QObject* from(const QJsonValue& json);
-
-
-    void parse(const QJsonObject& json);
-//  void serialize(QJsonObject& json);
-
 protected:
     QObject* from(const Endpoint::Pointer& source);
 
     friend class RouteBuilderProxy;
-    ScriptingInterface& _parent;
+    UserInputMapper& _parent;
     Mapping::Pointer _mapping;
 
 
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index ba2cd60c8b..d60032cb43 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -22,7 +22,7 @@ namespace controller {
 
 void RouteBuilderProxy::to(int destinationInput) {
     qCDebug(controllers) << "Completing route " << destinationInput;
-    auto destinationEndpoint = _parent.endpointFor(UserInputMapper::Input(destinationInput));
+    auto destinationEndpoint = _parent.endpointFor(Input(destinationInput));
     return to(destinationEndpoint);
 }
 
@@ -39,9 +39,9 @@ void RouteBuilderProxy::to(const QScriptValue& destination) {
 }
 
 void RouteBuilderProxy::to(const Endpoint::Pointer& destination) {
-    auto sourceEndpoint = _route->_source;
-    _route->_destination = destination;
-    _mapping->_channelMappings[sourceEndpoint].push_back(_route);
+    auto sourceEndpoint = _route->source;
+    _route->destination = destination;
+    _mapping->channelMappings[sourceEndpoint].push_back(_route);
     deleteLater();
 }
 
@@ -104,37 +104,7 @@ void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
 }
 
 void RouteBuilderProxy::addFilter(Filter::Pointer filter) {
-    _route->_filters.push_back(filter);
-}
-
-
-QObject* RouteBuilderProxy::filters(const QJsonValue& json) {
-    // We expect an array of objects to define the filters
-    if (json.isArray()) {
-        const auto& jsonFilters = json.toArray();
-        for (auto jsonFilter : jsonFilters) {
-            if (jsonFilter.isObject()) {
-                // The filter is an object, now let s check for type and potential arguments
-                Filter::Pointer filter = Filter::parse(jsonFilter.toObject());
-                if (filter) {
-                    addFilter(filter);
-                }
-            }
-        }
-    }
-
-    return this;
-}
-
-void RouteBuilderProxy::to(const QJsonValue& json) {
-    if (json.isString()) {
-
-        return to(_parent.endpointFor(_parent.inputFor(json.toString())));
-    } else if (json.isObject()) {
-        // Endpoint is defined as an object, we expect a js function then
-        //return to((Endpoint*) nullptr);
-    }
-
+    _route->filters.push_back(filter);
 }
 
 }
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 66b5e85394..1b66a3d996 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -10,10 +10,11 @@
 #define hifi_Controllers_Impl_RouteBuilderProxy_h
 
 #include <QtCore/QObject>
+
 #include "../Filter.h"
 #include "../Route.h"
 #include "../Mapping.h"
-
+#include "../UserInputMapper.h"
 class QJSValue;
 class QScriptValue;
 class QJsonValue;
@@ -27,7 +28,7 @@ class ScriptingInterface;
 class RouteBuilderProxy : public QObject {
         Q_OBJECT
     public:
-        RouteBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route)
+        RouteBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping, Route::Pointer route)
             : _parent(parent), _mapping(mapping), _route(route) { }
 
         Q_INVOKABLE void to(int destination);
@@ -44,15 +45,11 @@ class RouteBuilderProxy : public QObject {
         Q_INVOKABLE QObject* constrainToInteger();
         Q_INVOKABLE QObject* constrainToPositiveInteger();
 
-        // JSON route creation point
-        Q_INVOKABLE QObject* filters(const QJsonValue& json);
-        Q_INVOKABLE void to(const QJsonValue& json);
-
-    private:
+private:
         void to(const Endpoint::Pointer& destination);
         void addFilter(Filter::Lambda lambda);
         void addFilter(Filter::Pointer filter);
-        ScriptingInterface& _parent;
+        UserInputMapper& _parent;
         Mapping::Pointer _mapping;
         Route::Pointer _route;
     };
diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt
index 4f2a525f07..bb90c04c95 100644
--- a/libraries/entities-renderer/CMakeLists.txt
+++ b/libraries/entities-renderer/CMakeLists.txt
@@ -1,7 +1,7 @@
 set(TARGET_NAME entities-renderer)
 AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
 setup_hifi_library(Widgets Network Script)
-link_hifi_libraries(shared gpu procedural model model-networking script-engine controllers render render-utils)
+link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)
 
 target_bullet()
 
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index d3e4e7a629..30074b37d3 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -11,16 +11,15 @@
 
 #include "Joystick.h"
 
-#include <limits>
-#include <glm/glm.hpp>
+#include <PathUtils.h>
 
 const float CONTROLLER_THRESHOLD = 0.3f;
 
 #ifdef HAVE_SDL2
 const float MAX_AXIS = 32768.0f;
 
-Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
-        InputDevice(name),
+Joystick::Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameController) :
+        InputDevice("GamePad"),
     _sdlGameController(sdlGameController),
     _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
     _instanceId(instanceId)
@@ -72,136 +71,63 @@ void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
 
 #endif
 
+void Joystick::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
+    using namespace controller;
+    proxy->_name = _name;
+    proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
+    proxy->getAxis = [this](const Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
+    proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
+        QVector<Input::NamedPair> availableInputs{
+            makePair(A, "A"),
+            makePair(B, "B"),
+            makePair(X, "X"),
+            makePair(Y, "Y"),
+            // DPad
+            makePair(DU, "DU"),
+            makePair(DD, "DD"),
+            makePair(DL, "DL"),
+            makePair(DR, "DR"),
+            // Bumpers
+            makePair(LB, "LB"),
+            makePair(RB, "RB"),
+            // Stick press
+            makePair(LS, "LS"),
+            makePair(RS, "RS"),
+            // Center buttons
+            makePair(START, "Start"),
+            makePair(BACK, "Back"),
+            // Analog sticks
+            makePair(LX, "LX"),
+            makePair(LY, "LY"),
+            makePair(RX, "RX"),
+            makePair(RY, "RY"),
+ 
+            // Triggers
+            makePair(LT, "LT"),
+            makePair(RT, "RT"),
 
-void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getFreeDeviceID();
-    
-    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
-    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
-        // Buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
-
-        // DPad
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
-
-        // Bumpers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
-
-        // Stick press
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
-
-        // Center buttons
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
-
-        // Analog sticks
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
-
-        // Triggers
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
-
-        // Aliases, PlayStation style names
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
-
+            // Aliases, PlayStation style names
+            makePair(LB, "L1"),
+            makePair(RB, "R1"),
+            makePair(LT, "L2"),
+            makePair(RT, "R2"),
+            makePair(LS, "L3"),
+            makePair(RS, "R3"),
+            makePair(BACK, "Select"),
+            makePair(A, "Cross"),
+            makePair(B, "Circle"),
+            makePair(X, "Square"),
+            makePair(Y, "Triangle"),
+            makePair(DU, "Up"),
+            makePair(DD, "Down"),
+            makePair(DL, "Left"),
+            makePair(DR, "Right"),
+        };
         return availableInputs;
     };
-    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
-    mapper.registerDevice(_deviceID, proxy);
 }
 
-
-void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
-#if 0
-#ifdef HAVE_SDL2
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    const float DPAD_MOVE_SPEED = 0.5f;
-    const float JOYSTICK_YAW_SPEED = 0.5f;
-    const float JOYSTICK_PITCH_SPEED = 0.25f;
-    const float BOOM_SPEED = 0.1f;
-
-    // Y axes are flipped (up is negative)
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED);
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED);
-
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED);
-
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED);
-
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), BOOM_SPEED);
-
-    // Hold front right shoulder button for precision controls
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
-
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
-
-    // Dpad movement
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-
-    // Button controls
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-
-    // Zoom
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
-
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
-
-    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
-    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A)); 
-#endif
-#endif
-}
\ No newline at end of file
+QString Joystick::getDefaultMappingConfig() {
+    static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/xbox.json";
+    return MAPPING_JSON;
+}
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h
index 38f00f4f15..a9ed18607c 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.h
+++ b/libraries/input-plugins/src/input-plugins/Joystick.h
@@ -23,7 +23,7 @@
 #include <controllers/InputDevice.h>
 #include <controllers/StandardControls.h>
 
-class Joystick : public QObject, public InputDevice {
+class Joystick : public QObject, public controller::InputDevice {
     Q_OBJECT
     Q_PROPERTY(QString name READ getName)
 
@@ -36,16 +36,16 @@ public:
     const QString& getName() const { return _name; }
 
     // Device functions
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+    virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
+    virtual QString getDefaultMappingConfig() override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
     
-    Joystick() : InputDevice("Joystick") {}
+    Joystick() : InputDevice("GamePad") {}
     ~Joystick();
     
 #ifdef HAVE_SDL2
-    Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
+    Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameController);
 #endif
     
     void closeJoystick();
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
index 4703d3ae6a..f5f8b47a90 100755
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
@@ -14,6 +14,8 @@
 #include <QtGui/QMouseEvent>
 #include <QtGui/QTouchEvent>
 
+#include <controllers/UserInputMapper.h>
+#include <PathUtils.h>
 
 const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse";
 
@@ -128,163 +130,153 @@ void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) {
     _lastTouch = currentPos;
 }
 
-UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::Key code) {
-    auto shortCode = (UserInputMapper::uint16)(code & KEYBOARD_MASK);
+controller::Input KeyboardMouseDevice::makeInput(Qt::Key code) {
+    auto shortCode = (uint16_t)(code & KEYBOARD_MASK);
     if (shortCode != code) {
        shortCode |= 0x0800; // add this bit instead of the way Qt::Key add a bit on the 3rd byte for some keys
     }
-    return UserInputMapper::Input(_deviceID, shortCode, UserInputMapper::ChannelType::BUTTON);
+    return controller::Input(_deviceID, shortCode, controller::ChannelType::BUTTON);
 }
 
-UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) {
+controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) {
     switch (code) {
         case Qt::LeftButton:
-            return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_LEFT, UserInputMapper::ChannelType::BUTTON);
+            return controller::Input(_deviceID, MOUSE_BUTTON_LEFT, controller::ChannelType::BUTTON);
         case Qt::RightButton:
-            return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_RIGHT, UserInputMapper::ChannelType::BUTTON);
+            return controller::Input(_deviceID, MOUSE_BUTTON_RIGHT, controller::ChannelType::BUTTON);
         case Qt::MiddleButton:
-            return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_MIDDLE, UserInputMapper::ChannelType::BUTTON);
+            return controller::Input(_deviceID, MOUSE_BUTTON_MIDDLE, controller::ChannelType::BUTTON);
         default:
-            return UserInputMapper::Input();
+            return controller::Input();
     };
 }
 
-UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) {
-    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
+controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) {
+    return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
 }
 
-UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) {
-    return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
+controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) {
+    return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
 }
 
-UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) {
-    return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
+controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) {
+    return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);
 }
 
-void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getFreeDeviceID();
-
-    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
-    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
+void KeyboardMouseDevice::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
+    using namespace controller;
+    proxy->getButton = [this] (const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
+    proxy->getAxis = [this] (const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
+    proxy->getAvailabeInputs = [this] () -> QVector<Input::NamedPair> {
+        QVector<Input::NamedPair> availableInputs;
         for (int i = (int) Qt::Key_0; i <= (int) Qt::Key_9; i++) {
-            availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
+            availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
         }
         for (int i = (int) Qt::Key_A; i <= (int) Qt::Key_Z; i++) {
-            availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
+            availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
         }
         for (int i = (int) Qt::Key_Left; i <= (int) Qt::Key_Down; i++) {
-            availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
+            availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
         }
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_Space), QKeySequence(Qt::Key_Space).toString()));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_Shift), "Shift"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString()));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString()));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Space), QKeySequence(Qt::Key_Space).toString()));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Shift), "Shift"));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString()));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString()));
 
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::LeftButton), "Left Mouse Click"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::MiddleButton), "Middle Mouse Click"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::RightButton), "Right Mouse Click"));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "Left Mouse Click"));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "Middle Mouse Click"));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::RightButton), "Right Mouse Click"));
         
-        availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_X_POS), "Mouse Move Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_X_NEG), "Mouse Move Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_Y_POS), "Mouse Move Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_Y_NEG), "Mouse Move Down"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_POS), "Mouse Move Right"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_NEG), "Mouse Move Left"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_POS), "Mouse Move Up"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_NEG), "Mouse Move Down"));
         
-        availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "Mouse Wheel Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "Mouse Wheel Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "Mouse Wheel Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_X_NEG), "Mouse Wheel Down"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "Mouse Wheel Right"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "Mouse Wheel Left"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "Mouse Wheel Up"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_NEG), "Mouse Wheel Down"));
         
-        availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_X_POS), "Touchpad Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_X_NEG), "Touchpad Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_Y_POS), "Touchpad Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_Y_NEG), "Touchpad Down"));
+        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_POS), "Touchpad Right"));
+        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_NEG), "Touchpad Left"));
+        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_POS), "Touchpad Up"));
+        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_NEG), "Touchpad Down"));
 
         return availableInputs;
     };
-    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
-    mapper.registerDevice(_deviceID, proxy);
 }
 
-void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) {
-    const float BUTTON_MOVE_SPEED = 1.0f;
-    const float BUTTON_YAW_SPEED = 0.75f;
-    const float BUTTON_PITCH_SPEED = 0.5f;
-    const float MOUSE_YAW_SPEED = 0.5f;
-    const float MOUSE_PITCH_SPEED = 0.25f;
-    const float TOUCH_YAW_SPEED = 0.5f;
-    const float TOUCH_PITCH_SPEED = 0.25f;
-    const float BUTTON_BOOM_SPEED = 0.1f;
- 
-    // AWSD keys mapping
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_S), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_W), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_A), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_D), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_C), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_E), BUTTON_MOVE_SPEED);
-
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
-
-    // Arrow keys mapping
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED);
-
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
-
-    // Mouse move
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
-
-    
-#ifdef Q_OS_MAC
-    // wheel event modifier on Mac collide with the touchpad scroll event
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
-#else
-    // Touch pad yaw pitch
-    mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
-    
-    // Wheel move
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED);
-
-#endif
-    
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(Qt::Key_Space));
-    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(Qt::Key_R));
-    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(Qt::Key_T));
+QString KeyboardMouseDevice::getDefaultMappingConfig() {
+    static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/keyboardMouse.json";
+    return MAPPING_JSON;
 }
 
+//void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) {
+//    const float BUTTON_MOVE_SPEED = 1.0f;
+//    const float BUTTON_YAW_SPEED = 0.75f;
+//    const float BUTTON_PITCH_SPEED = 0.5f;
+//    const float MOUSE_YAW_SPEED = 0.5f;
+//    const float MOUSE_PITCH_SPEED = 0.25f;
+//    const float TOUCH_YAW_SPEED = 0.5f;
+//    const float TOUCH_PITCH_SPEED = 0.25f;
+//    const float BUTTON_BOOM_SPEED = 0.1f;
+// 
+//    // AWSD keys mapping
+//
+//    mapper.addInputChannel(controller::BOOM_IN, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
+//    mapper.addInputChannel(controller::BOOM_OUT, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
+//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
+//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
+//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
+//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
+//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
+//    mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
+//
+//    // Arrow keys mapping
+//    mapper.addInputChannel(controller::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED);
+//    mapper.addInputChannel(controller::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED);
+//    mapper.addInputChannel(controller::YAW_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED);
+//    mapper.addInputChannel(controller::YAW_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED);
+//    mapper.addInputChannel(controller::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED);
+//    mapper.addInputChannel(controller::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED);
+//
+//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
+//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
+//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
+//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
+//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
+//    mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
+//
+//    // Mouse move
+//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
+//    mapper.addInputChannel(controller::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
+//    mapper.addInputChannel(controller::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
+//    mapper.addInputChannel(controller::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
+//
+//    
+//#ifdef Q_OS_MAC
+//    // wheel event modifier on Mac collide with the touchpad scroll event
+//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
+//    mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
+//    mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
+//    mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
+//#else
+//    // Touch pad yaw pitch
+//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
+//    mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
+//    mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
+//    mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
+//    
+//    // Wheel move
+//    mapper.addInputChannel(controller::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED);
+//    mapper.addInputChannel(controller::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED);
+//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED);
+//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED);
+//
+//#endif
+//    
+//    mapper.addInputChannel(controller::SHIFT, makeInput(Qt::Key_Space));
+//    mapper.addInputChannel(controller::ACTION1, makeInput(Qt::Key_R));
+//    mapper.addInputChannel(controller::ACTION2, makeInput(Qt::Key_T));
+//}
+
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
index 3c935cab26..f89d877dcd 100644
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
@@ -24,7 +24,7 @@ class QKeyEvent;
 class QMouseEvent;
 class QWheelEvent;
 
-class KeyboardMouseDevice : public InputPlugin, public InputDevice {
+class KeyboardMouseDevice : public InputPlugin, public controller::InputDevice {
     Q_OBJECT
 public:
     enum KeyboardChannel {
@@ -72,8 +72,8 @@ public:
     virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
 
     // Device functions
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+    virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
+    virtual QString getDefaultMappingConfig() override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
  
@@ -91,11 +91,11 @@ public:
     void wheelEvent(QWheelEvent* event);
     
     // Let's make it easy for Qt because we assume we love Qt forever
-    UserInputMapper::Input makeInput(Qt::Key code);
-    UserInputMapper::Input makeInput(Qt::MouseButton code);
-    UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis);
-    UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis);
-    UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button);
+    controller::Input makeInput(Qt::Key code);
+    controller::Input makeInput(Qt::MouseButton code);
+    controller::Input makeInput(MouseAxisChannel axis);
+    controller::Input makeInput(TouchAxisChannel axis);
+    controller::Input makeInput(TouchButtonChannel button);
 
     static const QString NAME;
 
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
index 28874efdb0..b052162c77 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
@@ -14,6 +14,7 @@
 #include <HFActionEvent.h>
 #include <HFBackEvent.h>
 #include <PerfStat.h>
+#include <controllers/UserInputMapper.h>
 
 #include "SDL2Manager.h"
 
@@ -47,11 +48,11 @@ void SDL2Manager::init() {
             if (controller) {
                 SDL_JoystickID id = getInstanceId(controller);
                 if (!_openJoysticks.contains(id)) {
-                    Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
+                    //Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
+                    Joystick* joystick = new Joystick(id, controller);
                     _openJoysticks[id] = joystick;
-                    auto userInputMapper = DependencyManager::get<UserInputMapper>();
-                    joystick->registerToUserInputMapper(*userInputMapper);
-                    joystick->assignDefaultInputMapping(*userInputMapper);
+                    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+                    userInputMapper->registerDevice(joystick);
                     emit joystickAdded(joystick);
                 }
             }
@@ -92,7 +93,7 @@ void SDL2Manager::pluginFocusOutEvent() {
 void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) {
 #ifdef HAVE_SDL2
     if (_isInitialized) {
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
         for (auto joystick : _openJoysticks) {
             joystick->update(deltaTime, jointsCaptured);
         }
@@ -124,13 +125,11 @@ void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) {
                 
             } else if (event.type == SDL_CONTROLLERDEVICEADDED) {
                 SDL_GameController* controller = SDL_GameControllerOpen(event.cdevice.which);
-                
                 SDL_JoystickID id = getInstanceId(controller);
                 if (!_openJoysticks.contains(id)) {
-                    Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
-                    _openJoysticks[id] = joystick;
-                    joystick->registerToUserInputMapper(*userInputMapper);
-                    joystick->assignDefaultInputMapping(*userInputMapper);
+                    // Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
+                    Joystick* joystick = new Joystick(id, controller);
+                    userInputMapper->registerDevice(joystick);
                     emit joystickAdded(joystick);
                 }
             } else if (event.type == SDL_CONTROLLERDEVICEREMOVED) {
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index b304f260b3..eab3c03740 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -18,10 +18,13 @@
 #include <PerfStat.h>
 #include <SettingHandle.h>
 #include <plugins/PluginContainer.h>
+#include <PathUtils.h>
+#include <NumericalConstants.h>
+#include <UserActivityLogger.h>
+#include <controllers/UserInputMapper.h>
 
-#include "NumericalConstants.h"
 #include "SixenseManager.h"
-#include "UserActivityLogger.h"
+
 
 #ifdef HAVE_SIXENSE
     #include "sixense.h"
@@ -119,8 +122,8 @@ void SixenseManager::activate() {
     loadSettings();
     sixenseInit();
     _activated = true;
-    auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    registerToUserInputMapper(*userInputMapper);
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+    userInputMapper->registerDevice(this);
 #endif
 }
 
@@ -171,7 +174,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
     (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");
 #endif
 
-    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
 
     if (sixenseGetNumActiveControllers() == 0) {
         _poseStateMap.clear();
@@ -232,7 +235,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
                 _poseStateMap.clear();
             }
         } else {
-            _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = UserInputMapper::PoseValue();
+            _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = controller::Pose();
         }
     }
 
@@ -440,8 +443,7 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, boo
     // TODO: find a shortcut with fewer rotations.
     rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand;
 
-    _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = 
-        UserInputMapper::PoseValue(position, rotation);
+    _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = controller::Pose(position, rotation);
 #endif // HAVE_SIXENSE
 }
 
@@ -456,85 +458,91 @@ static const auto R2 = controller::A;
 static const auto R3 = controller::B;
 static const auto R4 = controller::Y;
 
-void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getFreeDeviceID();
-    auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
-    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getPose = [this](const UserInputMapper::Input& input, int timestamp) -> UserInputMapper::PoseValue { return this->getPose(input.getChannel()); };
-    using namespace controller;
-    proxy->getAvailabeInputs = [this]() -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
-        availableInputs.append(UserInputMapper::InputPair(makeInput(L0), "L0"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(L1), "L1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(L2), "L2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(L3), "L3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(L4), "L4"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LB), "LB"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LS), "LS"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LX), "LX"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LY), "LY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LT), "LT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(R0), "R0"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(R1), "R1"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(R2), "R2"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(R3), "R3"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(R4), "R4"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RB), "RB"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RS), "RS"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RX), "RX"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RY), "RY"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RT), "RT"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT), "LeftPose"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT), "RightPose"));
+using namespace controller;
+
+void SixenseManager::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
+    proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
+    proxy->getAxis = [this](const Input& input, int timestamp) -> float { 
+        return this->getAxis(input.getChannel()); 
+    };
+    proxy->getPose = [this](const Input& input, int timestamp) -> Pose { return this->getPose(input.getChannel()); };
+    proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
+        QVector<Input::NamedPair> availableInputs;
+        availableInputs.append(Input::NamedPair(makeInput(L0), "L0"));
+        availableInputs.append(Input::NamedPair(makeInput(L1), "L1"));
+        availableInputs.append(Input::NamedPair(makeInput(L2), "L2"));
+        availableInputs.append(Input::NamedPair(makeInput(L3), "L3"));
+        availableInputs.append(Input::NamedPair(makeInput(L4), "L4"));
+        availableInputs.append(Input::NamedPair(makeInput(LB), "LB"));
+        availableInputs.append(Input::NamedPair(makeInput(LS), "LS"));
+        availableInputs.append(Input::NamedPair(makeInput(LX), "LX"));
+        availableInputs.append(Input::NamedPair(makeInput(LY), "LY"));
+        availableInputs.append(Input::NamedPair(makeInput(LT), "LT"));
+        availableInputs.append(Input::NamedPair(makeInput(R0), "R0"));
+        availableInputs.append(Input::NamedPair(makeInput(R1), "R1"));
+        availableInputs.append(Input::NamedPair(makeInput(R2), "R2"));
+        availableInputs.append(Input::NamedPair(makeInput(R3), "R3"));
+        availableInputs.append(Input::NamedPair(makeInput(R4), "R4"));
+        availableInputs.append(Input::NamedPair(makeInput(RB), "RB"));
+        availableInputs.append(Input::NamedPair(makeInput(RS), "RS"));
+        availableInputs.append(Input::NamedPair(makeInput(RX), "RX"));
+        availableInputs.append(Input::NamedPair(makeInput(RY), "RY"));
+        availableInputs.append(Input::NamedPair(makeInput(RT), "RT"));
+        availableInputs.append(Input::NamedPair(makeInput(LEFT), "LeftPose"));
+        availableInputs.append(Input::NamedPair(makeInput(RIGHT), "RightPose"));
         return availableInputs;
     };
-    mapper.registerDevice(_deviceID, proxy);
 }
 
-void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    const float JOYSTICK_YAW_SPEED = 0.5f;
-    const float JOYSTICK_PITCH_SPEED = 0.25f;
-    const float BUTTON_MOVE_SPEED = 1.0f;
-    const float BOOM_SPEED = 0.1f;
-    using namespace controller;
-
-    // Left Joystick: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(LY), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(LX), JOYSTICK_MOVE_SPEED);
-
-    // Right Joystick: Camera orientation
-    mapper.addInputChannel(UserInputMapper::YAW, makeInput(RX), JOYSTICK_YAW_SPEED);
-    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(RY), JOYSTICK_PITCH_SPEED);
-
-    // Buttons
-    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(L3), BOOM_SPEED);
-    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(L1), BOOM_SPEED);
-
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(R3), BUTTON_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(R1), BUTTON_MOVE_SPEED);
-
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(L2));
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(R2));
-
-    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(L4));
-    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(R4));
-
-    // FIXME
-//    mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
-//    mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
-
-    mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(LT));
-    mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(RT));
-
-    // TODO find a mechanism to allow users to navigate the context menu via
-    mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(L0));
-    mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(R0));
 
+QString SixenseManager::getDefaultMappingConfig() {
+    static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/hydra.json";
+    return MAPPING_JSON;
 }
 
+//
+//void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
+//    const float JOYSTICK_MOVE_SPEED = 1.0f;
+//    const float JOYSTICK_YAW_SPEED = 0.5f;
+//    const float JOYSTICK_PITCH_SPEED = 0.25f;
+//    const float BUTTON_MOVE_SPEED = 1.0f;
+//    const float BOOM_SPEED = 0.1f;
+//    using namespace controller;
+//
+//    // Left Joystick: Movement, strafing
+//    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(LY), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(LX), JOYSTICK_MOVE_SPEED);
+//
+//    // Right Joystick: Camera orientation
+//    mapper.addInputChannel(UserInputMapper::YAW, makeInput(RX), JOYSTICK_YAW_SPEED);
+//    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(RY), JOYSTICK_PITCH_SPEED);
+//
+//    // Buttons
+//    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(L3), BOOM_SPEED);
+//    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(L1), BOOM_SPEED);
+//
+//    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(R3), BUTTON_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(R1), BUTTON_MOVE_SPEED);
+//
+//    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(L2));
+//    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(R2));
+//
+//    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(L4));
+//    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(R4));
+//
+//    // FIXME
+////    mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
+////    mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
+//
+//    mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(LT));
+//    mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(RT));
+//
+//    // TODO find a mechanism to allow users to navigate the context menu via
+//    mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(L0));
+//    mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(R0));
+//
+//}
+
 // virtual
 void SixenseManager::saveSettings() const {
     Settings settings;
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index 897ca72940..91cdb5f60e 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -42,7 +42,7 @@ const unsigned int BUTTON_TRIGGER = 1U << 8;
 const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
 
 // Handles interaction with the Sixense SDK (e.g., Razer Hydra).
-class SixenseManager : public InputPlugin, public InputDevice {
+class SixenseManager : public InputPlugin, public controller::InputDevice {
     Q_OBJECT
 public:
     SixenseManager();
@@ -60,8 +60,8 @@ public:
     virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
 
     // Device functions
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+    virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
+    virtual QString getDefaultMappingConfig() override;
 
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index a3374cc1c0..1c8d8c2add 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -12,15 +12,19 @@
 #include "ViveControllerManager.h"
 
 #include <PerfStat.h>
-
-#include "GeometryCache.h"
+#include <PathUtils.h>
+#include <GeometryCache.h>
 #include <gpu/Batch.h>
 #include <gpu/Context.h>
 #include <DeferredLightingEffect.h>
 #include <display-plugins/openvr/OpenVrHelpers.h>
-#include "NumericalConstants.h"
+#include <NumericalConstants.h>
 #include <plugins/PluginContainer.h>
-#include "UserActivityLogger.h"
+#include <UserActivityLogger.h>
+
+#include <controllers/UserInputMapper.h>
+
+#include <controllers/StandardControls.h>
 
 #ifdef Q_OS_WIN
 extern vr::IVRSystem* _hmd;
@@ -29,18 +33,6 @@ extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]
 extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
 #endif
 
-const unsigned int LEFT_MASK = 0U;
-const unsigned int RIGHT_MASK = 1U;
-
-const uint64_t VR_BUTTON_A = 1U << 1;
-const uint64_t VR_GRIP_BUTTON = 1U << 2;
-const uint64_t VR_TRACKPAD_BUTTON = 1ULL << 32;
-const uint64_t VR_TRIGGER_BUTTON = 1ULL << 33;
-
-const unsigned int BUTTON_A = 1U << 1;
-const unsigned int GRIP_BUTTON = 1U << 2;
-const unsigned int TRACKPAD_BUTTON = 1U << 3;
-const unsigned int TRIGGER_BUTTON = 1U << 4;
 
 const float CONTROLLER_LENGTH_OFFSET = 0.0762f;  // three inches
 const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
@@ -173,8 +165,8 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint
         //pendingChanges.updateItem(_leftHandRenderID, );
 
 
-        UserInputMapper::PoseValue leftHand = _poseStateMap[makeInput(JointChannel::LEFT_HAND).getChannel()];
-        UserInputMapper::PoseValue rightHand = _poseStateMap[makeInput(JointChannel::RIGHT_HAND).getChannel()];
+        controller::Pose leftHand = _poseStateMap[controller::StandardPoseChannel::LEFT];
+        controller::Pose rightHand = _poseStateMap[controller::StandardPoseChannel::RIGHT];
 
         gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
             auto geometryCache = DependencyManager::get<GeometryCache>();
@@ -186,21 +178,20 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint
             //batch._glBindTexture(GL_TEXTURE_2D, _uexture);
 
             if (leftHand.isValid()) {
-                renderHand(leftHand, batch, LEFT_HAND);
+                renderHand(leftHand, batch, 1);
             }
             if (rightHand.isValid()) {
-                renderHand(rightHand, batch, RIGHT_HAND);
+                renderHand(rightHand, batch, -1);
             }
         });
     }
 }
 
-void ViveControllerManager::renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index) {
-    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign) {
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
     Transform transform(userInputMapper->getSensorToWorldMat());
     transform.postTranslate(pose.getTranslation() + pose.getRotation() * glm::vec3(0, 0, CONTROLLER_LENGTH_OFFSET));
 
-    int sign = index == LEFT_HAND ? 1 : -1;
     glm::quat rotation = pose.getRotation() * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(sign * PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f));
     transform.postRotate(rotation);
 
@@ -251,6 +242,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
         }
             
         numTrackedControllers++;
+        bool left = numTrackedControllers == 1;
             
         const mat4& mat = _trackedDevicePoseMat4[device];
                   
@@ -264,14 +256,18 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
             //qDebug() << (numTrackedControllers == 1 ? "Left: " : "Right: ");
             //qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y;
             //qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y;
-            handleButtonEvent(controllerState.ulButtonPressed, numTrackedControllers - 1);
-            for (int i = 0; i < vr::k_unControllerStateAxisCount; i++) {
-                handleAxisEvent(Axis(i), controllerState.rAxis[i].x, controllerState.rAxis[i].y, numTrackedControllers - 1);
+            for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) {
+                auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i);
+                bool pressed = 0 != (controllerState.ulButtonPressed & mask);
+                handleButtonEvent(i, pressed, left);
+            }
+            for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) {
+                handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left);
             }
         }
     }
         
-    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
         
     if (numTrackedControllers == 0) {
         if (_deviceID != 0) {
@@ -282,8 +278,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
     }
         
     if (_trackedControllers == 0 && numTrackedControllers > 0) {
-        registerToUserInputMapper(*userInputMapper);
-        assignDefaultInputMapping(*userInputMapper);
+        userInputMapper->registerDevice(this);
         UserActivityLogger::getInstance().connectedDevice("spatial_controller", "steamVR");
     }
         
@@ -296,33 +291,41 @@ void ViveControllerManager::focusOutEvent() {
     _buttonPressedMap.clear();
 };
 
-void ViveControllerManager::handleAxisEvent(Axis axis, float x, float y, int index) {
-    if (axis == TRACKPAD_AXIS) {
-        _axisStateMap[makeInput(AXIS_Y_POS, index).getChannel()] = (y > 0.0f) ? y : 0.0f;
-        _axisStateMap[makeInput(AXIS_Y_NEG, index).getChannel()] = (y < 0.0f) ? -y : 0.0f;
-        _axisStateMap[makeInput(AXIS_X_POS, index).getChannel()] = (x > 0.0f) ? x : 0.0f;
-        _axisStateMap[makeInput(AXIS_X_NEG, index).getChannel()] = (x < 0.0f) ? -x : 0.0f;
-    } else if (axis == TRIGGER_AXIS) {
-        _axisStateMap[makeInput(BACK_TRIGGER, index).getChannel()] = x;
+// These functions do translation from the Steam IDs to the standard controller IDs
+void ViveControllerManager::handleAxisEvent(uint32_t axis, float x, float y, bool left) {
+#ifdef Q_OS_WIN
+    using namespace controller;
+    if (axis == vr::k_EButton_SteamVR_Touchpad) {
+        _axisStateMap[left ? LX : RX] = x;
+        _axisStateMap[left ? LY : RY] = y;
+    } else if (axis == vr::k_EButton_SteamVR_Trigger) {
+        _axisStateMap[left ? LT : RT] = x;
     }
+#endif
 }
 
-void ViveControllerManager::handleButtonEvent(uint64_t buttons, int index) {
-    if (buttons & VR_BUTTON_A) {
-        _buttonPressedMap.insert(makeInput(BUTTON_A, index).getChannel());
+// These functions do translation from the Steam IDs to the standard controller IDs
+void ViveControllerManager::handleButtonEvent(uint32_t button, bool pressed, bool left) {
+#ifdef Q_OS_WIN
+    if (!pressed) {
+        return;
     }
-    if (buttons & VR_GRIP_BUTTON) {
-        _buttonPressedMap.insert(makeInput(GRIP_BUTTON, index).getChannel());
-    }
-    if (buttons & VR_TRACKPAD_BUTTON) {
-        _buttonPressedMap.insert(makeInput(TRACKPAD_BUTTON, index).getChannel());
-    }
-    if (buttons & VR_TRIGGER_BUTTON) {
-        _buttonPressedMap.insert(makeInput(TRIGGER_BUTTON, index).getChannel());
+
+    if (button == vr::k_EButton_ApplicationMenu) {
+        // FIXME?
+        _buttonPressedMap.insert(left ? controller::A : controller::A);
+    } else if (button == vr::k_EButton_Grip) {
+        // Tony says these are harder to reach, so make them the meta buttons
+        _buttonPressedMap.insert(left ? controller::BACK : controller::START);
+    } else if (button == vr::k_EButton_SteamVR_Trigger) {
+        _buttonPressedMap.insert(left ? controller::LB : controller::RB);
+    } else if (button == vr::k_EButton_SteamVR_Touchpad) {
+        _buttonPressedMap.insert(left ? controller::LS : controller::RS);
     }
+#endif
 }
 
-void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) {
+void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) {
     glm::vec3 position = extractTranslation(mat);
     glm::quat rotation = glm::quat_cast(mat);
 
@@ -378,7 +381,7 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) {
    
     const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f));
     const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
-    float sign = (index == LEFT_HAND) ? -1.0f : 1.0f;
+    float sign = left ? -1.0f : 1.0f;
     const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); 
     const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f));
     const glm::quat offset = glm::inverse(signedQuaterZ * eighthX);
@@ -386,92 +389,93 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) {
 
     position += rotation * glm::vec3(0, 0, -CONTROLLER_LENGTH_OFFSET);
 
-    _poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation);
+    _poseStateMap[left ? controller::LEFT : controller::RIGHT] = controller::Pose(position, rotation);
 }
 
-void ViveControllerManager::registerToUserInputMapper(UserInputMapper& mapper) {
-    // Grab the current free device ID
-    _deviceID = mapper.getFreeDeviceID();
-    
-    auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy(_name));
-    proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getPose = [this](const UserInputMapper::Input& input, int timestamp) -> UserInputMapper::PoseValue { return this->getPose(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
-        QVector<UserInputMapper::InputPair> availableInputs;
-        availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_HAND), "Left Hand"));
-        
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_A, 0), "Left Button A"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(TRIGGER_BUTTON, 0), "Left Trigger Button"));
+void ViveControllerManager::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
+    using namespace controller;
+    proxy->_name = _name;
+    proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
+    proxy->getAxis = [this](const Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
+    proxy->getPose = [this](const Input& input, int timestamp) -> Pose { return this->getPose(input.getChannel()); };
+    proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
+        QVector<Input::NamedPair> availableInputs{
+            // Trackpad analogs
+            makePair(LX, "LX"),
+            makePair(LY, "LY"),
+            makePair(RX, "RX"),
+            makePair(RY, "RY"),
+            // trigger analogs
+            makePair(LT, "LT"),
+            makePair(RT, "RT"),
 
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 0), "Left Trackpad Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 0), "Left Trackpad Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 0), "Left Trackpad Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 0), "Left Trackpad Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 0), "Left Back Trigger"));
+            makePair(LB, "LB"),
+            makePair(RB, "RB"),
 
-        
-        availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_HAND), "Right Hand"));
+            makePair(LS, "LS"),
+            makePair(RS, "RS"),
+        };
 
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_A, 1), "Right Button A"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(GRIP_BUTTON, 1), "Right Grip Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(TRACKPAD_BUTTON, 1), "Right Trackpad Button"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(TRIGGER_BUTTON, 1), "Right Trigger Button"));
+        //availableInputs.append(Input::NamedPair(makeInput(LEFT_HAND), "Left Hand"));
+
+        //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 0), "Left Button A"));
+        //availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button"));
+        //availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button"));
+        //availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 0), "Left Trigger Button"));
+
+        //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_POS, 0), "Left Trackpad Up"));
+        //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_NEG, 0), "Left Trackpad Down"));
+        //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_POS, 0), "Left Trackpad Right"));
+        //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_NEG, 0), "Left Trackpad Left"));
+        //availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 0), "Left Back Trigger"));
+
+
+        //availableInputs.append(Input::NamedPair(makeInput(RIGHT_HAND), "Right Hand"));
+
+        //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 1), "Right Button A"));
+        //availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 1), "Right Grip Button"));
+        //availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 1), "Right Trackpad Button"));
+        //availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 1), "Right Trigger Button"));
+
+        //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_POS, 1), "Right Trackpad Up"));
+        //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_NEG, 1), "Right Trackpad Down"));
+        //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_POS, 1), "Right Trackpad Right"));
+        //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_NEG, 1), "Right Trackpad Left"));
+        //availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 1), "Right Back Trigger"));
 
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 1), "Right Trackpad Up"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 1), "Right Trackpad Down"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 1), "Right Trackpad Right"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 1), "Right Trackpad Left"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 1), "Right Back Trigger"));
-        
         return availableInputs;
     };
-    proxy->resetDeviceBindings = [this, &mapper] () -> bool {
-        mapper.removeAllInputChannelsForDevice(_deviceID);
-        this->assignDefaultInputMapping(mapper);
-        return true;
-    };
-    mapper.registerDevice(_deviceID, proxy);
 }
 
-void ViveControllerManager::assignDefaultInputMapping(UserInputMapper& mapper) {
-    const float JOYSTICK_MOVE_SPEED = 1.0f;
-    
-    // Left Trackpad: Movement, strafing
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(AXIS_X_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(AXIS_X_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
-
-    // Right Trackpad: Vertical movement, zooming
-    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(AXIS_Y_POS, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
-    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(AXIS_Y_NEG, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
-    
-    // Buttons
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 0));
-    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 1));
-    
-    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(GRIP_BUTTON, 0));
-    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(GRIP_BUTTON, 1));
-
-    mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0));
-    mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1));
-    
-    // Hands
-    mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
-    mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
+QString ViveControllerManager::getDefaultMappingConfig() {
+    static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
+    return MAPPING_JSON;
 }
 
-UserInputMapper::Input ViveControllerManager::makeInput(unsigned int button, int index) {
-    return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON);
-}
-
-UserInputMapper::Input ViveControllerManager::makeInput(ViveControllerManager::JoystickAxisChannel axis, int index) {
-    return UserInputMapper::Input(_deviceID, axis | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::AXIS);
-}
-
-UserInputMapper::Input ViveControllerManager::makeInput(JointChannel joint) {
-    return UserInputMapper::Input(_deviceID, joint, UserInputMapper::ChannelType::POSE);
-}
+//void ViveControllerManager::assignDefaultInputMapping(UserInputMapper& mapper) {
+//    const float JOYSTICK_MOVE_SPEED = 1.0f;
+//    
+//    // Left Trackpad: Movement, strafing
+//    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(AXIS_X_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(AXIS_X_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
+//
+//    // Right Trackpad: Vertical movement, zooming
+//    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(AXIS_Y_POS, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
+//    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(AXIS_Y_NEG, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
+//    
+//    // Buttons
+//    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 0));
+//    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 1));
+//    
+//    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(GRIP_BUTTON, 0));
+//    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(GRIP_BUTTON, 1));
+//
+//    mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0));
+//    mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1));
+//    
+//    // Hands
+//    mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
+//    mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
+//}
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
index bcc27d07ae..67ad75c9e8 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
@@ -24,30 +24,9 @@
 #include <RenderArgs.h>
 #include <render/Scene.h>
 
-class ViveControllerManager : public InputPlugin, public InputDevice {
+class ViveControllerManager : public InputPlugin, public controller::InputDevice {
     Q_OBJECT
 public:
-    enum JoystickAxisChannel {
-        AXIS_Y_POS = 1U << 1,
-        AXIS_Y_NEG = 1U << 2,
-        AXIS_X_POS = 1U << 3,
-        AXIS_X_NEG = 1U << 4,
-        BACK_TRIGGER = 1U << 5,
-    };
-
-    enum Axis {
-        TRACKPAD_AXIS = 0,
-        TRIGGER_AXIS,
-        AXIS_2,
-        AXIS_3,
-        AXIS_4,
-    };
-
-    enum JointChannel {
-        LEFT_HAND = 0,
-        RIGHT_HAND,
-    };
-
     ViveControllerManager();
 
     // Plugin functions
@@ -62,8 +41,8 @@ public:
     virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
 
     // Device functions
-    virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
-    virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
+    virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
+    virtual QString getDefaultMappingConfig() override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
@@ -71,16 +50,12 @@ public:
 
     void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; }
     
-    UserInputMapper::Input makeInput(unsigned int button, int index);
-    UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index);
-    UserInputMapper::Input makeInput(JointChannel joint);
-    
 private:
-    void renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index);
+    void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
     
-    void handleButtonEvent(uint64_t buttons, int index);
-    void handleAxisEvent(Axis axis, float x, float y, int index);
-    void handlePoseEvent(const mat4& mat, int index);
+    void handleButtonEvent(uint32_t button, bool pressed, bool left);
+    void handleAxisEvent(uint32_t axis, float x, float y, bool left);
+    void handlePoseEvent(const mat4& mat, bool left);
     
     int _trackedControllers;
 
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index dc08fd7a69..40de50b153 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -28,7 +28,9 @@
 #include <udt/PacketHeaders.h>
 #include <UUID.h>
 
-#include "AnimationObject.h"
+#include <controllers/ScriptingInterface.h>
+#include <AnimationObject.h>
+
 #include "ArrayBufferViewClass.h"
 #include "BatchLoader.h"
 #include "DataViewClass.h"
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index 5a0fb64ae2..9cf1bf1e18 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -26,8 +26,6 @@
 #include <LimitedNodeList.h>
 #include <EntityItemID.h>
 #include <EntitiesScriptEngineProvider.h>
-#include <controllers/ScriptingInterface.h>
-
 
 #include "MouseEvent.h"
 #include "ArrayBufferClass.h"
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index eb080700fa..bc0ad179ef 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -123,20 +123,20 @@ int main(int argc, char** argv) {
             inputPlugin->pluginUpdate(delta, false);
         }
 
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
         userInputMapper->update(delta);
     });
     timer.start(50);
 
     {
-        DependencyManager::set<UserInputMapper>();
+        DependencyManager::set<controller::UserInputMapper>();
         foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
             QString name = inputPlugin->getName();
             inputPlugin->activate();
-            auto userInputMapper = DependencyManager::get<UserInputMapper>();
+            auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
             if (name == KeyboardMouseDevice::NAME) {
                 auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
-                keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
+                userInputMapper->registerDevice(keyboardMouseDevice);
             }
             inputPlugin->pluginUpdate(0, false);
         }

From 22139931f252966396538fb75ef2bd091c89470b Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Tue, 20 Oct 2015 10:35:53 -0700
Subject: [PATCH 071/301] Warning fixes

---
 .../src/controllers/ScriptingInterface.cpp           |  1 -
 .../src/controllers/StandardController.cpp           |  2 --
 .../controllers/src/controllers/UserInputMapper.cpp  | 12 ++++++------
 3 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 0f9b5678ca..b10c4a83b0 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -54,7 +54,6 @@ controller::ScriptingInterface::ScriptingInterface() {
 
     // FIXME allow custom user actions?
     auto actionNames = userInputMapper->getActionNames();
-    int actionNumber = 0;
     qCDebug(controllers) << "Setting up standard actions";
     for (const auto& namedInput : userInputMapper->getActionInputs()) {
         const QString& actionName = namedInput.second;
diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index f5389d1518..304f1e87aa 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -18,8 +18,6 @@
 
 namespace controller {
 
-const float CONTROLLER_THRESHOLD = 0.3f;
-
 StandardController::StandardController() : InputDevice("Standard") { 
     _deviceID = UserInputMapper::STANDARD_DEVICE; 
 }
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 7b009273a1..0c3a43bd34 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -470,7 +470,11 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
     return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
 }
 
-
+enum Pass {
+    HARDWARE_PASS,
+    STANDARD_PASS,
+    NUM_PASSES
+};
 
 void UserInputMapper::update() {
     static auto deviceNames = getDeviceNames();
@@ -479,12 +483,9 @@ void UserInputMapper::update() {
     EndpointSet readEndpoints;
     EndpointSet writtenEndpoints;
 
-    static const int HARDWARE_PASS = 0;
-    static const int STANDARD_PASS = 1;
-
     // Now process the current values for each level of the stack
     for (auto& mapping : _activeMappings) {
-        for (int pass = 0; pass < 2; ++pass) {
+        for (int pass = HARDWARE_PASS; pass < NUM_PASSES; ++pass) {
             for (const auto& mappingEntry : mapping->channelMappings) {
                 const auto& source = mappingEntry.first;
                 if (_inputsByEndpoint.count(source)) {
@@ -534,7 +535,6 @@ void UserInputMapper::update() {
                     float value = getValue(source);
 
                     // Apply each of the filters.
-                    const auto& filters = route->filters;
                     for (const auto& filter : route->filters) {
                         value = filter->apply(value);
                     }

From eacd6af03232c15e5fc5220d046700eb52427fa3 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Tue, 20 Oct 2015 14:14:13 -0700
Subject: [PATCH 072/301] Get conditional routes working

---
 .../resources/controllers/keyboardMouse.json  |  11 +-
 .../src/controllers/Conditional.cpp           |  31 +++
 .../controllers/src/controllers/Conditional.h |  63 +++++++
 .../controllers/src/controllers/Filter.cpp    |  24 ++-
 .../controllers/src/controllers/Filter.h      |  85 ++-------
 .../controllers/src/controllers/Mapping.h     |   6 +-
 libraries/controllers/src/controllers/Route.h |   4 +-
 .../src/controllers/UserInputMapper.cpp       | 178 +++++++++++-------
 .../src/controllers/UserInputMapper.h         |   1 +
 .../controllers/impl/RouteBuilderProxy.cpp    |   2 +-
 .../src/input-plugins/KeyboardMouseDevice.cpp |  30 +--
 libraries/shared/src/shared/Factory.h         |  51 +++++
 12 files changed, 310 insertions(+), 176 deletions(-)
 create mode 100644 libraries/controllers/src/controllers/Conditional.cpp
 create mode 100644 libraries/controllers/src/controllers/Conditional.h
 create mode 100644 libraries/shared/src/shared/Factory.h

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
index 71450a0c48..7b9a8d733a 100644
--- a/interface/resources/controllers/keyboardMouse.json
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -1,22 +1,25 @@
 {
     "name": "Keyboard/Mouse to Actions",
     "channels": [
-        { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
-        { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" }, 
-        { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" }, 
-        { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" }, 
         { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, 
         { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, 
         { "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" }, 
         { "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" }, 
+
+        { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
+        { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" }, 
+        { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" }, 
+        { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" }, 
         { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
         { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
+
         { "from": "Keyboard.Up", "to": "Actions.LONGITUDINAL_FORWARD" },
         { "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" }, 
         { "from": "Keyboard.Left", "to": "Actions.YAW_LEFT" }, 
         { "from": "Keyboard.Right", "to": "Actions.YAW_RIGHT" }, 
         { "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
         { "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },
+
         { "from": "Keyboard.MouseMoveLeft", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_LEFT" }, 
         { "from": "Keyboard.MouseMoveRight", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_RIGHT" }, 
         { "from": "Keyboard.MouseMoveUp", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_UP" },
diff --git a/libraries/controllers/src/controllers/Conditional.cpp b/libraries/controllers/src/controllers/Conditional.cpp
new file mode 100644
index 0000000000..7173c80b76
--- /dev/null
+++ b/libraries/controllers/src/controllers/Conditional.cpp
@@ -0,0 +1,31 @@
+//
+//  Created by Bradley Austin Davis 2015/10/20
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Conditional.h"
+
+#include <QtCore/QJsonValue>
+
+#include "Endpoint.h"
+
+namespace controller {
+
+    Conditional::Pointer Conditional::parse(const QJsonValue& json) {
+        return Conditional::Pointer();
+    }
+
+    bool EndpointConditional::satisfied() { 
+        if (!_endpoint) {
+            return false;
+        }
+        auto value = _endpoint->value();
+        if (value == 0.0f) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/libraries/controllers/src/controllers/Conditional.h b/libraries/controllers/src/controllers/Conditional.h
new file mode 100644
index 0000000000..d0226d5775
--- /dev/null
+++ b/libraries/controllers/src/controllers/Conditional.h
@@ -0,0 +1,63 @@
+//
+//  Created by Bradley Austin Davis 2015/10/20
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Conditional_h
+#define hifi_Controllers_Conditional_h
+
+#include <list>
+#include <memory>
+
+#include <QtCore/QString>
+
+#include <shared/Factory.h>
+
+#include "Endpoint.h"
+
+class QJsonValue;
+
+namespace controller {
+    /*
+    * encapsulates a source, destination and filters to apply
+    */
+    class Conditional {
+    public:
+        using Pointer = std::shared_ptr<Conditional>;
+        using List = std::list<Pointer>;
+        using Factory = hifi::SimpleFactory<Conditional, QString>;
+
+        virtual bool satisfied() = 0;
+        virtual bool parseParameters(const QJsonValue& parameters) { return true; }
+
+        static Pointer parse(const QJsonValue& json);
+        static void registerBuilder(const QString& name, Factory::Builder builder);
+        static Factory& getFactory() { return _factory; }
+    protected:
+        static Factory _factory;
+    };
+
+    class EndpointConditional : public Conditional {
+    public:
+        EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) { }
+        virtual bool satisfied() override;
+    private:
+        Endpoint::Pointer _endpoint;
+    };
+
+}
+
+#define REGISTER_CONDITIONAL_CLASS(classEntry) \
+    private: \
+    using Registrar = Conditional::Factory::Registrar<classEntry>; \
+    static Registrar _registrar;
+
+#define REGISTER_CONDITIONAL_CLASS_INSTANCE(classEntry, className) \
+    classEntry::Registrar classEntry::_registrar(className, Conditional::getFactory());
+
+
+#endif
diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp
index 94fb87c48e..bc31e9ea44 100644
--- a/libraries/controllers/src/controllers/Filter.cpp
+++ b/libraries/controllers/src/controllers/Filter.cpp
@@ -18,18 +18,27 @@
 
 using namespace controller;
 
+Filter::Factory Filter::_factory;
+
+REGISTER_FILTER_CLASS_INSTANCE(InvertFilter, "invert")
+REGISTER_FILTER_CLASS_INSTANCE(ConstrainToIntegerFilter, "constrainToInteger")
+REGISTER_FILTER_CLASS_INSTANCE(ConstrainToPositiveIntegerFilter, "constrainToPositiveInteger")
+REGISTER_FILTER_CLASS_INSTANCE(ScaleFilter, "scale")
+REGISTER_FILTER_CLASS_INSTANCE(ClampFilter, "clamp")
+REGISTER_FILTER_CLASS_INSTANCE(DeadZoneFilter, "deadZone")
+REGISTER_FILTER_CLASS_INSTANCE(PulseFilter, "pulse")
+
 
 const QString JSON_FILTER_TYPE = QStringLiteral("type");
 const QString JSON_FILTER_PARAMS = QStringLiteral("params");
 
-Filter::Factory Filter::_factory;
 
 Filter::Pointer Filter::parse(const QJsonObject& json) {
     // The filter is an object, now let s check for type and potential arguments
     Filter::Pointer filter;
     auto filterType = json[JSON_FILTER_TYPE];
     if (filterType.isString()) {
-        filter.reset(Filter::getFactory().create(filterType.toString().toStdString()));
+        filter = Filter::getFactory().create(filterType.toString());
         if (filter) {
             // Filter is defined, need to read the parameters and validate
             auto parameters = json[JSON_FILTER_PARAMS];
@@ -44,7 +53,6 @@ Filter::Pointer Filter::parse(const QJsonObject& json) {
     return Filter::Pointer();
 }
 
-ScaleFilter::FactoryEntryBuilder ScaleFilter::_factoryEntryBuilder;
 
 bool ScaleFilter::parseParameters(const QJsonArray& parameters) {
     if (parameters.size() > 1) {
@@ -53,10 +61,6 @@ bool ScaleFilter::parseParameters(const QJsonArray& parameters) {
     return true;
 }
 
-InvertFilter::FactoryEntryBuilder InvertFilter::_factoryEntryBuilder;
-
-
-ClampFilter::FactoryEntryBuilder ClampFilter::_factoryEntryBuilder;
 
 bool ClampFilter::parseParameters(const QJsonArray& parameters) {
     if (parameters.size() > 1) {
@@ -68,7 +72,6 @@ bool ClampFilter::parseParameters(const QJsonArray& parameters) {
     return true;
 }
 
-DeadZoneFilter::FactoryEntryBuilder DeadZoneFilter::_factoryEntryBuilder;
 
 float DeadZoneFilter::apply(float value) const {
     float scale = 1.0f / (1.0f - _min);
@@ -85,8 +88,6 @@ bool DeadZoneFilter::parseParameters(const QJsonArray& parameters) {
     return true;
 }
 
-PulseFilter::FactoryEntryBuilder PulseFilter::_factoryEntryBuilder;
-
 
 float PulseFilter::apply(float value) const {
     float result = 0.0f;
@@ -110,7 +111,4 @@ bool PulseFilter::parseParameters(const QJsonArray& parameters) {
     return true;
 }
 
-ConstrainToIntegerFilter::FactoryEntryBuilder ConstrainToIntegerFilter::_factoryEntryBuilder;
-
-ConstrainToPositiveIntegerFilter::FactoryEntryBuilder ConstrainToPositiveIntegerFilter::_factoryEntryBuilder;
 
diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h
index 876f57c97d..1fa9833044 100644
--- a/libraries/controllers/src/controllers/Filter.h
+++ b/libraries/controllers/src/controllers/Filter.h
@@ -13,9 +13,10 @@
 #include <list>
 #include <memory>
 #include <numeric>
-#include <functional>
 #include <map>
 
+#include <shared/Factory.h>
+
 #include <GLMHelpers.h>
 
 #include <QtCore/QEasingCurve>
@@ -23,81 +24,35 @@
 class QJsonObject;
 class QJsonArray;
 
-
 namespace controller {
 
     // Encapsulates part of a filter chain
     class Filter {
     public:
-        virtual float apply(float value) const = 0;
-
         using Pointer = std::shared_ptr<Filter>;
         using List = std::list<Pointer>;
         using Lambda = std::function<float(float)>;
+        using Factory = hifi::SimpleFactory<Filter, QString>;
 
+        virtual float apply(float value) const = 0;
         // Factory features
         virtual bool parseParameters(const QJsonArray& parameters) { return true; }
 
-        class Factory {
-        public:
-
-            class Entry {
-            public:
-                virtual Filter* create() const = 0;
-                virtual const char* getName() const = 0;
-
-                Entry() {};
-                virtual ~Entry() {};
-            };
-
-            template <class T> class ClassEntry : public Entry {
-            public:
-                virtual Filter* create() const { return (Filter*) new T(); }
-                virtual const char* getName() const {  return T::getName(); };
-
-                ClassEntry() {};
-                virtual ~ClassEntry() = default;
-
-                class Builder {
-                public:
-                    Builder() {
-                        std::shared_ptr<Entry> classEntry(new ClassEntry<T>());
-                        Filter::getFactory().registerEntry(classEntry);
-                    }
-                };
-            };
-
-            using EntryMap = std::map<std::string, std::shared_ptr<Entry>>;
-
-            void registerEntry(std::shared_ptr<Entry>& entry) {
-                if (entry) {
-                    _entries.insert(EntryMap::value_type(entry->getName(), entry));
-                }
-            }
-
-            Filter* create(const std::string& name) const {
-                const auto& entryIt = _entries.find(name);
-                if (entryIt != _entries.end()) {
-                    return (*entryIt).second->create();
-                }
-                return nullptr;
-            }
-
-        protected:
-            EntryMap _entries;
-        };
-
-        static Filter::Pointer parse(const QJsonObject& json);
+        static Pointer parse(const QJsonObject& json);
+        static void registerBuilder(const QString& name, Factory::Builder builder);
         static Factory& getFactory() { return _factory; }
     protected:
         static Factory _factory;
     };
 }
 
-#define REGISTER_FILTER_CLASS(classEntry, className) \
-    static const char* getName() { return className; } \
-    using FactoryEntryBuilder = Filter::Factory::ClassEntry<classEntry>::Builder;\
-    static FactoryEntryBuilder _factoryEntryBuilder;
+#define REGISTER_FILTER_CLASS(classEntry) \
+    private: \
+    using Registrar = Filter::Factory::Registrar<classEntry>; \
+    static Registrar _registrar;
+
+#define REGISTER_FILTER_CLASS_INSTANCE(classEntry, className) \
+    classEntry::Registrar classEntry::_registrar(className, Filter::getFactory());
 
 namespace controller {
 
@@ -123,8 +78,8 @@ namespace controller {
     };
    
     class ScaleFilter : public Filter {
+        REGISTER_FILTER_CLASS(ScaleFilter);
     public:
-        REGISTER_FILTER_CLASS(ScaleFilter, "scale");
         ScaleFilter() {}
         ScaleFilter(float scale): _scale(scale) {}
 
@@ -138,8 +93,8 @@ namespace controller {
     };
 
     class InvertFilter : public ScaleFilter {
+        REGISTER_FILTER_CLASS(InvertFilter);
     public:
-        REGISTER_FILTER_CLASS(InvertFilter, "invert");
         InvertFilter() : ScaleFilter(-1.0f) {}
         
         virtual bool parseParameters(const QJsonArray& parameters) { return true; }
@@ -148,8 +103,8 @@ namespace controller {
     };
 
     class ClampFilter : public Filter {
+        REGISTER_FILTER_CLASS(ClampFilter);
     public:
-        REGISTER_FILTER_CLASS(ClampFilter, "clamp");
         ClampFilter(float min = 0.0, float max = 1.0) : _min(min), _max(max) {};
 
         virtual float apply(float value) const override {
@@ -162,8 +117,8 @@ namespace controller {
     };
 
     class DeadZoneFilter : public Filter {
+        REGISTER_FILTER_CLASS(DeadZoneFilter);
     public:
-        REGISTER_FILTER_CLASS(DeadZoneFilter, "deadZone");
         DeadZoneFilter(float min = 0.0) : _min(min) {};
 
         virtual float apply(float value) const override;
@@ -173,8 +128,8 @@ namespace controller {
     };
 
     class PulseFilter : public Filter {
+        REGISTER_FILTER_CLASS(PulseFilter);
     public:
-        REGISTER_FILTER_CLASS(PulseFilter, "pulse");
         PulseFilter() {}
         PulseFilter(float interval) : _interval(interval) {}
 
@@ -189,8 +144,8 @@ namespace controller {
     };
 
     class ConstrainToIntegerFilter : public Filter {
+        REGISTER_FILTER_CLASS(ConstrainToIntegerFilter);
     public:
-        REGISTER_FILTER_CLASS(ConstrainToIntegerFilter, "constrainToInteger");
         ConstrainToIntegerFilter() {};
 
         virtual float apply(float value) const override {
@@ -200,8 +155,8 @@ namespace controller {
     };
 
     class ConstrainToPositiveIntegerFilter : public Filter {
+        REGISTER_FILTER_CLASS(ConstrainToPositiveIntegerFilter);
     public:
-        REGISTER_FILTER_CLASS(ConstrainToPositiveIntegerFilter, "constrainToPositiveInteger");
         ConstrainToPositiveIntegerFilter() {};
 
         virtual float apply(float value) const override {
diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h
index ff988bf1b1..99328f310b 100644
--- a/libraries/controllers/src/controllers/Mapping.h
+++ b/libraries/controllers/src/controllers/Mapping.h
@@ -23,14 +23,12 @@ namespace controller {
 
     class Mapping {
     public:
-        // Map of source channels to route lists
-        using Map = std::map<Endpoint::Pointer, Route::List>;
         using Pointer = std::shared_ptr<Mapping>;
+        using List = Route::List;
 
         Mapping(const QString& name) : name(name) {}
 
-        Map channelMappings;
-
+        List routes;
         QString name;
     };
 
diff --git a/libraries/controllers/src/controllers/Route.h b/libraries/controllers/src/controllers/Route.h
index 8b0e70050f..f290799482 100644
--- a/libraries/controllers/src/controllers/Route.h
+++ b/libraries/controllers/src/controllers/Route.h
@@ -12,8 +12,7 @@
 
 #include "Endpoint.h"
 #include "Filter.h"
-
-class QJsonObject;
+#include "Conditional.h"
 
 namespace controller {
     /*
@@ -23,6 +22,7 @@ namespace controller {
     public:
         Endpoint::Pointer source;
         Endpoint::Pointer destination;
+        Conditional::Pointer conditional;
         Filter::List filters;
 
         using Pointer = std::shared_ptr<Route>;
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 0c3a43bd34..757f680163 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -8,6 +8,8 @@
 
 #include "UserInputMapper.h"
 
+#include <set>
+
 #include <QtCore/QThread>
 #include <QtCore/QFile>
 
@@ -208,17 +210,46 @@ void UserInputMapper::registerDevice(InputDevice* device) {
     auto mapping = loadMapping(device->getDefaultMappingConfig());
     if (mapping) {
         _mappingsByDevice[deviceID] = mapping;
-        for (const auto& entry : mapping->channelMappings) {
-            const auto& source = entry.first;
-            const auto& routes = entry.second;
-            auto& list = _defaultMapping->channelMappings[source];
-            list.insert(list.end(), routes.begin(), routes.end());
-        }
+        auto& defaultRoutes = _defaultMapping->routes;
+
+        // New routes for a device get injected IN FRONT of existing routes.  Routes
+        // are processed in order so this ensures that the standard -> action processing 
+        // takes place after all of the hardware -> standard or hardware -> action processing
+        // because standard -> action is the first set of routes added.
+        defaultRoutes.insert(defaultRoutes.begin(), mapping->routes.begin(), mapping->routes.end());
     }
 
     emit hardwareChanged();
 }
 
+// FIXME remove the associated device mappings
+void UserInputMapper::removeDevice(int deviceID) {
+    auto proxyEntry = _registeredDevices.find(deviceID);
+    if (_registeredDevices.end() == proxyEntry) {
+        qCWarning(controllers) << "Attempted to remove unknown device " << deviceID;
+        return;
+    }
+    auto proxy = proxyEntry->second;
+    auto mappingsEntry = _mappingsByDevice.find(deviceID);
+    if (_mappingsByDevice.end() != mappingsEntry) {
+        const auto& mapping = mappingsEntry->second;
+        const auto& deviceRoutes = mapping->routes;
+        std::set<Route::Pointer> routeSet(deviceRoutes.begin(), deviceRoutes.end());
+
+        auto& defaultRoutes = _defaultMapping->routes;
+        std::remove_if(defaultRoutes.begin(), defaultRoutes.end(), [&](Route::Pointer route)->bool {
+            return routeSet.count(route) != 0;
+        });
+
+        _mappingsByDevice.erase(mappingsEntry);
+    }
+
+    _registeredDevices.erase(proxyEntry);
+
+    emit hardwareChanged();
+}
+
+
 DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
     auto device = _registeredDevices.find(input.getDevice());
     if (device != _registeredDevices.end()) {
@@ -290,11 +321,6 @@ Input UserInputMapper::findDeviceInput(const QString& inputName) const {
     return Input::INVALID_INPUT;
 }
 
-// FIXME remove the associated device mappings
-void UserInputMapper::removeDevice(int device) {
-    _registeredDevices.erase(device);
-}
-
 void fixBisectedAxis(float& full, float& negative, float& positive) {
     full = full + (negative * -1.0f) + positive;
     negative = full >= 0.0f ? 0.0f : full * -1.0f;
@@ -470,12 +496,6 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
     return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
 }
 
-enum Pass {
-    HARDWARE_PASS,
-    STANDARD_PASS,
-    NUM_PASSES
-};
-
 void UserInputMapper::update() {
     static auto deviceNames = getDeviceNames();
     _overrideValues.clear();
@@ -485,66 +505,58 @@ void UserInputMapper::update() {
 
     // Now process the current values for each level of the stack
     for (auto& mapping : _activeMappings) {
-        for (int pass = HARDWARE_PASS; pass < NUM_PASSES; ++pass) {
-            for (const auto& mappingEntry : mapping->channelMappings) {
-                const auto& source = mappingEntry.first;
-                if (_inputsByEndpoint.count(source)) {
-                    auto sourceInput = _inputsByEndpoint[source];
-                    if ((sourceInput.device == STANDARD_DEVICE) ^ (pass == STANDARD_PASS)) {
-                        continue;
-                    }
-                }
+        for (const auto& route : mapping->routes) {
+            const auto& source = route->source;
+            // Endpoints can only be read once (though a given mapping can route them to 
+            // multiple places).  Consider... If the default is to wire the A button to JUMP
+            // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
+            // I press the button.  The exception is if I'm wiring a control back to itself
+            // in order to adjust my interface, like inverting the Y axis on an analog stick
+            if (readEndpoints.count(source)) {
+                continue;
+            }
 
-                // Endpoints can only be read once (though a given mapping can route them to 
-                // multiple places).  Consider... If the default is to wire the A button to JUMP
-                // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
-                // I press the button.  The exception is if I'm wiring a control back to itself
-                // in order to adjust my interface, like inverting the Y axis on an analog stick
-                if (readEndpoints.count(source)) {
+            const auto& destination = route->destination;
+            // THis could happen if the route destination failed to create
+            // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
+            if (!destination) {
+                continue;
+            }
+
+            if (writtenEndpoints.count(destination)) {
+                continue;
+            }
+
+            if (route->conditional) {
+                if (!route->conditional->satisfied()) {
                     continue;
                 }
+            }
 
-                // Apply the value to all the routes
-                const auto& routes = mappingEntry.second;
+            // Standard controller destinations can only be can only be used once.
+            if (getStandardDeviceID() == destination->getInput().getDevice()) {
+                writtenEndpoints.insert(destination);
+            }
 
-                for (const auto& route : routes) {
-                    const auto& destination = route->destination;
-                    // THis could happen if the route destination failed to create
-                    // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
-                    if (!destination) {
-                        continue;
-                    }
+            // Only consume the input if the route isn't a loopback.
+            // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
+            bool loopback = source == destination;
+            if (!loopback) {
+                readEndpoints.insert(source);
+            }
 
-                    if (writtenEndpoints.count(destination)) {
-                        continue;
-                    }
+            // Fetch the value, may have been overriden by previous loopback routes
+            float value = getValue(source);
 
-                    // Standard controller destinations can only be can only be used once.
-                    if (getStandardDeviceID() == destination->getInput().getDevice()) {
-                        writtenEndpoints.insert(destination);
-                    }
+            // Apply each of the filters.
+            for (const auto& filter : route->filters) {
+                value = filter->apply(value);
+            }
 
-                    // Only consume the input if the route isn't a loopback.
-                    // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
-                    bool loopback = source == destination;
-                    if (!loopback) {
-                        readEndpoints.insert(source);
-                    }
-
-                    // Fetch the value, may have been overriden by previous loopback routes
-                    float value = getValue(source);
-
-                    // Apply each of the filters.
-                    for (const auto& filter : route->filters) {
-                        value = filter->apply(value);
-                    }
-
-                    if (loopback) {
-                        _overrideValues[source] = value;
-                    } else {
-                        destination->apply(value, 0, source);
-                    }
-                }
+            if (loopback) {
+                _overrideValues[source] = value;
+            } else {
+                destination->apply(value, 0, source);
             }
         }
     }
@@ -693,6 +705,7 @@ Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) {
 const QString JSON_NAME = QStringLiteral("name");
 const QString JSON_CHANNELS = QStringLiteral("channels");
 const QString JSON_CHANNEL_FROM = QStringLiteral("from");
+const QString JSON_CHANNEL_WHEN = QStringLiteral("when");
 const QString JSON_CHANNEL_TO = QStringLiteral("to");
 const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
 
@@ -707,6 +720,20 @@ Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) {
     return Endpoint::Pointer();
 }
 
+Conditional::Pointer UserInputMapper::parseConditional(const QJsonValue& value) {
+    if (value.isString()) {
+        auto input = findDeviceInput(value.toString());
+        auto endpoint = endpointFor(input);
+        if (!endpoint) {
+            return Conditional::Pointer();
+        }
+
+        return std::make_shared<EndpointConditional>(endpoint);
+    } 
+      
+    return Conditional::parse(value);
+}
+
 Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
     if (!value.isObject()) {
         return Route::Pointer();
@@ -725,6 +752,15 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
         return Route::Pointer();
     }
 
+    if (obj.contains(JSON_CHANNEL_WHEN)) {
+        auto when = parseConditional(obj[JSON_CHANNEL_WHEN]);
+        if (!when) {
+            qWarning() << "Invalid route conditional " << obj[JSON_CHANNEL_TO];
+            return Route::Pointer();
+        }
+        result->conditional = when;
+    }
+
     const auto& filtersValue = obj[JSON_CHANNEL_FILTERS];
     if (filtersValue.isArray()) {
         auto filtersArray = filtersValue.toArray();
@@ -752,16 +788,14 @@ Mapping::Pointer UserInputMapper::parseMapping(const QJsonValue& json) {
     auto obj = json.toObject();
     auto mapping = std::make_shared<Mapping>("default");
     mapping->name = obj[JSON_NAME].toString();
-    mapping->channelMappings.clear();
     const auto& jsonChannels = obj[JSON_CHANNELS].toArray();
-    Mapping::Map map;
     for (const auto& channelIt : jsonChannels) {
         Route::Pointer route = parseRoute(channelIt);
         if (!route) {
             qWarning() << "Couldn't parse route";
             continue;
         }
-        mapping->channelMappings[route->source].push_back(route);
+        mapping->routes.push_back(route);
     }
     return mapping;
 }
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 1c1a9506df..5d5895fa7b 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -142,6 +142,7 @@ namespace controller {
         Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
         Mapping::Pointer parseMapping(const QJsonValue& json);
         Route::Pointer parseRoute(const QJsonValue& value);
+        Conditional::Pointer parseConditional(const QJsonValue& value);
         Endpoint::Pointer parseEndpoint(const QJsonValue& value);
 
         InputToEndpointMap _endpointsByInput;
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index d60032cb43..e76f55534f 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -41,7 +41,7 @@ void RouteBuilderProxy::to(const QScriptValue& destination) {
 void RouteBuilderProxy::to(const Endpoint::Pointer& destination) {
     auto sourceEndpoint = _route->source;
     _route->destination = destination;
-    _mapping->channelMappings[sourceEndpoint].push_back(_route);
+    _mapping->routes.push_back(_route);
     deleteLater();
 }
 
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
index f5f8b47a90..ff6c0ce2de 100755
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
@@ -183,24 +183,24 @@ void KeyboardMouseDevice::buildDeviceProxy(controller::DeviceProxy::Pointer prox
         availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString()));
         availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString()));
 
-        availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "Left Mouse Click"));
-        availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "Middle Mouse Click"));
-        availableInputs.append(Input::NamedPair(makeInput(Qt::RightButton), "Right Mouse Click"));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "LeftMouseClick"));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "MiddleMouseClick"));
+        availableInputs.append(Input::NamedPair(makeInput(Qt::RightButton), "RightMouseClick"));
         
-        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_POS), "Mouse Move Right"));
-        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_NEG), "Mouse Move Left"));
-        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_POS), "Mouse Move Up"));
-        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_NEG), "Mouse Move Down"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_POS), "MouseMoveRight"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_NEG), "MouseMoveLeft"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_POS), "MouseMoveUp"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_NEG), "MouseMoveDown"));
         
-        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "Mouse Wheel Right"));
-        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "Mouse Wheel Left"));
-        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "Mouse Wheel Up"));
-        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_NEG), "Mouse Wheel Down"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "MouseWheelRight"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "MouseWheelLeft"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "MouseWheelUp"));
+        availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_NEG), "MouseWheelDown"));
         
-        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_POS), "Touchpad Right"));
-        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_NEG), "Touchpad Left"));
-        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_POS), "Touchpad Up"));
-        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_NEG), "Touchpad Down"));
+        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_POS), "TouchpadRight"));
+        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_NEG), "TouchpadLeft"));
+        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_POS), "TouchpadUp"));
+        availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_NEG), "TouchpadDown"));
 
         return availableInputs;
     };
diff --git a/libraries/shared/src/shared/Factory.h b/libraries/shared/src/shared/Factory.h
new file mode 100644
index 0000000000..6f1da6644b
--- /dev/null
+++ b/libraries/shared/src/shared/Factory.h
@@ -0,0 +1,51 @@
+//
+//  Created by Bradley Austin Davis 2015/10/09
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Shared_Factory_h
+#define hifi_Shared_Factory_h
+
+#include <functional>
+#include <map>
+#include <memory>
+
+namespace hifi {
+
+    template <typename T, typename Key>
+    class SimpleFactory {
+    public:
+        using Pointer = std::shared_ptr<T>;
+        using Builder = std::function<Pointer()>;
+        using BuilderMap = std::map<Key, Builder>;
+
+        void registerBuilder(const Key& name, Builder builder) {
+            // FIXME don't allow name collisions
+            _builders[name] = builder;
+        }
+
+        Pointer create(const Key& name) const {
+            const auto& entryIt = _builders.find(name);
+            if (entryIt != _builders.end()) {
+                return (*entryIt).second();
+            }
+            return Pointer();
+        }
+
+        template <typename Impl>
+        class Registrar {
+        public:
+            Registrar(const Key& name, SimpleFactory& factory) {
+                factory.registerBuilder(name, [] { return std::make_shared<Impl>(); });
+            }
+        };
+    protected:
+        BuilderMap _builders;
+    };
+}
+
+#endif

From 3d2f00c609fc5ee48afcbaec5ffe56b4e0acc11d Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Tue, 20 Oct 2015 17:01:45 -0700
Subject: [PATCH 073/301] Cleaner intgerface, including cleanup.

---
 libraries/animation/src/Rig.cpp | 56 +++++++++++++++++++++++----------
 libraries/animation/src/Rig.h   |  7 +++--
 2 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 2fd7364434..215e0095c0 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -13,6 +13,7 @@
 
 #include <glm/gtx/vector_angle.hpp>
 #include <queue>
+#include <QScriptValueIterator>
 
 #include <NumericalConstants.h>
 #include <DebugDraw.h>
@@ -604,6 +605,42 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
     _lastPosition = worldPosition;
 }
 
+void Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) {
+    _stateHandlers = handler;
+}
+void Rig::removeAnimationStateHandler(QScriptValue handler) {
+    _stateHandlersResultsToRemove = _stateHandlersResults;
+    _stateHandlers = _stateHandlersResults = QScriptValue();
+}
+void Rig::cleanupAnimationStateHandler() {
+    if (!_stateHandlersResultsToRemove.isValid()) {
+        return;
+    }
+    QScriptValueIterator property(_stateHandlersResultsToRemove);
+    while (property.hasNext()) {
+        property.next();
+        _animVars.unset(property.name());
+    }
+    _stateHandlersResultsToRemove = QScriptValue();
+}
+void Rig::updateAnimationStateHandlers() {
+    if (!_stateHandlers.isValid()) {
+        return;
+    }
+    // TODO: iterate multiple handlers, but with one shared arg.
+    // TODO: fill the properties based on the union of requested properties. (Keep all properties objs and compute new union when add/remove handler.)
+    // TODO: check QScriptEngine::hasUncaughtException()
+    // TODO: call asynchronously (through a signal on script), so that each script is single threaded, and so we never block here.
+    //       This will require inboundMaps to be kept in the list of per-handler data.
+    QScriptEngine* engine = _stateHandlers.engine();
+    QScriptValue outboundMap = _animVars.animVariantMapToScriptValue(engine);
+    QScriptValueList args;
+    args << outboundMap;
+    _stateHandlersResults = _stateHandlers.call(QScriptValue(), args);
+    _animVars.animVariantMapFromScriptValue(_stateHandlersResults);
+    //qCDebug(animation) << _animVars.lookup("foo", QString("not set"));
+}
+
 void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
 
     if (_enableAnimGraph) {
@@ -611,20 +648,7 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
             return;
         }
 
-        if (_stateHandlers.isValid()) {
-            // TODO: iterate multiple handlers, but with one shared arg.
-            // TODO: fill the properties based on the union of requested properties. (Keep all properties objs and compute new union when add/remove handler.)
-            // TODO: check QScriptEngine::hasUncaughtException()
-            // TODO: call asynchronously (through a signal on script), so that each script is single threaded, and so we never block here.
-            //       This will require inboundMaps to be kept in the list of per-handler data.
-            QScriptEngine* engine = _stateHandlers.engine();
-            QScriptValue outboundMap = _animVars.animVariantMapToScriptValue(engine);
-            QScriptValueList args;
-            args << outboundMap;
-            _stateHandlersResults = _stateHandlers.call(QScriptValue(), args);
-            _animVars.animVariantMapFromScriptValue(_stateHandlersResults);
-            //qCDebug(animation) << _animVars.lookup("foo", QString("not set"));
-        }
+        updateAnimationStateHandlers();
         // evaluate the animation
         AnimNode::Triggers triggersOut;
         AnimPoseVec poses = _animNode->evaluate(_animVars, deltaTime, triggersOut);
@@ -1201,9 +1225,7 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
             _animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
         }
         if (params.isRightEnabled) {
-            if (!_stateHandlersResults.property("rightHandPosition", QScriptValue::ResolveLocal).isValid()) {
-                _animVars.set("rightHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.rightPosition);
-            }
+            _animVars.set("rightHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.rightPosition);
             _animVars.set("rightHandRotation", rootBindPose.rot * yFlipHACK * params.rightOrientation);
             _animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
         } else {
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index 89fde9002f..3f68deef1a 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -200,12 +200,14 @@ public:
     AnimNode::ConstPointer getAnimNode() const { return _animNode; }
     AnimSkeleton::ConstPointer getAnimSkeleton() const { return _animSkeleton; }
     bool disableHands {false}; // should go away with rig animation (and Rig::inverseKinematics)
-    void addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { _stateHandlers = handler; }
-    void removeAnimationStateHandler(QScriptValue handler) { _stateHandlers = QScriptValue(); }
+    void addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList);
+    void removeAnimationStateHandler(QScriptValue handler);
+    void cleanupAnimationStateHandler();
 
     bool getModelOffset(glm::vec3& modelOffsetOut) const;
 
  protected:
+    void updateAnimationStateHandlers();
 
     void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
     void updateNeckJoint(int index, const HeadParameters& params);
@@ -248,6 +250,7 @@ public:
 private:
     QScriptValue _stateHandlers {};
     QScriptValue _stateHandlersResults {};
+    QScriptValue _stateHandlersResultsToRemove {};
 };
 
 #endif /* defined(__hifi__Rig__) */

From 574a51e83140e7784e7ee1e7ab37d6e23bd4df5f Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Tue, 20 Oct 2015 17:02:16 -0700
Subject: [PATCH 074/301] Use cleaner interface.

---
 interface/src/avatar/SkeletonModel.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp
index 28c7941c52..5c98d4cd9b 100644
--- a/interface/src/avatar/SkeletonModel.cpp
+++ b/interface/src/avatar/SkeletonModel.cpp
@@ -111,11 +111,8 @@ static const PalmData* getPalmWithIndex(Hand* hand, int index) {
 const float PALM_PRIORITY = DEFAULT_PRIORITY;
 // Called within Model::simulate call, below.
 void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
-    if (_owningAvatar->isMyAvatar()) {
-        _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation());
-    }
-    Model::updateRig(deltaTime, parentTransform);
     Head* head = _owningAvatar->getHead();
+    _rig->cleanupAnimationStateHandler();
     if (_owningAvatar->isMyAvatar()) {
         MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
         const FBXGeometry& geometry = _geometry->getFBXGeometry();
@@ -191,6 +188,8 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
 
         _rig->updateFromHandParameters(handParams, deltaTime);
 
+        _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation());
+
     } else {
         // This is a little more work than we really want.
         //
@@ -212,6 +211,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
                               getTranslation(), getRotation(),
                               head->getFinalOrientationInWorldFrame(), head->getCorrectedLookAtPosition());
      }
+    Model::updateRig(deltaTime, parentTransform);
 }
 
 void SkeletonModel::updateAttitude() {

From 6f7719e9e9cb021545f807129ad5e8c8a4eb2b8a Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 20 Oct 2015 17:44:24 -0700
Subject: [PATCH 075/301] Finally getting the merge to work

---
 libraries/controllers/src/controllers/Actions.h    |  3 ++-
 .../src/controllers/ScriptingInterface.cpp         | 14 ++++++++++++++
 .../src/controllers/UserInputMapper.cpp            |  1 -
 .../controllers/src/controllers/UserInputMapper.h  |  9 ++++++---
 4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h
index 2b581eb706..77a772de9e 100644
--- a/libraries/controllers/src/controllers/Actions.h
+++ b/libraries/controllers/src/controllers/Actions.h
@@ -71,7 +71,8 @@ enum class Action {
     NUM_ACTIONS,
 };
 
-int toInt(Action action) { return static_cast<int>(action); }
+template <typename T>
+int toInt(T enumValue) { return static_cast<int>(enumValue); }
 
 class ActionsDevice : public QObject, public InputDevice {
     Q_OBJECT
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 37c3035535..40c65549a8 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -71,6 +71,16 @@ controller::ScriptingInterface::ScriptingInterface() {
 
 namespace controller {
 
+    QObject* ScriptingInterface::newMapping(const QString& mappingName) {
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        return new MappingBuilderProxy(*userInputMapper, userInputMapper->newMapping(mappingName));
+    }
+
+    void ScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        userInputMapper->enableMapping(mappingName, enable);
+    }
+
     float ScriptingInterface::getValue(const int& source) const {
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
         return userInputMapper->getValue(Input((uint32_t)source));
@@ -88,6 +98,10 @@ namespace controller {
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
         return userInputMapper->getPose(Input((uint32_t)source)); 
     }
+    
+    Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
+        return getPoseValue(Input(device, source, ChannelType::POSE).getID());
+    }
 
     //bool ScriptingInterface::isPrimaryButtonPressed() const {
     //    return isButtonPressed(StandardButtonChannel::A);
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 8dfdd33eba..6c530020a9 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -31,7 +31,6 @@ controller::UserInputMapper::UserInputMapper() {
     _standardController = std::make_shared<StandardController>();
     registerDevice(new ActionsDevice());
     registerDevice(_standardController.get());
-    assignDefaulActionScales();
 }
 
 namespace controller {
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index d5b2e4e282..e9b6c59596 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -32,6 +32,10 @@
 #include "Actions.h"
 
 namespace controller {
+
+    class RouteBuilderProxy;
+    class MappingBuilderProxy;
+
     class UserInputMapper : public QObject, public Dependency {
         Q_OBJECT
             SINGLETON_DEPENDENCY
@@ -81,7 +85,6 @@ namespace controller {
         Pose getPoseState(Action action) const { return _poseStates[toInt(action)]; }
         int findAction(const QString& actionName) const;
         QVector<QString> getActionNames() const;
-        void assignDefaulActionScales();
 
         void setActionState(Action action, float value) { _externalActionStates[toInt(action)] = value; }
         void deltaActionState(Action action, float delta) { _externalActionStates[toInt(action)] += delta; }
@@ -139,8 +142,8 @@ namespace controller {
         float getValue(const Endpoint::Pointer& endpoint) const;
         Pose getPose(const Endpoint::Pointer& endpoint) const;
 
-        friend class ::controller::RouteBuilderProxy;
-        friend class ::controller::MappingBuilderProxy;
+        friend class RouteBuilderProxy;
+        friend class MappingBuilderProxy;
         Endpoint::Pointer endpointFor(const QJSValue& endpoint);
         Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
         Endpoint::Pointer endpointFor(const Input& endpoint) const;

From da26d0dee159b241932ee2eaadc5921386ce095a Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 20 Oct 2015 18:19:44 -0700
Subject: [PATCH 076/301] Adding the hand poses channels in the controller
 mapping files

---
 interface/resources/controllers/hydra.json              | 7 +++++--
 interface/resources/controllers/standard.json           | 4 +++-
 libraries/controllers/src/controllers/UserInputMapper.h | 1 -
 3 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json
index 25c8db61cb..c20d54b7c1 100644
--- a/interface/resources/controllers/hydra.json
+++ b/interface/resources/controllers/hydra.json
@@ -23,6 +23,9 @@
         { "from": "Hydra.R1", "to": "Standard.X" },
         { "from": "Hydra.R2", "to": "Standard.A" }, 
         { "from": "Hydra.R3", "to": "Standard.B" }, 
-        { "from": "Hydra.R4", "to": "Standard.Y" }
-    ]
+        { "from": "Hydra.R4", "to": "Standard.Y" },
+
+        { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, 
+        { "from": "Hydra.RightHand", "to": "Standard.RightHand" }
+  ]
 }
diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 364d24ae16..b662e5394d 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -36,6 +36,8 @@
             "from": "Standard.LT", 
             "to": "Actions.BOOM_OUT", 
             "filters": [ { "type": "scale", "scale": 0.1 } ]
-        }
+        },
+        { "from": "Standard.LeftHand", "to": "Actions.LEFT_HAND" }, 
+        { "from": "Standard.RightHand", "to": "Actions.RIGHT_HAND" }
     ]
 }
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index e9b6c59596..7561ba84af 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -174,6 +174,5 @@ Q_DECLARE_METATYPE(QVector<controller::Action>)
 
 // Cheating.
 using UserInputMapper = controller::UserInputMapper;
-//>>>>>>> 9c031b6bef988f123cb955c81299395386ec488c
 
 #endif // hifi_UserInputMapper_h

From 053aca2e3695ebb8aa9ffbeae1c1886f5e3a7813 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 20 Oct 2015 21:12:46 -0700
Subject: [PATCH 077/301] fixing the cast bug on osx

---
 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 4e23e19652..fcb90a96cd 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -630,7 +630,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     connect(userInputMapper.data(), &UserInputMapper::actionEvent, _controllerScriptingInterface, &ControllerScriptingInterface::actionEvent);
     connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
         if (state) {
-            switch (action) {
+            switch (controller::Action(action)) {
             case controller::Action::TOGGLE_MUTE:
                 DependencyManager::get<AudioClient>()->toggleMute();
                 break;

From a124d3b4332205436b73997079600f52c3dd03c0 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Tue, 20 Oct 2015 22:00:16 -0700
Subject: [PATCH 078/301] Moving to InputEndpoint, fixing build problem

---
 interface/src/Application.cpp                             | 8 ++------
 libraries/controllers/src/controllers/UserInputMapper.cpp | 4 +---
 2 files changed, 3 insertions(+), 9 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 4e23e19652..4418f94b3a 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -629,12 +629,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     connect(userInputMapper.data(), &UserInputMapper::actionEvent, _controllerScriptingInterface, &ControllerScriptingInterface::actionEvent);
     connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
-        if (state) {
-            switch (action) {
-            case controller::Action::TOGGLE_MUTE:
-                DependencyManager::get<AudioClient>()->toggleMute();
-                break;
-            }
+        if (state && action == toInt(controller::Action::TOGGLE_MUTE)) {
+            DependencyManager::get<AudioClient>()->toggleMute();
         }
     });
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 5d93150aed..74b3db0d57 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -255,9 +255,7 @@ void UserInputMapper::registerDevice(InputDevice* device) {
         } else if (input.device == ACTIONS_DEVICE) {
             endpoint = std::make_shared<ActionEndpoint>(input);
         } else {
-            endpoint = std::make_shared<LambdaEndpoint>([=] {
-                return proxy->getValue(input, 0);
-            });
+            endpoint = std::make_shared<InputEndpoint>(input);
         }
         _inputsByEndpoint[endpoint] = input;
         _endpointsByInput[input] = endpoint;

From f0edc302bf351a8be5b22d6d2c60c10e3886ee8f Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Tue, 20 Oct 2015 22:06:08 -0700
Subject: [PATCH 079/301] Fixing filters creation

---
 libraries/controllers/src/controllers/UserInputMapper.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 74b3db0d57..0c47a2dce8 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -845,10 +845,15 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
     }
 
     const auto& filtersValue = obj[JSON_CHANNEL_FILTERS];
+    // FIXME support strings for filters with no parameters, both in the array and at the top level...
+    // i.e.
+    // { "from": "Standard.DU", "to" : "Actions.LONGITUDINAL_FORWARD", "filters" : "invert" },
+    // and 
+    // { "from": "Standard.DU", "to" : "Actions.LONGITUDINAL_FORWARD", "filters" : [ "invert", "constrainToInteger" ] },
     if (filtersValue.isArray()) {
         auto filtersArray = filtersValue.toArray();
         for (auto filterValue : filtersArray) {
-            if (filterValue.isObject()) {
+            if (!filterValue.isObject()) {
                 qWarning() << "Invalid filter " << filterValue;
                 return Route::Pointer();
             }

From ac2a60befb73dd11fe4d04a3cf90e8e8a6be3f03 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 21 Oct 2015 10:57:41 -0700
Subject: [PATCH 080/301] Adding primary/secondary thumb abstraction

---
 .../src/controllers/StandardController.cpp    | 81 ++++++++++---------
 .../src/controllers/StandardControls.h        | 11 +++
 2 files changed, 55 insertions(+), 37 deletions(-)

diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index e9a2e71973..061fc4ea56 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -40,59 +40,66 @@ void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
     proxy->getAvailabeInputs = [this] () -> QVector<Input::NamedPair> {
         QVector<Input::NamedPair> availableInputs;
         // Buttons
-        availableInputs.append(Input::NamedPair(makeInput(controller::A), "A"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::B), "B"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::X), "X"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::Y), "Y"));
+        availableInputs.append(makePair(A, "A"));
+        availableInputs.append(makePair(B, "B"));
+        availableInputs.append(makePair(X, "X"));
+        availableInputs.append(makePair(Y, "Y"));
 
         // DPad
-        availableInputs.append(Input::NamedPair(makeInput(controller::DU), "DU"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::DD), "DD"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::DL), "DL"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::DR), "DR"));
+        availableInputs.append(makePair(DU, "DU"));
+        availableInputs.append(makePair(DD, "DD"));
+        availableInputs.append(makePair(DL, "DL"));
+        availableInputs.append(makePair(DR, "DR"));
 
         // Bumpers
-        availableInputs.append(Input::NamedPair(makeInput(controller::LB), "LB"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::RB), "RB"));
+        availableInputs.append(makePair(LB, "LB"));
+        availableInputs.append(makePair(RB, "RB"));
 
         // Stick press
-        availableInputs.append(Input::NamedPair(makeInput(controller::LS), "LS"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::RS), "RS"));
+        availableInputs.append(makePair(LS, "LS"));
+        availableInputs.append(makePair(RS, "RS"));
 
         // Center buttons
-        availableInputs.append(Input::NamedPair(makeInput(controller::START), "Start"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::BACK), "Back"));
+        availableInputs.append(makePair(START, "Start"));
+        availableInputs.append(makePair(BACK, "Back"));
 
         // Analog sticks
-        availableInputs.append(Input::NamedPair(makeInput(controller::LY), "LY"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::LX), "LX"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::RY), "RY"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::RX), "RX"));
+        availableInputs.append(makePair(LY, "LY"));
+        availableInputs.append(makePair(LX, "LX"));
+        availableInputs.append(makePair(RY, "RY"));
+        availableInputs.append(makePair(RX, "RX"));
 
         // Triggers
-        availableInputs.append(Input::NamedPair(makeInput(controller::LT), "LT"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::RT), "RT"));
+        availableInputs.append(makePair(LT, "LT"));
+        availableInputs.append(makePair(RT, "RT"));
 
         // Poses
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT_HAND), "LeftHand"));
-        availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT_HAND), "RightHand"));
+        availableInputs.append(makePair(LEFT_HAND, "LeftHand"));
+        availableInputs.append(makePair(RIGHT_HAND, "RightHand"));
 
         // Aliases, PlayStation style names
-        availableInputs.append(Input::NamedPair(makeInput(controller::LB), "L1"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::RB), "R1"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::LT), "L2"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::RT), "R2"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::LS), "L3"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::RS), "R3"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::BACK), "Select"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::A), "Cross"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::B), "Circle"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::X), "Square"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::Y), "Triangle"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::DU), "Up"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::DD), "Down"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::DL), "Left"));
-        availableInputs.append(Input::NamedPair(makeInput(controller::DR), "Right"));
+        availableInputs.append(makePair(LB, "L1"));
+        availableInputs.append(makePair(RB, "R1"));
+        availableInputs.append(makePair(LT, "L2"));
+        availableInputs.append(makePair(RT, "R2"));
+        availableInputs.append(makePair(LS, "L3"));
+        availableInputs.append(makePair(RS, "R3"));
+        availableInputs.append(makePair(BACK, "Select"));
+        availableInputs.append(makePair(A, "Cross"));
+        availableInputs.append(makePair(B, "Circle"));
+        availableInputs.append(makePair(X, "Square"));
+        availableInputs.append(makePair(Y, "Triangle"));
+        availableInputs.append(makePair(DU, "Up"));
+        availableInputs.append(makePair(DD, "Down"));
+        availableInputs.append(makePair(DL, "Left"));
+        availableInputs.append(makePair(DR, "Right"));
+
+
+        availableInputs.append(makePair(LeftPrimaryThumb, "LeftPrimaryThumb"));
+        availableInputs.append(makePair(LeftSecondaryThumb, "LeftSecondaryThumb"));
+        availableInputs.append(makePair(RightPrimaryThumb, "RightPrimaryThumb"));
+        availableInputs.append(makePair(RightSecondaryThumb, "RightSecondaryThumb"));
+
         return availableInputs;
     };
 }
diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h
index dc39a8bbeb..26644e2f38 100644
--- a/libraries/controllers/src/controllers/StandardControls.h
+++ b/libraries/controllers/src/controllers/StandardControls.h
@@ -16,21 +16,32 @@ namespace controller {
         B,
         X,
         Y,
+
         // Center buttons
         BACK,
         GUIDE,
         START,
+
         // Stick press
         LS,
         RS,
+
         // Bumper press
         LB,
         RB,
+
         // DPad
         DU,
         DD,
         DL,
         DR,
+
+        // These don't map to SDL types
+        LeftPrimaryThumb,
+        LeftSecondaryThumb,
+        RightPrimaryThumb,
+        RightSecondaryThumb,
+
         NUM_STANDARD_BUTTONS
     };
 

From 84e2ace0ead11d7de1e8a60a60dff127084a4bc4 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 21 Oct 2015 12:57:48 -0700
Subject: [PATCH 081/301] Prevent crash on connecting gamepad

---
 libraries/input-plugins/src/input-plugins/SDL2Manager.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
index b052162c77..54197b1a70 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
@@ -129,6 +129,7 @@ void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) {
                 if (!_openJoysticks.contains(id)) {
                     // Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
                     Joystick* joystick = new Joystick(id, controller);
+                    _openJoysticks[id] = joystick;
                     userInputMapper->registerDevice(joystick);
                     emit joystickAdded(joystick);
                 }

From 3eedfd369e7c02866d8d76e6228c7ee8aac7afed Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 21 Oct 2015 14:01:18 -0700
Subject: [PATCH 082/301] expose the Pose structure to JS

---
 .../controllers/src/controllers/Pose.cpp      | 19 +++++++++++++++++++
 libraries/controllers/src/controllers/Pose.h  |  8 ++++++--
 .../src/controllers/UserInputMapper.cpp       |  3 +++
 3 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp
index 112e6e01a9..9cb33bc777 100644
--- a/libraries/controllers/src/controllers/Pose.cpp
+++ b/libraries/controllers/src/controllers/Pose.cpp
@@ -6,6 +6,11 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
+#include <QScriptEngine>
+#include <QScriptValue>
+
+#include <RegisteredMetaTypes.h>
+
 #include "Pose.h"
 
 namespace controller {
@@ -25,6 +30,20 @@ namespace controller {
             velocity == right.getVelocity() && angularVelocity == right.getAngularVelocity();
     }
 
+    QScriptValue Pose::toScriptValue(QScriptEngine* engine, const Pose& pose) {
+        QScriptValue obj = engine->newObject();
+        obj.setProperty("translation", vec3toScriptValue(engine, pose.translation));
+        obj.setProperty("rotation", quatToScriptValue(engine, pose.rotation));
+        obj.setProperty("velocity", vec3toScriptValue(engine, pose.velocity));
+        obj.setProperty("angularVelocity", quatToScriptValue(engine, pose.angularVelocity));
+        obj.setProperty("valid", pose.valid);
+
+        return obj;
+    }
+
+    void Pose::fromScriptValue(const QScriptValue& object, Pose& pose) {
+        // nothing for now...
+    }
 
 }
 
diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h
index 9243ceb734..b792b0e901 100644
--- a/libraries/controllers/src/controllers/Pose.h
+++ b/libraries/controllers/src/controllers/Pose.h
@@ -11,6 +11,7 @@
 #ifndef hifi_controllers_Pose_h
 #define hifi_controllers_Pose_h
 
+#include <QScriptValue>
 #include <GLMHelpers.h>
 
 namespace controller {
@@ -35,9 +36,12 @@ namespace controller {
         quat getRotation() const { return rotation; }
         vec3 getVelocity() const { return velocity; }
         quat getAngularVelocity() const { return angularVelocity; }
+
+        static QScriptValue toScriptValue(QScriptEngine* engine, const Pose& event);
+        static void fromScriptValue(const QScriptValue& object, Pose& event);
     };
-
-
 }
 
+//Q_DECLARE_METATYPE(controller::Pose);
+
 #endif
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 6ef64fc784..b9833a1f6b 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -495,6 +495,7 @@ void UserInputMapper::assignDefaulActionScales() {
 static int actionMetaTypeId = qRegisterMetaType<Action>();
 static int inputMetaTypeId = qRegisterMetaType<Input>();
 static int inputPairMetaTypeId = qRegisterMetaType<InputPair>();
+static int poseMetaTypeId = qRegisterMetaType<controller::Pose>("Pose");
 
 
 QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input);
@@ -547,6 +548,8 @@ void UserInputMapper::registerControllerTypes(QScriptEngine* engine) {
     qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
     qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
     qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
+
+    qScriptRegisterMetaType(engine, Pose::toScriptValue, Pose::fromScriptValue);
 }
 
 Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) {

From ffd277d4d5d75a1a59fea8f6505b3449c9b00aad Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 21 Oct 2015 14:31:17 -0700
Subject: [PATCH 083/301] fix EntityItemID dependency

---
 libraries/entities/src/EntityItemID.cpp      | 16 ++++++++++++++++
 libraries/entities/src/EntityItemID.h        |  1 +
 libraries/shared/src/RegisteredMetaTypes.cpp | 15 ---------------
 libraries/shared/src/RegisteredMetaTypes.h   |  2 --
 4 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/libraries/entities/src/EntityItemID.cpp b/libraries/entities/src/EntityItemID.cpp
index 36664f5457..1462a4ef88 100644
--- a/libraries/entities/src/EntityItemID.cpp
+++ b/libraries/entities/src/EntityItemID.cpp
@@ -52,3 +52,19 @@ QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID
 void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& id) {
     quuidFromScriptValue(object, id);
 }
+
+QVector<EntityItemID> qVectorEntityItemIDFromScriptValue(const QScriptValue& array) {
+    if (!array.isArray()) {
+        return QVector<EntityItemID>();
+    }
+    QVector<EntityItemID> newVector;
+    int length = array.property("length").toInteger();
+    newVector.reserve(length);
+    for (int i = 0; i < length; i++) {
+        QString uuidAsString = array.property(i).toString();
+        EntityItemID fromString(uuidAsString);
+        newVector << fromString;
+    }
+    return newVector;
+}
+
diff --git a/libraries/entities/src/EntityItemID.h b/libraries/entities/src/EntityItemID.h
index 765082ef0b..41a11147f8 100644
--- a/libraries/entities/src/EntityItemID.h
+++ b/libraries/entities/src/EntityItemID.h
@@ -43,5 +43,6 @@ Q_DECLARE_METATYPE(EntityItemID);
 Q_DECLARE_METATYPE(QVector<EntityItemID>);
 QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& properties);
 void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& properties);
+QVector<EntityItemID> qVectorEntityItemIDFromScriptValue(const QScriptValue& array);
 
 #endif // hifi_EntityItemID_h
diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp
index 016c99a8dc..008ac238d5 100644
--- a/libraries/shared/src/RegisteredMetaTypes.cpp
+++ b/libraries/shared/src/RegisteredMetaTypes.cpp
@@ -118,21 +118,6 @@ QVector<QUuid> qVectorQUuidFromScriptValue(const QScriptValue& array) {
     return newVector;
 }
 
-QVector<EntityItemID> qVectorEntityItemIDFromScriptValue(const QScriptValue& array) {
-    if (!array.isArray()) {
-        return QVector<EntityItemID>();
-    }
-    QVector<EntityItemID> newVector;
-    int length = array.property("length").toInteger();
-    newVector.reserve(length);
-    for (int i = 0; i < length; i++) {
-        QString uuidAsString = array.property(i).toString();
-        EntityItemID fromString(uuidAsString);
-        newVector << fromString;
-    }
-    return newVector;
-}
-
 QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector<float>& vector) {
     QScriptValue array = engine->newArray();
     for (int i = 0; i < vector.size(); i++) {
diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h
index 8e53f0ee37..cd1e3b0d3e 100644
--- a/libraries/shared/src/RegisteredMetaTypes.h
+++ b/libraries/shared/src/RegisteredMetaTypes.h
@@ -14,7 +14,6 @@
 
 #include <QtScript/QScriptEngine>
 #include <QtCore/QUuid>
-#include "../../entities/src/EntityItemID.h"
 
 #include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
@@ -67,7 +66,6 @@ void qVectorFloatFromScriptValue(const QScriptValue& array, QVector<float>& vect
 QVector<float> qVectorFloatFromScriptValue(const QScriptValue& array);
 
 QVector<QUuid> qVectorQUuidFromScriptValue(const QScriptValue& array);
-QVector<EntityItemID> qVectorEntityItemIDFromScriptValue(const QScriptValue& array);
 
 class PickRay {
 public:

From 6bd1e593059cf45740cb4dadab4681c57744fe95 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 21 Oct 2015 14:31:44 -0700
Subject: [PATCH 084/301] fix CR feedback

---
 libraries/controllers/src/controllers/Pose.cpp | 4 ++--
 libraries/controllers/src/controllers/Pose.h   | 4 +++-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp
index 9cb33bc777..2281fc98ff 100644
--- a/libraries/controllers/src/controllers/Pose.cpp
+++ b/libraries/controllers/src/controllers/Pose.cpp
@@ -6,8 +6,8 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include <QScriptEngine>
-#include <QScriptValue>
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptValue>
 
 #include <RegisteredMetaTypes.h>
 
diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h
index b792b0e901..3d0f716087 100644
--- a/libraries/controllers/src/controllers/Pose.h
+++ b/libraries/controllers/src/controllers/Pose.h
@@ -11,7 +11,9 @@
 #ifndef hifi_controllers_Pose_h
 #define hifi_controllers_Pose_h
 
-#include <QScriptValue>
+class QScriptEngine;
+class QScriptValue;
+
 #include <GLMHelpers.h>
 
 namespace controller {

From b9b03bd842e03a60ba447c4039c2583b08bc1e33 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 21 Oct 2015 14:31:22 -0700
Subject: [PATCH 085/301] Working on conditional and filter parsing

---
 interface/resources/controllers/hydra.json    |   4 +-
 .../resources/controllers/standard-old.json   |  43 ++
 interface/resources/controllers/standard.json |  31 +-
 interface/resources/qml/TestControllers.qml   |  53 +--
 .../resources/qml/controller/AnalogButton.qml |   2 +-
 .../resources/qml/controller/AnalogStick.qml  |   6 +-
 .../resources/qml/controller/ToggleButton.qml |  12 +-
 interface/resources/qml/controller/Xbox.qml   |  15 +
 .../src/controllers/Conditional.cpp           |  10 -
 .../controllers/src/controllers/Conditional.h |  10 -
 .../controllers/src/controllers/Endpoint.h    |  25 +-
 libraries/controllers/src/controllers/Input.h |   1 +
 libraries/controllers/src/controllers/Pose.h  |   1 +
 .../src/controllers/UserInputMapper.cpp       | 429 +++++++++++++-----
 .../src/controllers/UserInputMapper.h         |  22 +-
 15 files changed, 453 insertions(+), 211 deletions(-)
 create mode 100644 interface/resources/controllers/standard-old.json

diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json
index c20d54b7c1..20d954932a 100644
--- a/interface/resources/controllers/hydra.json
+++ b/interface/resources/controllers/hydra.json
@@ -1,10 +1,10 @@
 {
     "name": "Hydra to Standard",
     "channels": [
-        { "from": "Hydra.LY", "to": "Standard.LY" }, 
+        { "from": "Hydra.LY", "filters": "invert", "to": "Standard.LY" }, 
         { "from": "Hydra.LX", "to": "Standard.LX" },
         { "from": "Hydra.LT", "to": "Standard.LT" }, 
-        { "from": "Hydra.RY", "to": "Standard.RY" }, 
+        { "from": "Hydra.RY", "filters": "invert", "to": "Standard.RY" }, 
         { "from": "Hydra.RX", "to": "Standard.RX" },
         { "from": "Hydra.RT", "to": "Standard.RT" }, 
 
diff --git a/interface/resources/controllers/standard-old.json b/interface/resources/controllers/standard-old.json
new file mode 100644
index 0000000000..b662e5394d
--- /dev/null
+++ b/interface/resources/controllers/standard-old.json
@@ -0,0 +1,43 @@
+{
+    "name": "Standard to Action",
+    "channels": [
+        { "from": "Standard.LY", "to": "Actions.TranslateZ" },
+        { "from": "Standard.LX", "to": "Actions.TranslateX" },
+        { "from": "Standard.RX", "to": "Actions.Yaw" },
+        { "from": "Standard.RY", "to": "Actions.Pitch" },
+        {
+            "from": "Standard.DU", 
+            "to": "Actions.LONGITUDINAL_FORWARD",
+            "filters": [ { "type": "scale", "scale": 0.5 } ]
+        },
+        { 
+            "from": "Standard.DD", 
+            "to": "Actions.LONGITUDINAL_BACKWARD",
+            "filters": [ { "type": "scale", "scale": 0.5 } ]
+        },
+        { 
+            "from": "Standard.DR", 
+            "to": "Actions.LATERAL_RIGHT",
+            "filters": [ { "type": "scale", "scale": 0.5 } ]
+        },
+        { 
+            "from": "Standard.DL", 
+            "to": "Actions.LATERAL_LEFT",
+            "filters": [ { "type": "scale", "scale": 0.5 } ]
+        },
+        { "from": "Standard.Y", "to": "Actions.VERTICAL_UP" },
+        { "from": "Standard.X", "to": "Actions.VERTICAL_DOWN" },
+        { 
+            "from": "Standard.RT", 
+            "to": "Actions.BOOM_IN", 
+            "filters": [ { "type": "scale", "scale": 0.1 } ]
+        },
+        { 
+            "from": "Standard.LT", 
+            "to": "Actions.BOOM_OUT", 
+            "filters": [ { "type": "scale", "scale": 0.1 } ]
+        },
+        { "from": "Standard.LeftHand", "to": "Actions.LEFT_HAND" }, 
+        { "from": "Standard.RightHand", "to": "Actions.RIGHT_HAND" }
+    ]
+}
diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index b662e5394d..ef6668ec07 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -5,38 +5,25 @@
         { "from": "Standard.LX", "to": "Actions.TranslateX" },
         { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
-        {
-            "from": "Standard.DU", 
-            "to": "Actions.LONGITUDINAL_FORWARD",
-            "filters": [ { "type": "scale", "scale": 0.5 } ]
-        },
-        { 
-            "from": "Standard.DD", 
-            "to": "Actions.LONGITUDINAL_BACKWARD",
-            "filters": [ { "type": "scale", "scale": 0.5 } ]
-        },
-        { 
-            "from": "Standard.DR", 
-            "to": "Actions.LATERAL_RIGHT",
-            "filters": [ { "type": "scale", "scale": 0.5 } ]
-        },
-        { 
-            "from": "Standard.DL", 
-            "to": "Actions.LATERAL_LEFT",
-            "filters": [ { "type": "scale", "scale": 0.5 } ]
-        },
-        { "from": "Standard.Y", "to": "Actions.VERTICAL_UP" },
-        { "from": "Standard.X", "to": "Actions.VERTICAL_DOWN" },
+
+        { "from": [ "Standard.DU", "Standard.DU", "Standard.DU", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
+        { "from": "Standard.Back", "to": "Standard.LeftSecondaryThumb" },
+
+        { "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" },
+        { "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" },
+
         { 
             "from": "Standard.RT", 
             "to": "Actions.BOOM_IN", 
             "filters": [ { "type": "scale", "scale": 0.1 } ]
         },
+
         { 
             "from": "Standard.LT", 
             "to": "Actions.BOOM_OUT", 
             "filters": [ { "type": "scale", "scale": 0.1 } ]
         },
+
         { "from": "Standard.LeftHand", "to": "Actions.LEFT_HAND" }, 
         { "from": "Standard.RightHand", "to": "Actions.RIGHT_HAND" }
     ]
diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index e409b7a4a4..71a836f2e4 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -183,32 +183,33 @@ HifiControls.VrDialog {
             Xbox { device: root.xbox; label: "XBox"; width: 360 }
             Hydra { device: root.hydra; width: 360 }
         }
-//        Row {
-//            spacing: 8
-//            ScrollingGraph {
-//                controlId: Controller.Actions.Yaw
-//                label: "Yaw"
-//                min: -3.0
-//                max: 3.0
-//                size: 128
-//            }
-//
-//            ScrollingGraph {
-//                controlId: Controller.Actions.YAW_LEFT
-//                label: "Yaw Left"
-//                min: -3.0
-//                max: 3.0
-//                size: 128
-//            }
-//
-//            ScrollingGraph {
-//                controlId: Controller.Actions.YAW_RIGHT
-//                label: "Yaw Right"
-//                min: -3.0
-//                max: 3.0
-//                size: 128
-//            }
-//        }
+        
+        Row {
+            spacing: 8
+            ScrollingGraph {
+                controlId: Controller.Actions.Yaw
+                label: "Yaw"
+                min: -3.0
+                max: 3.0
+                size: 128
+            }
+
+            ScrollingGraph {
+                controlId: Controller.Actions.YAW_LEFT
+                label: "Yaw Left"
+                min: -3.0
+                max: 3.0
+                size: 128
+            }
+
+            ScrollingGraph {
+                controlId: Controller.Actions.YAW_RIGHT
+                label: "Yaw Right"
+                min: -3.0
+                max: 3.0
+                size: 128
+            }
+        }
     }
 } // dialog
 
diff --git a/interface/resources/qml/controller/AnalogButton.qml b/interface/resources/qml/controller/AnalogButton.qml
index d027332d42..82beb818ab 100644
--- a/interface/resources/qml/controller/AnalogButton.qml
+++ b/interface/resources/qml/controller/AnalogButton.qml
@@ -13,7 +13,7 @@ Item {
     property color color: 'black'
 
     function update() {
-        value = Controller.getValue(controlId);
+        value = controlId ? Controller.getValue(controlId) : 0;
         canvas.requestPaint();
     }
 
diff --git a/interface/resources/qml/controller/AnalogStick.qml b/interface/resources/qml/controller/AnalogStick.qml
index 499e0e9ce9..c0d10bac59 100644
--- a/interface/resources/qml/controller/AnalogStick.qml
+++ b/interface/resources/qml/controller/AnalogStick.qml
@@ -17,8 +17,8 @@ Item {
 
     function update() {
         value = Qt.vector2d(
-            Controller.getValue(controlIds[0]),
-            Controller.getValue(controlIds[1])
+            controlIds[0] ? Controller.getValue(controlIds[0]) : 0,
+            controlIds[1] ? Controller.getValue(controlIds[1]) : 0
         );
         if (root.invertY) {
             value.y = value.y * -1.0
@@ -27,7 +27,7 @@ Item {
     }
 
     Timer {
-        interval: 50; running: true; repeat: true
+        interval: 50; running: controlIds; repeat: true
         onTriggered: root.update()
     }
 
diff --git a/interface/resources/qml/controller/ToggleButton.qml b/interface/resources/qml/controller/ToggleButton.qml
index 6481045dd0..ee8bd380e2 100644
--- a/interface/resources/qml/controller/ToggleButton.qml
+++ b/interface/resources/qml/controller/ToggleButton.qml
@@ -12,12 +12,14 @@ Item {
     property real value: 0
     property color color: 'black'
 
+    function update() {
+        value = controlId ? Controller.getValue(controlId) : 0;
+        canvas.requestPaint();
+    }
+
     Timer {
-        interval: 50; running: true; repeat: true
-        onTriggered: {
-            root.value = Controller.getValue(root.controlId);
-            canvas.requestPaint();
-        }
+        interval: 50; running: root.controlId; repeat: true
+        onTriggered: root.update()
     }
 
     Canvas {
diff --git a/interface/resources/qml/controller/Xbox.qml b/interface/resources/qml/controller/Xbox.qml
index 4ff2959129..def2cf6fe8 100644
--- a/interface/resources/qml/controller/Xbox.qml
+++ b/interface/resources/qml/controller/Xbox.qml
@@ -100,5 +100,20 @@ Item {
             width: 16 * root.scale; height: 12 * root.scale
             x: (177 * root.scale); y: (45 * root.scale)
         }
+        
+        // Left primary
+        ToggleButton {
+            x: 0; y: parent.height - height; 
+            controlId: root.device.LeftPrimaryThumb
+            width: 16 * root.scale; height: 16 * root.scale
+        }
+
+        // Left primary
+        ToggleButton {
+            x: parent.width - width; y: parent.height - height; 
+            controlId: root.device.RightPrimaryThumb
+            width: 16 * root.scale; height: 16 * root.scale
+        }
+
     }
 }
diff --git a/libraries/controllers/src/controllers/Conditional.cpp b/libraries/controllers/src/controllers/Conditional.cpp
index 7173c80b76..00e42870e4 100644
--- a/libraries/controllers/src/controllers/Conditional.cpp
+++ b/libraries/controllers/src/controllers/Conditional.cpp
@@ -18,14 +18,4 @@ namespace controller {
         return Conditional::Pointer();
     }
 
-    bool EndpointConditional::satisfied() { 
-        if (!_endpoint) {
-            return false;
-        }
-        auto value = _endpoint->value();
-        if (value == 0.0f) {
-            return false;
-        }
-        return true;
-    }
 }
diff --git a/libraries/controllers/src/controllers/Conditional.h b/libraries/controllers/src/controllers/Conditional.h
index d0226d5775..4d67d2871e 100644
--- a/libraries/controllers/src/controllers/Conditional.h
+++ b/libraries/controllers/src/controllers/Conditional.h
@@ -17,8 +17,6 @@
 
 #include <shared/Factory.h>
 
-#include "Endpoint.h"
-
 class QJsonValue;
 
 namespace controller {
@@ -41,14 +39,6 @@ namespace controller {
         static Factory _factory;
     };
 
-    class EndpointConditional : public Conditional {
-    public:
-        EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) { }
-        virtual bool satisfied() override;
-    private:
-        Endpoint::Pointer _endpoint;
-    };
-
 }
 
 #define REGISTER_CONDITIONAL_CLASS(classEntry) \
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index 5d529ace30..7a94b06e7e 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -40,9 +40,12 @@ namespace controller {
         virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
         virtual Pose pose() { return Pose(); }
         virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) {}
-
         virtual const bool isPose() { return _input.isPose(); }
 
+        virtual bool writeable() const { return true; }
+        virtual bool readable() const { return true; }
+        virtual void reset() { }
+
         const Input& getInput() { return _input;  }
 
     protected:
@@ -61,6 +64,26 @@ namespace controller {
         ReadLambda _readLambda;
         WriteLambda _writeLambda;
     };
+
+
+    class VirtualEndpoint : public Endpoint {
+    public:
+        VirtualEndpoint(const Input& id = Input::INVALID_INPUT)
+            : Endpoint(id) {
+        }
+
+        virtual float value() override { return _currentValue; }
+        virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; }
+
+        virtual Pose pose() override { return _currentPose; }
+        virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
+            _currentPose = newValue;
+        }
+    protected:
+        float _currentValue { 0.0f };
+        Pose _currentPose {};
+    };
+
 }
 
 #endif
diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h
index 98377b7434..6f997c9f91 100644
--- a/libraries/controllers/src/controllers/Input.h
+++ b/libraries/controllers/src/controllers/Input.h
@@ -55,6 +55,7 @@ struct Input {
     Input(const Input& src) : id(src.id) {}
     Input& operator = (const Input& src) { id = src.id; return (*this); }
     bool operator ==(const Input& right) const { return INVALID_INPUT.id != id && INVALID_INPUT.id != right.id && id == right.id; }
+    bool operator !=(const Input& right) const { return !(*this == right); }
     bool operator < (const Input& src) const { return id < src.id; }
 
     static const Input INVALID_INPUT;
diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h
index 9243ceb734..f0f9fbc012 100644
--- a/libraries/controllers/src/controllers/Pose.h
+++ b/libraries/controllers/src/controllers/Pose.h
@@ -30,6 +30,7 @@ namespace controller {
         Pose(const Pose&) = default;
         Pose& operator = (const Pose&) = default;
         bool operator ==(const Pose& right) const;
+        bool operator !=(const Pose& right) const { return !(*this == right); }
         bool isValid() const { return valid; }
         vec3 getTranslation() const { return translation; }
         quat getRotation() const { return rotation; }
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 6ef64fc784..ed688a47aa 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -55,22 +55,45 @@ private:
     float _lastValue = 0.0f;
 };
 
-class VirtualEndpoint : public Endpoint {
+class StandardEndpoint : public VirtualEndpoint {
 public:
-    VirtualEndpoint(const Input& id = Input::INVALID_INPUT)
-        : Endpoint(id) {
+    StandardEndpoint(const Input& input) : VirtualEndpoint(input) {}
+    virtual bool writeable() const override { return !_written; }
+    virtual bool readable() const override { return !_read; }
+    virtual void reset() override { 
+        apply(0.0f, 0.0f, Endpoint::Pointer());
+        apply(Pose(), Pose(), Endpoint::Pointer());
+        _written = _read = false;
     }
 
-    virtual float value() override { return _currentValue; }
-    virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; }
+    virtual float value() override { 
+        _read = true;
+        return VirtualEndpoint::value();
+    }
+
+    virtual void apply(float newValue, float oldValue, const Pointer& source) override { 
+        // For standard endpoints, the first NON-ZERO write counts.  
+        if (newValue != 0.0) {
+            _written = true;
+        }
+        VirtualEndpoint::apply(newValue, oldValue, source);
+    }
+
+    virtual Pose pose() override { 
+        _read = true;
+        return VirtualEndpoint::pose();
+    }
 
-    virtual Pose pose() override { return _currentPose; }
     virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
-        _currentPose = newValue;
+        if (newValue != Pose()) {
+            _written = true;
+        }
+        VirtualEndpoint::apply(newValue, oldValue, source);
     }
+
 private:
-    float _currentValue{ 0.0f };
-    Pose _currentPose{};
+    bool _written { false };
+    bool _read { false };
 };
 
 
@@ -136,12 +159,67 @@ public:
     virtual void apply(float newValue, float oldValue, const Pointer& source) {
         // Composites are read only
     }
-
-private:
-    Endpoint::Pointer _first;
-    Endpoint::Pointer _second;
 };
 
+class ArrayEndpoint : public Endpoint {
+    friend class UserInputMapper;
+public:
+    using Pointer = std::shared_ptr<ArrayEndpoint>;
+    ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
+
+    virtual float value() override {
+        return 0.0;
+    }
+
+    virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
+        for (auto& child : _children) {
+            if (child->writeable()) {
+                child->apply(newValue, oldValue, source);
+            }
+        }
+    }
+
+    virtual bool readable() const override { return false; }
+
+private:
+    Endpoint::List _children;
+};
+
+class AnyEndpoint : public Endpoint {
+    friend class UserInputMapper;
+public:
+    using Pointer = std::shared_ptr<AnyEndpoint>;
+    AnyEndpoint() : Endpoint(Input::INVALID_INPUT) {}
+
+    virtual float value() override {
+        float result = 0;
+        for (auto& child : _children) {
+            float childResult = child->value();
+            if (childResult != 0.0f) {
+                result = childResult;
+            }
+        }
+        return result;
+    }
+
+    virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
+        qFatal("AnyEndpoint is read only");
+    }
+
+    virtual bool writeable() const override { return false; }
+
+    virtual bool readable() const override { 
+        for (auto& child : _children) {
+            if (!child->readable()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+private:
+    Endpoint::List _children;
+};
 
 class InputEndpoint : public Endpoint {
 public:
@@ -150,40 +228,44 @@ public:
     }
 
     virtual float value() override {
-        _currentValue = 0.0f;
+        _read = true;
         if (isPose()) {
-            return _currentValue;
+            return pose().valid ? 1.0f : 0.0f;
         }
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
         auto deviceProxy = userInputMapper->getDeviceProxy(_input);
         if (!deviceProxy) {
-            return _currentValue;
+            return 0.0f;
         }
-        _currentValue = deviceProxy->getValue(_input, 0);
-        return _currentValue;
+        return deviceProxy->getValue(_input, 0);
     }
+
+    // FIXME need support for writing back to vibration / force feedback effects
     virtual void apply(float newValue, float oldValue, const Pointer& source) override {}
 
     virtual Pose pose() override {
-        _currentPose = Pose();
+        _read = true;
         if (!isPose()) {
-            return _currentPose;
+            return Pose();
         }
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
         auto deviceProxy = userInputMapper->getDeviceProxy(_input);
         if (!deviceProxy) {
-            return _currentPose;
+            return Pose();
         }
-        _currentPose = deviceProxy->getPose(_input, 0);
-        return _currentPose;
+        return deviceProxy->getPose(_input, 0);
     }
 
-    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
-    }
+    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
+
+    virtual bool writeable() const { return !_written; }
+    virtual bool readable() const { return !_read; }
+    virtual void reset() { _written = _read = false; }
 
 private:
-    float _currentValue{ 0.0f };
-    Pose _currentPose{};
+
+    bool _written { false };
+    bool _read { false };
 };
 
 class ActionEndpoint : public Endpoint {
@@ -194,9 +276,8 @@ public:
 
     virtual float value() override { return _currentValue; }
     virtual void apply(float newValue, float oldValue, const Pointer& source) override {
-
         _currentValue += newValue;
-        if (!(_input == Input::INVALID_INPUT)) {
+        if (_input != Input::INVALID_INPUT) {
             auto userInputMapper = DependencyManager::get<UserInputMapper>();
             userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
         }
@@ -208,12 +289,17 @@ public:
         if (!_currentPose.isValid()) {
             return;
         }
-        if (!(_input == Input::INVALID_INPUT)) {
+        if (_input != Input::INVALID_INPUT) {
             auto userInputMapper = DependencyManager::get<UserInputMapper>();
             userInputMapper->setActionState(Action(_input.getChannel()), _currentPose);
         }
     }
 
+    virtual void reset() override {
+        _currentValue = 0.0f;
+        _currentPose = Pose();
+    }
+
 private:
     float _currentValue{ 0.0f };
     Pose _currentPose{};
@@ -254,7 +340,7 @@ void UserInputMapper::registerDevice(InputDevice* device) {
         }
         Endpoint::Pointer endpoint;
         if (input.device == STANDARD_DEVICE) {
-             endpoint = std::make_shared<VirtualEndpoint>(input);
+            endpoint = std::make_shared<StandardEndpoint>(input);
         } else if (input.device == ACTIONS_DEVICE) {
             endpoint = std::make_shared<ActionEndpoint>(input);
         } else {
@@ -396,20 +482,7 @@ void UserInputMapper::update(float deltaTime) {
     }
 
     // Run the mappings code
-    update();
-
-    // Scale all the channel step with the scale
-    for (auto i = 0; i < toInt(Action::NUM_ACTIONS); i++) {
-        if (_externalActionStates[i] != 0) {
-            _actionStates[i] += _externalActionStates[i];
-            _externalActionStates[i] = 0.0f;
-        }
-
-        if (_externalPoseStates[i].isValid()) {
-            _poseStates[i] = _externalPoseStates[i];
-            _externalPoseStates[i] = Pose();
-        }
-    }
+    runMappings();
 
     // merge the bisected and non-bisected axes for now
     fixBisectedAxis(_actionStates[toInt(Action::TRANSLATE_X)], _actionStates[toInt(Action::LATERAL_LEFT)], _actionStates[toInt(Action::LATERAL_RIGHT)]);
@@ -419,7 +492,6 @@ void UserInputMapper::update(float deltaTime) {
     fixBisectedAxis(_actionStates[toInt(Action::ROTATE_Y)], _actionStates[toInt(Action::YAW_LEFT)], _actionStates[toInt(Action::YAW_RIGHT)]);
     fixBisectedAxis(_actionStates[toInt(Action::ROTATE_X)], _actionStates[toInt(Action::PITCH_UP)], _actionStates[toInt(Action::PITCH_DOWN)]);
 
-
     static const float EPSILON = 0.01f;
     for (auto i = 0; i < toInt(Action::NUM_ACTIONS); i++) {
         _actionStates[i] *= _actionScales[i];
@@ -561,53 +633,62 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
     return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
 }
 
-void UserInputMapper::update() {
+void UserInputMapper::runMappings() {
     static auto deviceNames = getDeviceNames();
-    _overrideValues.clear();
+    _overrides.clear();
 
-    EndpointSet readEndpoints;
-    EndpointSet writtenEndpoints;
+    for (auto endpointEntry : this->_endpointsByInput) {
+        endpointEntry.second->reset();
+    }
 
     // Now process the current values for each level of the stack
     for (auto& mapping : _activeMappings) {
         for (const auto& route : mapping->routes) {
-            const auto& source = route->source;
-            // Endpoints can only be read once (though a given mapping can route them to 
-            // multiple places).  Consider... If the default is to wire the A button to JUMP
-            // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
-            // I press the button.  The exception is if I'm wiring a control back to itself
-            // in order to adjust my interface, like inverting the Y axis on an analog stick
-            if (readEndpoints.count(source)) {
-                continue;
-            }
-
-            const auto& destination = route->destination;
-            // THis could happen if the route destination failed to create
-            // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
-            if (!destination) {
-                continue;
-            }
-
-            if (writtenEndpoints.count(destination)) {
-                continue;
-            }
-
             if (route->conditional) {
                 if (!route->conditional->satisfied()) {
                     continue;
                 }
             }
 
-            // Standard controller destinations can only be can only be used once.
-            if (getStandardDeviceID() == destination->getInput().getDevice()) {
-                writtenEndpoints.insert(destination);
+            auto source = route->source;
+            if (_overrides.count(source)) {
+                source = _overrides[source];
+            }
+
+            // Endpoints can only be read once (though a given mapping can route them to 
+            // multiple places).  Consider... If the default is to wire the A button to JUMP
+            // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
+            // I press the button.  The exception is if I'm wiring a control back to itself
+            // in order to adjust my interface, like inverting the Y axis on an analog stick
+            if (!source->readable()) {
+                continue;
+            }
+
+
+            auto input = source->getInput();
+            float value = source->value();
+            if (value != 0.0) {
+                int i = 0;
+            }
+
+            auto destination = route->destination;
+            // THis could happen if the route destination failed to create
+            // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
+            if (!destination) {
+                continue;
+            }
+
+            // FIXME?, should come before or after the override logic?
+            if (!destination->writeable()) {
+                continue;
             }
 
             // Only consume the input if the route isn't a loopback.
             // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
-            bool loopback = source == destination;
-            if (!loopback) {
-                readEndpoints.insert(source);
+            bool loopback = (source->getInput() == destination->getInput()) && (source->getInput() != Input::INVALID_INPUT);
+            // Each time we loop back we re-write the override 
+            if (loopback) {
+                _overrides[source] = destination = std::make_shared<StandardEndpoint>(source->getInput());
             }
 
             // Fetch the value, may have been overriden by previous loopback routes
@@ -624,14 +705,11 @@ void UserInputMapper::update() {
                     value = filter->apply(value);
                 }
 
-                if (loopback) {
-                    _overrideValues[source] = value;
-                } else {
-                    destination->apply(value, 0, source);
-                }
+                destination->apply(value, 0, source);
             }
         }
     }
+
 }
 
 Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) {
@@ -741,9 +819,9 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
 }
 
 float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const {
-    auto valuesIterator = _overrideValues.find(endpoint);
-    if (_overrideValues.end() != valuesIterator) {
-        return valuesIterator->second;
+    auto valuesIterator = _overrides.find(endpoint);
+    if (_overrides.end() != valuesIterator) {
+        return valuesIterator->second->value();
     }
 
     return endpoint->value();
@@ -787,27 +865,70 @@ Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) {
     return parseMapping(json);
 }
 
-
-const QString JSON_NAME = QStringLiteral("name");
-const QString JSON_CHANNELS = QStringLiteral("channels");
-const QString JSON_CHANNEL_FROM = QStringLiteral("from");
-const QString JSON_CHANNEL_WHEN = QStringLiteral("when");
-const QString JSON_CHANNEL_TO = QStringLiteral("to");
-const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
+static const QString JSON_NAME = QStringLiteral("name");
+static const QString JSON_CHANNELS = QStringLiteral("channels");
+static const QString JSON_CHANNEL_FROM = QStringLiteral("from");
+static const QString JSON_CHANNEL_WHEN = QStringLiteral("when");
+static const QString JSON_CHANNEL_TO = QStringLiteral("to");
+static const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
 
 Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) {
+    Endpoint::Pointer result;
     if (value.isString()) {
         auto input = findDeviceInput(value.toString());
-        return endpointFor(input);
+        result = endpointFor(input);
     } else if (value.isObject()) {
         // Endpoint is defined as an object, we expect a js function then
         return Endpoint::Pointer();
     }
-    return Endpoint::Pointer();
+
+    if (!result) {
+        qWarning() << "Invalid endpoint definition " << value;
+    }
+    return result;
 }
 
+class AndConditional : public Conditional {
+public:
+    using Pointer = std::shared_ptr<AndConditional>;
+
+    AndConditional(Conditional::List children) : _children(children) { }
+
+    virtual bool satisfied() override {
+        for (auto& conditional : _children) {
+            if (!conditional->satisfied()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+private:
+    Conditional::List _children;
+};
+
+class EndpointConditional : public Conditional {
+public:
+    EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
+    virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
+private:
+    Endpoint::Pointer _endpoint;
+};
+
 Conditional::Pointer UserInputMapper::parseConditional(const QJsonValue& value) {
-    if (value.isString()) {
+    if (value.isArray()) {
+        // Support "when" : [ "GamePad.RB", "GamePad.LB" ]
+        Conditional::List children;
+        for (auto arrayItem : value.toArray()) {
+            Conditional::Pointer childConditional = parseConditional(arrayItem);
+            if (!childConditional) {
+                return Conditional::Pointer();
+            }
+            children.push_back(childConditional);
+        }
+        return std::make_shared<AndConditional>(children);
+    } else if (value.isString()) {
+        // Support "when" : "GamePad.RB"
         auto input = findDeviceInput(value.toString());
         auto endpoint = endpointFor(input);
         if (!endpoint) {
@@ -815,11 +936,85 @@ Conditional::Pointer UserInputMapper::parseConditional(const QJsonValue& value)
         }
 
         return std::make_shared<EndpointConditional>(endpoint);
-    } 
-      
+    }
+
     return Conditional::parse(value);
 }
 
+
+Filter::Pointer UserInputMapper::parseFilter(const QJsonValue& value) {
+    Filter::Pointer result;
+    if (value.isString()) {
+        result = Filter::getFactory().create(value.toString());
+    } else if (value.isObject()) {
+        result = Filter::parse(value.toObject());
+    } 
+
+    if (!result) {
+        qWarning() << "Invalid filter definition " << value;
+    }
+      
+    return result;
+}
+
+
+Filter::List UserInputMapper::parseFilters(const QJsonValue& value) {
+    if (value.isNull()) {
+        return Filter::List();
+    }
+
+    if (value.isArray()) {
+        Filter::List result;
+        auto filtersArray = value.toArray();
+        for (auto filterValue : filtersArray) {
+            Filter::Pointer filter = parseFilter(filterValue);
+            if (!filter) {
+                return Filter::List();
+            }
+            result.push_back(filter);
+        }
+        return result;
+    } 
+
+    Filter::Pointer filter = parseFilter(value);
+    if (!filter) {
+        return Filter::List();
+    }
+    return Filter::List({ filter });
+}
+
+Endpoint::Pointer UserInputMapper::parseDestination(const QJsonValue& value) {
+    if (value.isArray()) {
+        ArrayEndpoint::Pointer result = std::make_shared<ArrayEndpoint>();
+        for (auto arrayItem : value.toArray()) {
+            Endpoint::Pointer destination = parseEndpoint(arrayItem);
+            if (!destination) {
+                return Endpoint::Pointer();
+            }
+            result->_children.push_back(destination);
+        }
+        return result;
+    } 
+    
+    return parseEndpoint(value);
+}
+
+Endpoint::Pointer UserInputMapper::parseSource(const QJsonValue& value) {
+    if (value.isArray()) {
+        AnyEndpoint::Pointer result = std::make_shared<AnyEndpoint>();
+        for (auto arrayItem : value.toArray()) {
+            Endpoint::Pointer destination = parseEndpoint(arrayItem);
+            if (!destination) {
+                return Endpoint::Pointer();
+            }
+            result->_children.push_back(destination);
+        }
+        return result;
+    }
+
+    return parseEndpoint(value);
+}
+
 Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
     if (!value.isObject()) {
         return Route::Pointer();
@@ -827,47 +1022,37 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
 
     const auto& obj = value.toObject();
     Route::Pointer result = std::make_shared<Route>();
-    result->source = parseEndpoint(obj[JSON_CHANNEL_FROM]);
+    result->source = parseSource(obj[JSON_CHANNEL_FROM]);
     if (!result->source) {
         qWarning() << "Invalid route source " << obj[JSON_CHANNEL_FROM];
         return Route::Pointer();
     }
-    result->destination = parseEndpoint(obj[JSON_CHANNEL_TO]);
+
+
+    result->destination = parseDestination(obj[JSON_CHANNEL_TO]);
     if (!result->destination) {
         qWarning() << "Invalid route destination " << obj[JSON_CHANNEL_TO];
         return Route::Pointer();
     }
 
     if (obj.contains(JSON_CHANNEL_WHEN)) {
-        auto when = parseConditional(obj[JSON_CHANNEL_WHEN]);
-        if (!when) {
-            qWarning() << "Invalid route conditional " << obj[JSON_CHANNEL_TO];
+        auto conditionalsValue = obj[JSON_CHANNEL_WHEN];
+        result->conditional = parseConditional(conditionalsValue);
+        if (!result->conditional) {
+            qWarning() << "Invalid route conditionals " << conditionalsValue;
             return Route::Pointer();
         }
-        result->conditional = when;
     }
 
-    const auto& filtersValue = obj[JSON_CHANNEL_FILTERS];
-    // FIXME support strings for filters with no parameters, both in the array and at the top level...
-    // i.e.
-    // { "from": "Standard.DU", "to" : "Actions.LONGITUDINAL_FORWARD", "filters" : "invert" },
-    // and 
-    // { "from": "Standard.DU", "to" : "Actions.LONGITUDINAL_FORWARD", "filters" : [ "invert", "constrainToInteger" ] },
-    if (filtersValue.isArray()) {
-        auto filtersArray = filtersValue.toArray();
-        for (auto filterValue : filtersArray) {
-            if (!filterValue.isObject()) {
-                qWarning() << "Invalid filter " << filterValue;
-                return Route::Pointer();
-            }
-            Filter::Pointer filter = Filter::parse(filterValue.toObject());
-            if (!filter) {
-                qWarning() << "Invalid filter " << filterValue;
-                return Route::Pointer();
-            }
-            result->filters.push_back(filter);
+    if (obj.contains(JSON_CHANNEL_FILTERS)) {
+        auto filtersValue = obj[JSON_CHANNEL_FILTERS];
+        result->filters = parseFilters(filtersValue);
+        if (result->filters.empty()) {
+            qWarning() << "Invalid route filters " << filtersValue;
+            return Route::Pointer();
         }
     }
+
     return result;
 }
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index ec1267cd0c..345bba8c2b 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -50,7 +50,7 @@ namespace controller {
         using MappingStack = std::list<Mapping::Pointer>;
         using InputToEndpointMap = std::map<Input, Endpoint::Pointer>;
         using EndpointSet = std::unordered_set<Endpoint::Pointer>;
-        using ValueMap = std::map<Endpoint::Pointer, float>;
+        using EndpointOverrideMap = std::map<Endpoint::Pointer, Endpoint::Pointer>;
         using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
         using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
         using DevicesMap = std::map<int, DeviceProxy::Pointer>;
@@ -86,9 +86,9 @@ namespace controller {
         int findAction(const QString& actionName) const;
         QVector<QString> getActionNames() const;
 
-        void setActionState(Action action, float value) { _externalActionStates[toInt(action)] = value; }
-        void deltaActionState(Action action, float delta) { _externalActionStates[toInt(action)] += delta; }
-        void setActionState(Action action, const Pose& value) { _externalPoseStates[toInt(action)] = value; }
+        void setActionState(Action action, float value) { _actionStates[toInt(action)] = value; }
+        void deltaActionState(Action action, float delta) { _actionStates[toInt(action)] += delta; }
+        void setActionState(Action action, const Pose& value) { _poseStates[toInt(action)] = value; }
 
         static Input makeStandardInput(controller::StandardButtonChannel button);
         static Input makeStandardInput(controller::StandardAxisChannel axis);
@@ -119,7 +119,7 @@ namespace controller {
         void hardwareChanged();
 
     protected:
-        virtual void update();
+        virtual void runMappings();
         // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
         uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
 
@@ -128,11 +128,9 @@ namespace controller {
         uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
 
         std::vector<float> _actionStates = std::vector<float>(toInt(Action::NUM_ACTIONS), 0.0f);
-        std::vector<float> _externalActionStates = std::vector<float>(toInt(Action::NUM_ACTIONS), 0.0f);
         std::vector<float> _actionScales = std::vector<float>(toInt(Action::NUM_ACTIONS), 1.0f);
         std::vector<float> _lastActionStates = std::vector<float>(toInt(Action::NUM_ACTIONS), 0.0f);
         std::vector<Pose> _poseStates = std::vector<Pose>(toInt(Action::NUM_ACTIONS));
-        std::vector<Pose> _externalPoseStates = std::vector<Pose>(toInt(Action::NUM_ACTIONS));
 
         glm::mat4 _sensorToWorldMat;
 
@@ -148,16 +146,22 @@ namespace controller {
         Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
         Endpoint::Pointer endpointFor(const Input& endpoint) const;
         Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
+        
         Mapping::Pointer parseMapping(const QJsonValue& json);
         Route::Pointer parseRoute(const QJsonValue& value);
-        Conditional::Pointer parseConditional(const QJsonValue& value);
+        Endpoint::Pointer parseDestination(const QJsonValue& value);
+        Endpoint::Pointer parseSource(const QJsonValue& value);
         Endpoint::Pointer parseEndpoint(const QJsonValue& value);
+        Conditional::Pointer parseConditional(const QJsonValue& value);
+
+        static Filter::Pointer parseFilter(const QJsonValue& value);
+        static Filter::List parseFilters(const QJsonValue& value);
 
         InputToEndpointMap _endpointsByInput;
         EndpointToInputMap _inputsByEndpoint;
         EndpointPairMap _compositeEndpoints;
 
-        ValueMap _overrideValues;
+        EndpointOverrideMap _overrides;
         MappingNameMap _mappingsByName;
         Mapping::Pointer _defaultMapping{ std::make_shared<Mapping>("Default") };
         MappingDeviceMap _mappingsByDevice;

From 4a1df286fda6eb0805d52c71cc61518a6d27df7b Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 21 Oct 2015 15:57:37 -0700
Subject: [PATCH 086/301] Cleanup of enums and JS names

---
 interface/resources/qml/TestControllers.qml   |  27 +----
 .../resources/qml/controller/Standard.qml     |  35 ++++++
 interface/resources/qml/controller/Xbox.qml   |  15 ---
 interface/src/devices/3DConnexionClient.cpp   |  50 ++++-----
 interface/src/devices/3DConnexionClient.h     |  18 ++--
 .../controllers/src/controllers/Actions.cpp   | 102 +++++++++++++-----
 .../src/controllers/StandardController.cpp    |   8 +-
 .../src/controllers/StandardControls.h        |   8 +-
 .../input-plugins/ViveControllerManager.cpp   |   4 +-
 9 files changed, 150 insertions(+), 117 deletions(-)
 create mode 100644 interface/resources/qml/controller/Standard.qml

diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index 71a836f2e4..a5deaed159 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -131,27 +131,8 @@ HifiControls.VrDialog {
                 onClicked: {
                     var mapping = Controller.newMapping();
                     // Inverting a value
-                    mapping.from(hydra.RY).invert().to(standard.RY);
-                    mapping.from(hydra.RX).to(standard.RX);
-                    mapping.from(hydra.LY).to(standard.LY);
-                    mapping.from(hydra.LX).to(standard.LX);
-                    // Assigning a value from a function
-                    // mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
-                    // Constrainting a value to -1, 0, or 1, with a deadzone
-//                    mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
+                    mapping.from(standard.RY).invert().to(standard.RY);
                     mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
-//                    mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
-//                    mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
-                    // mapping.modifier(keyboard.Ctrl).scale(2.0)
-//                    mapping.from(keyboard.A).to(actions.TranslateLeft)
-//                    mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
-//                    mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
-//                    // First loopbacks
-//                    // Then non-loopbacks by constraint level (number of inputs)
-//                    mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
-//                    mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
-//                    mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
-//                    mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
                     testMapping = mapping;
                     enabled = false
                     text = "Built"
@@ -175,13 +156,13 @@ HifiControls.VrDialog {
         }
 
         Row {
-            Xbox { device: root.standard; label: "Standard"; width: 360 }
+            Standard { device: root.standard; label: "Standard"; width: 180 }
         }
         
         Row {
             spacing: 8
-            Xbox { device: root.xbox; label: "XBox"; width: 360 }
-            Hydra { device: root.hydra; width: 360 }
+            Xbox { device: root.xbox; label: "XBox"; width: 180 }
+            Hydra { device: root.hydra; width: 180 }
         }
         
         Row {
diff --git a/interface/resources/qml/controller/Standard.qml b/interface/resources/qml/controller/Standard.qml
new file mode 100644
index 0000000000..cee79fe50c
--- /dev/null
+++ b/interface/resources/qml/controller/Standard.qml
@@ -0,0 +1,35 @@
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
+
+import "xbox"
+
+Item {
+    id: root
+    property real aspect: 300.0 / 215.0
+    width: 300
+    height: width / aspect
+    property var device
+    property string label: ""
+    property real scale: width / 300.0 
+
+    Xbox {
+        width: root.width; height: root.height
+        device: root.device
+    }
+
+    // Left primary
+    ToggleButton {
+        x: 0; y: parent.height - height; 
+        controlId: root.device.LeftPrimaryThumb
+        width: 16 * root.scale; height: 16 * root.scale
+    }
+
+    // Left primary
+    ToggleButton {
+        x: parent.width - width; y: parent.height - height; 
+        controlId: root.device.RB
+        width: 16 * root.scale; height: 16 * root.scale
+    }
+}
diff --git a/interface/resources/qml/controller/Xbox.qml b/interface/resources/qml/controller/Xbox.qml
index def2cf6fe8..4ff2959129 100644
--- a/interface/resources/qml/controller/Xbox.qml
+++ b/interface/resources/qml/controller/Xbox.qml
@@ -100,20 +100,5 @@ Item {
             width: 16 * root.scale; height: 12 * root.scale
             x: (177 * root.scale); y: (45 * root.scale)
         }
-        
-        // Left primary
-        ToggleButton {
-            x: 0; y: parent.height - height; 
-            controlId: root.device.LeftPrimaryThumb
-            width: 16 * root.scale; height: 16 * root.scale
-        }
-
-        // Left primary
-        ToggleButton {
-            x: parent.width - width; y: parent.height - height; 
-            controlId: root.device.RightPrimaryThumb
-            width: 16 * root.scale; height: 16 * root.scale
-        }
-
     }
 }
diff --git a/interface/src/devices/3DConnexionClient.cpp b/interface/src/devices/3DConnexionClient.cpp
index 05795e87e9..7c44e4eed7 100755
--- a/interface/src/devices/3DConnexionClient.cpp
+++ b/interface/src/devices/3DConnexionClient.cpp
@@ -33,18 +33,14 @@ ConnexionData::ConnexionData() : InputDevice("ConnexionClient") {}
 
 
 void ConnexionData::handleAxisEvent() {
-    _axisStateMap[makeInput(ROTATION_AXIS_Y_POS).getChannel()] = (cc_rotation.y > 0.0f) ? cc_rotation.y / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(ROTATION_AXIS_Y_NEG).getChannel()] = (cc_rotation.y < 0.0f) ? -cc_rotation.y / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(POSITION_AXIS_X_POS).getChannel()] = (cc_position.x > 0.0f) ? cc_position.x / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(POSITION_AXIS_X_NEG).getChannel()] = (cc_position.x < 0.0f) ? -cc_position.x / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(POSITION_AXIS_Y_POS).getChannel()] = (cc_position.y > 0.0f) ? cc_position.y / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(POSITION_AXIS_Y_NEG).getChannel()] = (cc_position.y < 0.0f) ? -cc_position.y / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(POSITION_AXIS_Z_POS).getChannel()] = (cc_position.z > 0.0f) ? cc_position.z / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(POSITION_AXIS_Z_NEG).getChannel()] = (cc_position.z < 0.0f) ? -cc_position.z / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(ROTATION_AXIS_X_POS).getChannel()] = (cc_rotation.x > 0.0f) ? cc_rotation.x / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(ROTATION_AXIS_X_NEG).getChannel()] = (cc_rotation.x < 0.0f) ? -cc_rotation.x / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(ROTATION_AXIS_Z_POS).getChannel()] = (cc_rotation.z > 0.0f) ? cc_rotation.z / MAX_AXIS : 0.0f;
-    _axisStateMap[makeInput(ROTATION_AXIS_Z_NEG).getChannel()] = (cc_rotation.z < 0.0f) ? -cc_rotation.z / MAX_AXIS : 0.0f;
+    auto rotation = cc_rotation / MAX_AXIS;
+    _axisStateMap[ROTATE_X] = rotation.x; 
+    _axisStateMap[ROTATE_Y] = rotation.y;
+    _axisStateMap[ROTATE_Z] = rotation.z;
+    auto position = cc_rotation / MAX_AXIS;
+    _axisStateMap[TRANSLATE_X] = position.x;
+    _axisStateMap[TRANSLATE_Y] = position.y;
+    _axisStateMap[TRANSLATE_Z] = position.z;
 }
 
 void ConnexionData::setButton(int lastButtonState) {
@@ -57,24 +53,18 @@ void ConnexionData::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
     proxy->getButton = [this](const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
     proxy->getAxis = [this](const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
     proxy->getAvailabeInputs = [this]() -> QVector<controller::Input::NamedPair> {
-        QVector<controller::Input::NamedPair> availableInputs;
-
-        availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_1), "Left button"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_2), "Right button"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_3), "Both buttons"));
-
-        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Y_NEG), "Move backward"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Y_POS), "Move forward"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_X_POS), "Move right"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_X_NEG), "Move Left"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Z_POS), "Move up"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Z_NEG), "Move down"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Y_NEG), "Rotate backward"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Y_POS), "Rotate forward"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_X_POS), "Rotate right"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_X_NEG), "Rotate left"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Z_POS), "Rotate up"));
-        availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Z_NEG), "Rotate down"));
+        using namespace controller;
+        static QVector<controller::Input::NamedPair> availableInputs {
+            Input::NamedPair(makeInput(BUTTON_1), "LeftButton"),
+            Input::NamedPair(makeInput(BUTTON_2), "RightButton"),
+            Input::NamedPair(makeInput(BUTTON_3), "BothButtons"),
+            Input::NamedPair(makeInput(TRANSLATE_X), "TranslateX"),
+            Input::NamedPair(makeInput(TRANSLATE_Y), "TranslateY"),
+            Input::NamedPair(makeInput(TRANSLATE_Z), "TranslateZ"),
+            Input::NamedPair(makeInput(ROTATE_X), "RotateX"),
+            Input::NamedPair(makeInput(ROTATE_Y), "RotateY"),
+            Input::NamedPair(makeInput(ROTATE_Z), "RotateZ"),
+        };
         return availableInputs;
     };
 }
diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h
index 8f66a602a4..8489d54913 100755
--- a/interface/src/devices/3DConnexionClient.h
+++ b/interface/src/devices/3DConnexionClient.h
@@ -182,18 +182,12 @@ public:
     static ConnexionData& getInstance();
     ConnexionData();
     enum PositionChannel {
-        POSITION_AXIS_X_POS = 1,
-        POSITION_AXIS_X_NEG = 2,
-        POSITION_AXIS_Y_POS = 3,
-        POSITION_AXIS_Y_NEG = 4,
-        POSITION_AXIS_Z_POS = 5,
-        POSITION_AXIS_Z_NEG = 6,
-        ROTATION_AXIS_X_POS = 7,
-        ROTATION_AXIS_X_NEG = 8,
-        ROTATION_AXIS_Y_POS = 9,
-        ROTATION_AXIS_Y_NEG = 10,
-        ROTATION_AXIS_Z_POS = 11,
-        ROTATION_AXIS_Z_NEG = 12
+        TRANSLATE_X,
+        TRANSLATE_Y,
+        TRANSLATE_Z,
+        ROTATE_X,
+        ROTATE_Y,
+        ROTATE_Z,
     };
 
     enum ButtonChannel {
diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp
index 78ba42db8b..7954ab5522 100644
--- a/libraries/controllers/src/controllers/Actions.cpp
+++ b/libraries/controllers/src/controllers/Actions.cpp
@@ -12,6 +12,23 @@
 
 namespace controller {
 
+    Input::NamedPair makePair(ChannelType type, Action action, const QString& name) {
+        auto input = Input(UserInputMapper::ACTIONS_DEVICE, toInt(action), type);
+        return Input::NamedPair(input, name);
+    }
+
+    Input::NamedPair makeAxisPair(Action action, const QString& name) {
+        return makePair(ChannelType::AXIS, action, name);
+    }
+
+    Input::NamedPair makeButtonPair(Action action, const QString& name) {
+        return makePair(ChannelType::BUTTON, action, name);
+    }
+
+    Input::NamedPair makePosePair(Action action, const QString& name) {
+        return makePair(ChannelType::POSE, action, name);
+    }
+
     // Device functions
     void ActionsDevice::buildDeviceProxy(DeviceProxy::Pointer proxy) {
         proxy->_name = _name;
@@ -19,33 +36,64 @@ namespace controller {
         proxy->getAxis = [this](const Input& input, int timestamp) -> float { return 0; };
         proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
             QVector<Input::NamedPair> availableInputs{
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::LONGITUDINAL_BACKWARD), ChannelType::AXIS), "LONGITUDINAL_BACKWARD"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::LONGITUDINAL_FORWARD), ChannelType::AXIS), "LONGITUDINAL_FORWARD"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::LATERAL_LEFT), ChannelType::AXIS), "LATERAL_LEFT"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::LATERAL_RIGHT), ChannelType::AXIS), "LATERAL_RIGHT"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::VERTICAL_DOWN), ChannelType::AXIS), "VERTICAL_DOWN"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::VERTICAL_UP), ChannelType::AXIS), "VERTICAL_UP"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::YAW_LEFT), ChannelType::AXIS), "YAW_LEFT"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::YAW_RIGHT), ChannelType::AXIS), "YAW_RIGHT"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::PITCH_DOWN), ChannelType::AXIS), "PITCH_DOWN"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::PITCH_UP), ChannelType::AXIS), "PITCH_UP"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::BOOM_IN), ChannelType::AXIS), "BOOM_IN"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::BOOM_OUT), ChannelType::AXIS), "BOOM_OUT"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::LEFT_HAND), ChannelType::POSE), "LEFT_HAND"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::RIGHT_HAND), ChannelType::POSE), "RIGHT_HAND"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::LEFT_HAND_CLICK), ChannelType::BUTTON), "LEFT_HAND_CLICK"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::RIGHT_HAND_CLICK), ChannelType::BUTTON), "RIGHT_HAND_CLICK"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::SHIFT), ChannelType::BUTTON), "SHIFT"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::ACTION1), ChannelType::BUTTON), "ACTION1"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::ACTION2), ChannelType::BUTTON), "ACTION2"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::CONTEXT_MENU), ChannelType::BUTTON), "CONTEXT_MENU"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::TOGGLE_MUTE), ChannelType::AXIS), "TOGGLE_MUTE"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::TRANSLATE_X), ChannelType::AXIS), "TranslateX"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::TRANSLATE_Y), ChannelType::AXIS), "TranslateY"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::TRANSLATE_Z), ChannelType::AXIS), "TranslateZ"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::ROLL), ChannelType::AXIS), "Roll"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::PITCH), ChannelType::AXIS), "Pitch"),
-                Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, toInt(Action::YAW), ChannelType::AXIS), "Yaw")
+                makeAxisPair(Action::TRANSLATE_X, "TranslateX"),
+                makeAxisPair(Action::TRANSLATE_Y, "TranslateY"),
+                makeAxisPair(Action::TRANSLATE_Z, "TranslateZ"),
+                makeAxisPair(Action::ROLL, "Roll"),
+                makeAxisPair(Action::PITCH, "Pitch"),
+                makeAxisPair(Action::YAW, "Yaw"),
+                makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),
+                makeAxisPair(Action::LONGITUDINAL_FORWARD, "Forward"),
+                makeAxisPair(Action::LATERAL_LEFT, "StrafeLeft"),
+                makeAxisPair(Action::LATERAL_RIGHT, "StrafeRight"),
+                makeAxisPair(Action::VERTICAL_DOWN, "Down"),
+                makeAxisPair(Action::VERTICAL_UP, "Up"),
+                makeAxisPair(Action::YAW_LEFT, "YawLeft"),
+                makeAxisPair(Action::YAW_RIGHT, "YawRight"),
+                makeAxisPair(Action::PITCH_DOWN, "PitchDown"),
+                makeAxisPair(Action::PITCH_UP, "PitchUp"),
+                makeAxisPair(Action::BOOM_IN, "BoomIn"),
+                makeAxisPair(Action::BOOM_OUT, "BoomOut"),
+
+                makePosePair(Action::LEFT_HAND, "LeftHand"),
+                makePosePair(Action::RIGHT_HAND, "RightHand"),
+
+                makeButtonPair(Action::LEFT_HAND_CLICK, "LeftHandClick"),
+                makeButtonPair(Action::RIGHT_HAND_CLICK, "RightHandClick"),
+
+                makeButtonPair(Action::SHIFT, "Shift"),
+                makeButtonPair(Action::ACTION1, "PrimaryAction"),
+                makeButtonPair(Action::ACTION2, "SecondaryAction"),
+                makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"),
+                makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"),
+
+
+                // Deprecated aliases
+                // FIXME remove after we port all scripts
+                makeAxisPair(Action::LONGITUDINAL_BACKWARD, "LONGITUDINAL_BACKWARD"),
+                makeAxisPair(Action::LONGITUDINAL_FORWARD, "LONGITUDINAL_FORWARD"),
+                makeAxisPair(Action::LATERAL_LEFT, "LATERAL_LEFT"),
+                makeAxisPair(Action::LATERAL_RIGHT, "LATERAL_RIGHT"),
+                makeAxisPair(Action::VERTICAL_DOWN, "VERTICAL_DOWN"),
+                makeAxisPair(Action::VERTICAL_UP, "VERTICAL_UP"),
+                makeAxisPair(Action::YAW_LEFT, "YAW_LEFT"),
+                makeAxisPair(Action::YAW_RIGHT, "YAW_RIGHT"),
+                makeAxisPair(Action::PITCH_DOWN, "PITCH_DOWN"),
+                makeAxisPair(Action::PITCH_UP, "PITCH_UP"),
+                makeAxisPair(Action::BOOM_IN, "BOOM_IN"),
+                makeAxisPair(Action::BOOM_OUT, "BOOM_OUT"),
+
+                makePosePair(Action::LEFT_HAND, "LEFT_HAND"),
+                makePosePair(Action::RIGHT_HAND, "RIGHT_HAND"),
+
+                makeButtonPair(Action::LEFT_HAND_CLICK, "LEFT_HAND_CLICK"),
+                makeButtonPair(Action::RIGHT_HAND_CLICK, "RIGHT_HAND_CLICK"),
+
+                makeButtonPair(Action::SHIFT, "SHIFT"),
+                makeButtonPair(Action::ACTION1, "ACTION1"),
+                makeButtonPair(Action::ACTION2, "ACTION2"),
+                makeButtonPair(Action::CONTEXT_MENU, "CONTEXT_MENU"),
+                makeButtonPair(Action::TOGGLE_MUTE, "TOGGLE_MUTE"),
             };
             return availableInputs;
         };
diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index 061fc4ea56..5734174284 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -95,10 +95,10 @@ void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
         availableInputs.append(makePair(DR, "Right"));
 
 
-        availableInputs.append(makePair(LeftPrimaryThumb, "LeftPrimaryThumb"));
-        availableInputs.append(makePair(LeftSecondaryThumb, "LeftSecondaryThumb"));
-        availableInputs.append(makePair(RightPrimaryThumb, "RightPrimaryThumb"));
-        availableInputs.append(makePair(RightSecondaryThumb, "RightSecondaryThumb"));
+        availableInputs.append(makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"));
+        availableInputs.append(makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"));
+        availableInputs.append(makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"));
+        availableInputs.append(makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"));
 
         return availableInputs;
     };
diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h
index 26644e2f38..b051f68c13 100644
--- a/libraries/controllers/src/controllers/StandardControls.h
+++ b/libraries/controllers/src/controllers/StandardControls.h
@@ -37,10 +37,10 @@ namespace controller {
         DR,
 
         // These don't map to SDL types
-        LeftPrimaryThumb,
-        LeftSecondaryThumb,
-        RightPrimaryThumb,
-        RightSecondaryThumb,
+        LEFT_PRIMARY_THUMB,
+        LEFT_SECONDARY_THUMB,
+        RIGHT_PRIMARY_THUMB,
+        RIGHT_SECONDARY_THUMB,
 
         NUM_STANDARD_BUTTONS
     };
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index 66697e8b11..21b7b81173 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -414,10 +414,10 @@ void ViveControllerManager::buildDeviceProxy(controller::DeviceProxy::Pointer pr
 
             makePair(LS, "LS"),
             makePair(RS, "RS"),
+            makePair(LEFT_HAND, "LeftHand"),
+            makePair(RIGHT_HAND, "RightHand"),
         };
 
-        //availableInputs.append(Input::NamedPair(makeInput(LEFT_HAND), "Left Hand"));
-
         //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 0), "Left Button A"));
         //availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button"));
         //availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button"));

From 9b11b2091f4aa6d33202e29829048cdd7be9cd44 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 21 Oct 2015 16:17:11 -0700
Subject: [PATCH 087/301] fix hydra left right arm flip

---
 .../input-plugins/src/input-plugins/SixenseManager.cpp     | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index c9b8ba11ce..3f612a39f3 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -230,7 +230,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
             if (!jointsCaptured) {
                 //  Rotation of Palm
                 glm::quat rotation(data->rot_quat[3], data->rot_quat[0], data->rot_quat[1], data->rot_quat[2]);
-                handlePoseEvent(position, rotation, numActiveControllers - 1);
+                handlePoseEvent(position, rotation, left);
             } else {
                 _poseStateMap.clear();
             }
@@ -384,7 +384,12 @@ void SixenseManager::handleButtonEvent(unsigned int buttons, bool left) {
     }
 }
 
+#include <StreamUtils.h>
+
 void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, bool left) {
+
+    qDebug() << "SixenseManager::handlePoseEvent() position:" << position << "rotation:" << rotation << "left:" << left;
+
 #ifdef HAVE_SIXENSE
     // From ABOVE the sixense coordinate frame looks like this:
     //

From 63e6452630b42836ada2c8d6436102f1bafaef2f Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 21 Oct 2015 16:17:58 -0700
Subject: [PATCH 088/301] fix hydra left right arm flip

---
 libraries/input-plugins/src/input-plugins/SixenseManager.cpp | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 3f612a39f3..3dc983cb34 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -384,12 +384,7 @@ void SixenseManager::handleButtonEvent(unsigned int buttons, bool left) {
     }
 }
 
-#include <StreamUtils.h>
-
 void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, bool left) {
-
-    qDebug() << "SixenseManager::handlePoseEvent() position:" << position << "rotation:" << rotation << "left:" << left;
-
 #ifdef HAVE_SIXENSE
     // From ABOVE the sixense coordinate frame looks like this:
     //

From a3900a954b7e9c1db9a17a0a867a24b73ecf573c Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 21 Oct 2015 17:03:54 -0700
Subject: [PATCH 089/301] expose MyAvatar.leftHandePosition and
 MyAvatar.rightHandPosition to JS

---
 interface/src/avatar/MyAvatar.cpp | 36 +++++++++++++++++++++++++++++++
 interface/src/avatar/MyAvatar.h   | 11 +++++++++-
 2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 5920543dca..7d0f9edaa0 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -524,6 +524,42 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
 }
 
 
+// FIXME - this is super duper dumb... but this is how master works. When you have
+// hydras plugged in, you'll get 4 "palms" but only the number of controllers lifted
+// of the base station are considered active. So when you ask for "left" you get the
+// first active controller. If you have both controllers held up or just the left, that
+// will be correct. But if you lift the right controller, then it will be reported
+// as "left"... you also see this in the avatars hands. 
+const PalmData* MyAvatar::getActivePalm(int palmIndex) const {
+    const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
+    int numberOfPalms = handData->getNumPalms();
+    int numberOfActivePalms = 0;
+    for (int i = 0; i < numberOfPalms; i++) {
+        auto palm = handData->getPalms()[i];
+        if (palm.isActive()) {
+            // if we've reached the requested "active" palm, then we will return it
+            if (numberOfActivePalms == palmIndex) {
+                return &handData->getPalms()[i];
+            }
+            numberOfActivePalms++;
+        }
+    }
+    return NULL;
+}
+
+
+glm::vec3 MyAvatar::getLeftHandPosition() const {
+    const int LEFT_HAND = 0;
+    auto palmData = getActivePalm(LEFT_HAND);
+    return palmData ? palmData->getPosition() : glm::vec3(0.0f);
+}
+
+glm::vec3 MyAvatar::getRightHandPosition() const {
+    const int RIGHT_HAND = 1;
+    auto palmData = getActivePalm(RIGHT_HAND);
+    return palmData ? palmData->getPosition() : glm::vec3(0.0f);
+}
+
 // virtual
 void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
     // don't render if we've been asked to disable local rendering
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 7347419fee..d9ac2db271 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -34,7 +34,6 @@ enum AudioListenerMode {
 };
 Q_DECLARE_METATYPE(AudioListenerMode);
 
-
 class MyAvatar : public Avatar {
     Q_OBJECT
     Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally)
@@ -50,6 +49,10 @@ class MyAvatar : public Avatar {
     Q_PROPERTY(AudioListenerMode CUSTOM READ getAudioListenerModeCustom)
     //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
 
+
+    Q_PROPERTY(glm::vec3 leftHandPosition  READ getLeftHandPosition)
+    Q_PROPERTY(glm::vec3 rightHandPosition  READ getRightHandPosition)
+
 public:
     MyAvatar(RigPointer rig);
     ~MyAvatar();
@@ -136,6 +139,9 @@ public:
 
     Q_INVOKABLE glm::vec3 getTargetAvatarPosition() const { return _targetAvatarPosition; }
 
+    Q_INVOKABLE glm::vec3 getLeftHandPosition() const;
+    Q_INVOKABLE glm::vec3 getRightHandPosition() const;
+
     AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
     void updateLookAtTargetAvatar();
     void clearLookAtTargetAvatar();
@@ -274,6 +280,9 @@ private:
 
     void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
 
+    const PalmData* getActivePalm(int palmIndex) const;
+
+
     // derive avatar body position and orientation from the current HMD Sensor location.
     // results are in sensor space
     glm::mat4 deriveBodyFromHMDSensor() const;

From 68a2985b7abedd08d49c1bfb73abfeae4dca1c83 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 21 Oct 2015 17:14:48 -0700
Subject: [PATCH 090/301] add tip position as well

---
 interface/src/avatar/MyAvatar.cpp | 12 ++++++++++++
 interface/src/avatar/MyAvatar.h   |  4 ++++
 2 files changed, 16 insertions(+)

diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 7d0f9edaa0..5202138147 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -560,6 +560,18 @@ glm::vec3 MyAvatar::getRightHandPosition() const {
     return palmData ? palmData->getPosition() : glm::vec3(0.0f);
 }
 
+glm::vec3 MyAvatar::getLeftHandTipPosition() const {
+    const int LEFT_HAND = 0;
+    auto palmData = getActivePalm(LEFT_HAND);
+    return palmData ? palmData->getTipPosition() : glm::vec3(0.0f);
+}
+
+glm::vec3 MyAvatar::getRightHandTipPosition() const {
+    const int RIGHT_HAND = 1;
+    auto palmData = getActivePalm(RIGHT_HAND);
+    return palmData ? palmData->getTipPosition() : glm::vec3(0.0f);
+}
+
 // virtual
 void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
     // don't render if we've been asked to disable local rendering
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index d9ac2db271..4a0ae514f6 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -52,6 +52,8 @@ class MyAvatar : public Avatar {
 
     Q_PROPERTY(glm::vec3 leftHandPosition  READ getLeftHandPosition)
     Q_PROPERTY(glm::vec3 rightHandPosition  READ getRightHandPosition)
+    Q_PROPERTY(glm::vec3 leftHandTipPosition  READ getLeftHandTipPosition)
+    Q_PROPERTY(glm::vec3 rightHandTipPosition  READ getRightHandTipPosition)
 
 public:
     MyAvatar(RigPointer rig);
@@ -141,6 +143,8 @@ public:
 
     Q_INVOKABLE glm::vec3 getLeftHandPosition() const;
     Q_INVOKABLE glm::vec3 getRightHandPosition() const;
+    Q_INVOKABLE glm::vec3 getLeftHandTipPosition() const;
+    Q_INVOKABLE glm::vec3 getRightHandTipPosition() const;
 
     AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
     void updateLookAtTargetAvatar();

From 637654adeacce63cdd0da4495ec5b609818c7a8f Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 21 Oct 2015 18:40:13 -0700
Subject: [PATCH 091/301] Wiring up step yaw

---
 examples/tests/controllerInterfaceTest.js     |  11 +
 interface/resources/qml/ScrollingGraph.qml    |  12 +-
 interface/resources/qml/TestControllers.qml   | 147 +++---------
 .../resources/qml/controller/Standard.qml     |   2 +-
 .../controllers/src/controllers/Actions.cpp   |   7 +-
 .../controllers/src/controllers/Actions.h     |  10 +
 .../src/controllers/UserInputMapper.cpp       | 211 +++++++++++-------
 .../src/controllers/UserInputMapper.h         |  17 +-
 8 files changed, 210 insertions(+), 207 deletions(-)

diff --git a/examples/tests/controllerInterfaceTest.js b/examples/tests/controllerInterfaceTest.js
index fa8cf48b9b..48ad8f0879 100644
--- a/examples/tests/controllerInterfaceTest.js
+++ b/examples/tests/controllerInterfaceTest.js
@@ -1,4 +1,12 @@
 ControllerTest = function() {
+    var standard = Controller.Standard;
+    var actions = Controller.Actions;
+    this.mappingEnabled = false;
+    this.mapping = Controller.newMapping();
+    this.mapping.from(standard.RX).to(actions.StepYaw);
+    this.mapping.enable();
+    this.mappingEnabled = true;
+
 
     print("Actions");
     for (var prop in Controller.Actions) {
@@ -24,6 +32,9 @@ ControllerTest = function() {
 }
 
 ControllerTest.prototype.onCleanup = function() {
+    if (this.mappingEnabled) {
+        this.mapping.disable();
+    }
 }
 
 
diff --git a/interface/resources/qml/ScrollingGraph.qml b/interface/resources/qml/ScrollingGraph.qml
index b5eaac6f89..26ca9a61ff 100644
--- a/interface/resources/qml/ScrollingGraph.qml
+++ b/interface/resources/qml/ScrollingGraph.qml
@@ -3,12 +3,12 @@ import QtQuick.Controls 1.0
 import QtQuick.Layouts 1.0
 import QtQuick.Dialogs 1.0
 
-Item {
+Rectangle {
     id: root
     property int size: 64
     width: size
     height: size
-
+    color: 'black'
     property int controlId: 0
     property real value: 0.5
     property int scrollWidth: 1
@@ -16,7 +16,7 @@ Item {
     property real max: 1.0
     property bool log: false
     property real range: max - min
-    property color color: 'blue'
+    property color lineColor: 'yellow'
     property bool bar: false
     property real lastHeight: -1
     property string label: ""
@@ -49,19 +49,21 @@ Item {
        Text {
            anchors.top: parent.top
            text: root.label
-
+           color: 'white'
        }
 
        Text {
            anchors.right: parent.right
            anchors.top: parent.top
            text: root.max
+           color: 'white'
        }
 
        Text {
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            text: root.min
+           color: 'white'
        }
 
        function scroll() {
@@ -92,7 +94,7 @@ Item {
 
            ctx.beginPath();
            ctx.lineWidth = 1
-           ctx.strokeStyle = root.color
+           ctx.strokeStyle = root.lineColor
            ctx.moveTo(canvas.width - root.scrollWidth, root.lastHeight).lineTo(canvas.width, currentHeight)
            ctx.stroke()
            ctx.restore()
diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index a5deaed159..f1b8640c02 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -20,8 +20,20 @@ HifiControls.VrDialog {
     property var standard: Controller.Standard
     property var hydra: null
     property var testMapping: null
+    property bool testMappingEnabled: false
     property var xbox: null
 
+    function buildMapping() {
+        testMapping = Controller.newMapping();
+        testMapping.from(standard.RY).invert().to(actions.Pitch);
+        testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
+        testMapping.from(standard.RX).to(actions.StepYaw);
+    }
+
+    function toggleMapping() {
+        testMapping.enable(!testMappingEnabled);
+        testMappingEnabled = !testMappingEnabled;
+    }
 
     Component.onCompleted: {
         enabled = true
@@ -49,110 +61,18 @@ HifiControls.VrDialog {
 
         Row {
             spacing: 8
-            Button {
-                text: "Standard Mapping"
-                onClicked: {
-                    var mapping = Controller.newMapping("Default");
-                    mapping.from(standard.LX).to(actions.TranslateX);
-                    mapping.from(standard.LY).to(actions.TranslateZ);
-                    mapping.from(standard.RY).to(actions.Pitch);
-                    mapping.from(standard.RX).to(actions.Yaw);
-                    mapping.from(standard.DU).scale(0.5).to(actions.LONGITUDINAL_FORWARD);
-                    mapping.from(standard.DD).scale(0.5).to(actions.LONGITUDINAL_BACKWARD);
-                    mapping.from(standard.DL).scale(0.5).to(actions.LATERAL_LEFT);
-                    mapping.from(standard.DR).scale(0.5).to(actions.LATERAL_RIGHT);
-                    mapping.from(standard.X).to(actions.VERTICAL_DOWN);
-                    mapping.from(standard.Y).to(actions.VERTICAL_UP);
-                    mapping.from(standard.RT).scale(0.1).to(actions.BOOM_IN);
-                    mapping.from(standard.LT).scale(0.1).to(actions.BOOM_OUT);
-                    mapping.from(standard.B).to(actions.ACTION1);
-                    mapping.from(standard.A).to(actions.ACTION2);
-                    mapping.from(standard.RB).to(actions.SHIFT);
-                    mapping.from(standard.Back).to(actions.TOGGLE_MUTE);
-                    mapping.from(standard.Start).to(actions.CONTEXT_MENU);
-                    Controller.enableMapping("Default");
-                    enabled = false;
-                    text = "Standard Built"
-                }
-            }
             
             Button {
-                text: root.xbox ? "XBox Mapping" : "XBox not found"
-                property bool built: false
-                enabled: root.xbox && !built
+                text: !root.testMapping ? "Build Mapping" : (root.testMappingEnabled ? "Disable Mapping" : "Enable Mapping")
                 onClicked: {
-                    var mapping = Controller.newMapping();
-                    mapping.from(xbox.A).to(standard.A);
-                    mapping.from(xbox.B).to(standard.B);
-                    mapping.from(xbox.X).to(standard.X);
-                    mapping.from(xbox.Y).to(standard.Y);
-                    mapping.from(xbox.Up).to(standard.DU);
-                    mapping.from(xbox.Down).to(standard.DD);
-                    mapping.from(xbox.Left).to(standard.DL);
-                    mapping.from(xbox.Right).to(standard.Right);
-                    mapping.from(xbox.LB).to(standard.LB);
-                    mapping.from(xbox.RB).to(standard.RB);
-                    mapping.from(xbox.LS).to(standard.LS);
-                    mapping.from(xbox.RS).to(standard.RS);
-                    mapping.from(xbox.Start).to(standard.Start);
-                    mapping.from(xbox.Back).to(standard.Back);
-                    mapping.from(xbox.LY).to(standard.LY);
-                    mapping.from(xbox.LX).to(standard.LX);
-                    mapping.from(xbox.RY).to(standard.RY);
-                    mapping.from(xbox.RX).to(standard.RX);
-                    mapping.from(xbox.LT).to(standard.LT);
-                    mapping.from(xbox.RT).to(standard.RT);
-                    mapping.enable();
-                    built = false;
-                    text = "XBox Built"
+
+                    if (!root.testMapping) {
+                        root.buildMapping()
+                    } else {
+                        root.toggleMapping();
+                    }
                 }
             }
-
-            Button {
-                text: root.hydra ? "Hydra Mapping" : "Hydra Not Found"
-                property bool built: false
-                enabled: root.hydra && !built
-                onClicked: {
-                    var mapping = Controller.newMapping();
-                    mapping.from(hydra.LY).invert().to(standard.LY);
-                    mapping.from(hydra.LX).to(standard.LX);
-                    mapping.from(hydra.RY).invert().to(standard.RY);
-                    mapping.from(hydra.RX).to(standard.RX);
-                    mapping.from(hydra.LT).to(standard.LT);
-                    mapping.from(hydra.RT).to(standard.RT);
-                    mapping.enable();
-                    built = false;
-                    text = "Hydra Built"
-                }
-            }
-
-            Button {
-                text: "Test Mapping"
-                onClicked: {
-                    var mapping = Controller.newMapping();
-                    // Inverting a value
-                    mapping.from(standard.RY).invert().to(standard.RY);
-                    mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
-                    testMapping = mapping;
-                    enabled = false
-                    text = "Built"
-                }
-            }
-
-            Button {
-                text: "Enable Mapping"
-                onClicked: root.testMapping.enable()
-            }
-
-            Button {
-                text: "Disable Mapping"
-                onClicked: root.testMapping.disable()
-            }
-
-            Button {
-                text: "Enable Mapping"
-                onClicked: print(Controller.getValue(root.xbox.LY));
-            }
         }
 
         Row {
@@ -170,25 +90,32 @@ HifiControls.VrDialog {
             ScrollingGraph {
                 controlId: Controller.Actions.Yaw
                 label: "Yaw"
-                min: -3.0
-                max: 3.0
-                size: 128
+                min: -2.0
+                max: 2.0
+                size: 64
             }
 
             ScrollingGraph {
-                controlId: Controller.Actions.YAW_LEFT
+                controlId: Controller.Actions.YawLeft
                 label: "Yaw Left"
-                min: -3.0
-                max: 3.0
-                size: 128
+                min: -2.0
+                max: 2.0
+                size: 64
             }
 
             ScrollingGraph {
-                controlId: Controller.Actions.YAW_RIGHT
+                controlId: Controller.Actions.YawRight
                 label: "Yaw Right"
-                min: -3.0
-                max: 3.0
-                size: 128
+                min: -2.0
+                max: 2.0
+                size: 64
+            }
+            ScrollingGraph {
+                controlId: Controller.Actions.StepYaw
+                label: "StepYaw"
+                min: -2.0
+                max: 2.0
+                size: 64
             }
         }
     }
diff --git a/interface/resources/qml/controller/Standard.qml b/interface/resources/qml/controller/Standard.qml
index cee79fe50c..45e4febfa2 100644
--- a/interface/resources/qml/controller/Standard.qml
+++ b/interface/resources/qml/controller/Standard.qml
@@ -29,7 +29,7 @@ Item {
     // Left primary
     ToggleButton {
         x: parent.width - width; y: parent.height - height; 
-        controlId: root.device.RB
+        controlId: root.device.RightPrimaryThumb
         width: 16 * root.scale; height: 16 * root.scale
     }
 }
diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp
index 7954ab5522..b0d2d24edf 100644
--- a/libraries/controllers/src/controllers/Actions.cpp
+++ b/libraries/controllers/src/controllers/Actions.cpp
@@ -42,6 +42,12 @@ namespace controller {
                 makeAxisPair(Action::ROLL, "Roll"),
                 makeAxisPair(Action::PITCH, "Pitch"),
                 makeAxisPair(Action::YAW, "Yaw"),
+                makeAxisPair(Action::STEP_YAW, "StepYaw"),
+                makeAxisPair(Action::STEP_PITCH, "StepPitch"),
+                makeAxisPair(Action::STEP_ROLL, "StepRoll"),
+                makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateX"),
+                makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateY"),
+                makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateZ"),
                 makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),
                 makeAxisPair(Action::LONGITUDINAL_FORWARD, "Forward"),
                 makeAxisPair(Action::LATERAL_LEFT, "StrafeLeft"),
@@ -67,7 +73,6 @@ namespace controller {
                 makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"),
                 makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"),
 
-
                 // Deprecated aliases
                 // FIXME remove after we port all scripts
                 makeAxisPair(Action::LONGITUDINAL_BACKWARD, "LONGITUDINAL_BACKWARD"),
diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h
index 77a772de9e..47f04141f3 100644
--- a/libraries/controllers/src/controllers/Actions.h
+++ b/libraries/controllers/src/controllers/Actions.h
@@ -27,6 +27,16 @@ enum class Action {
     ROTATE_Y, YAW = ROTATE_Y,
     ROTATE_Z, ROLL = ROTATE_Z,
 
+    STEP_YAW,
+    // FIXME does this have a use case?
+    STEP_PITCH,
+    // FIXME does this have a use case?
+    STEP_ROLL,
+
+    STEP_TRANSLATE_X,
+    STEP_TRANSLATE_Y,
+    STEP_TRANSLATE_Z,
+
     TRANSLATE_CAMERA_Z,
     NUM_COMBINED_AXES,
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index d80952a5d9..ae806ed613 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -29,7 +29,6 @@ namespace controller {
 
 // Default contruct allocate the poutput size with the current hardcoded action channels
 controller::UserInputMapper::UserInputMapper() {
-    _activeMappings.push_back(_defaultMapping);
     _standardController = std::make_shared<StandardController>();
     registerDevice(new ActionsDevice());
     registerDevice(_standardController.get());
@@ -317,6 +316,7 @@ int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
 }
 
 void UserInputMapper::registerDevice(InputDevice* device) {
+    Locker locker(_lock);
     if (device->_deviceID == Input::INVALID_DEVICE) {
         device->_deviceID = getFreeDeviceID();
     }
@@ -354,13 +354,7 @@ void UserInputMapper::registerDevice(InputDevice* device) {
     auto mapping = loadMapping(device->getDefaultMappingConfig());
     if (mapping) {
         _mappingsByDevice[deviceID] = mapping;
-        auto& defaultRoutes = _defaultMapping->routes;
-
-        // New routes for a device get injected IN FRONT of existing routes.  Routes
-        // are processed in order so this ensures that the standard -> action processing 
-        // takes place after all of the hardware -> standard or hardware -> action processing
-        // because standard -> action is the first set of routes added.
-        defaultRoutes.insert(defaultRoutes.begin(), mapping->routes.begin(), mapping->routes.end());
+        enableMapping(mapping);
     }
 
     emit hardwareChanged();
@@ -368,6 +362,7 @@ void UserInputMapper::registerDevice(InputDevice* device) {
 
 // FIXME remove the associated device mappings
 void UserInputMapper::removeDevice(int deviceID) {
+    Locker locker(_lock);
     auto proxyEntry = _registeredDevices.find(deviceID);
     if (_registeredDevices.end() == proxyEntry) {
         qCWarning(controllers) << "Attempted to remove unknown device " << deviceID;
@@ -376,15 +371,7 @@ void UserInputMapper::removeDevice(int deviceID) {
     auto proxy = proxyEntry->second;
     auto mappingsEntry = _mappingsByDevice.find(deviceID);
     if (_mappingsByDevice.end() != mappingsEntry) {
-        const auto& mapping = mappingsEntry->second;
-        const auto& deviceRoutes = mapping->routes;
-        std::set<Route::Pointer> routeSet(deviceRoutes.begin(), deviceRoutes.end());
-
-        auto& defaultRoutes = _defaultMapping->routes;
-        std::remove_if(defaultRoutes.begin(), defaultRoutes.end(), [&](Route::Pointer route)->bool {
-            return routeSet.count(route) != 0;
-        });
-
+        disableMapping(mappingsEntry->second);
         _mappingsByDevice.erase(mappingsEntry);
     }
 
@@ -395,6 +382,7 @@ void UserInputMapper::removeDevice(int deviceID) {
 
 
 DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
+    Locker locker(_lock);
     auto device = _registeredDevices.find(input.getDevice());
     if (device != _registeredDevices.end()) {
         return (device->second);
@@ -404,6 +392,7 @@ DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
 }
 
 QString UserInputMapper::getDeviceName(uint16 deviceID) { 
+    Locker locker(_lock);
     if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
         return _registeredDevices[deviceID]->_name;
     }
@@ -411,6 +400,7 @@ QString UserInputMapper::getDeviceName(uint16 deviceID) {
 }
 
 int UserInputMapper::findDevice(QString name) const {
+    Locker locker(_lock);
     for (auto device : _registeredDevices) {
         if (device.second->_name == name) {
             return device.first;
@@ -420,6 +410,7 @@ int UserInputMapper::findDevice(QString name) const {
 }
 
 QVector<QString> UserInputMapper::getDeviceNames() {
+    Locker locker(_lock);
     QVector<QString> result;
     for (auto device : _registeredDevices) {
         QString deviceName = device.second->_name.split(" (")[0];
@@ -433,6 +424,7 @@ int UserInputMapper::findAction(const QString& actionName) const {
 }
 
 Input UserInputMapper::findDeviceInput(const QString& inputName) const {
+    Locker locker(_lock);
     // Split the full input name as such: deviceName.inputName
     auto names = inputName.split('.');
 
@@ -472,6 +464,7 @@ void fixBisectedAxis(float& full, float& negative, float& positive) {
 }
 
 void UserInputMapper::update(float deltaTime) {
+    Locker locker(_lock);
     // Reset the axis state for next loop
     for (auto& channel : _actionStates) {
         channel = 0.0f;
@@ -505,11 +498,13 @@ void UserInputMapper::update(float deltaTime) {
 }
 
 Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const {
+    Locker locker(_lock);
     auto iterator = _registeredDevices.find(deviceID);
     return iterator->second->getAvailabeInputs();
 }
 
 QVector<Action> UserInputMapper::getAllActions() const {
+    Locker locker(_lock);
     QVector<Action> actions;
     for (auto i = 0; i < toInt(Action::NUM_ACTIONS); i++) {
         actions.append(Action(i));
@@ -518,6 +513,7 @@ QVector<Action> UserInputMapper::getAllActions() const {
 }
 
 QString UserInputMapper::getActionName(Action action) const {
+    Locker locker(_lock);
     for (auto actionPair : getActionInputs()) {
         if (actionPair.first.channel == toInt(action)) {
             return actionPair.second;
@@ -528,6 +524,7 @@ QString UserInputMapper::getActionName(Action action) const {
 
 
 QVector<QString> UserInputMapper::getActionNames() const {
+    Locker locker(_lock);
     QVector<QString> result;
     for (auto actionPair : getActionInputs()) {
         result << actionPair.second;
@@ -645,74 +642,87 @@ void UserInputMapper::runMappings() {
     }
 
     // Now process the current values for each level of the stack
-    for (auto& mapping : _activeMappings) {
-        for (const auto& route : mapping->routes) {
-            if (route->conditional) {
-                if (!route->conditional->satisfied()) {
-                    continue;
-                }
-            }
+    for (const auto& route : _deviceRoutes) {
+        if (!route) {
+            continue;
+        }
+        applyRoute(route);
+    }
 
-            auto source = route->source;
-            if (_overrides.count(source)) {
-                source = _overrides[source];
-            }
+    for (const auto& route : _standardRoutes) {
+        if (!route) {
+            continue;
+        }
+        applyRoute(route);
+    }
 
-            // Endpoints can only be read once (though a given mapping can route them to 
-            // multiple places).  Consider... If the default is to wire the A button to JUMP
-            // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
-            // I press the button.  The exception is if I'm wiring a control back to itself
-            // in order to adjust my interface, like inverting the Y axis on an analog stick
-            if (!source->readable()) {
-                continue;
-            }
+}
 
 
-            auto input = source->getInput();
-            float value = source->value();
-            if (value != 0.0) {
-                int i = 0;
-            }
-
-            auto destination = route->destination;
-            // THis could happen if the route destination failed to create
-            // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
-            if (!destination) {
-                continue;
-            }
-
-            // FIXME?, should come before or after the override logic?
-            if (!destination->writeable()) {
-                continue;
-            }
-
-            // Only consume the input if the route isn't a loopback.
-            // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
-            bool loopback = (source->getInput() == destination->getInput()) && (source->getInput() != Input::INVALID_INPUT);
-            // Each time we loop back we re-write the override 
-            if (loopback) {
-                _overrides[source] = destination = std::make_shared<StandardEndpoint>(source->getInput());
-            }
-
-            // Fetch the value, may have been overriden by previous loopback routes
-            if (source->isPose()) {
-                Pose value = getPose(source);
-                // no filters yet for pose
-                destination->apply(value, Pose(), source);
-            } else {
-                // Fetch the value, may have been overriden by previous loopback routes
-                float value = getValue(source);
-
-                // Apply each of the filters.
-                for (const auto& filter : route->filters) {
-                    value = filter->apply(value);
-                }
-
-                destination->apply(value, 0, source);
-            }
+void UserInputMapper::applyRoute(const Route::Pointer& route) {
+    if (route->conditional) {
+        if (!route->conditional->satisfied()) {
+            return;
         }
     }
 
+    auto source = route->source;
+    if (_overrides.count(source)) {
+        source = _overrides[source];
+    }
+
+    // Endpoints can only be read once (though a given mapping can route them to 
+    // multiple places).  Consider... If the default is to wire the A button to JUMP
+    // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
+    // I press the button.  The exception is if I'm wiring a control back to itself
+    // in order to adjust my interface, like inverting the Y axis on an analog stick
+    if (!source->readable()) {
+        return;
+    }
+
+
+    auto input = source->getInput();
+    float value = source->value();
+    if (value != 0.0) {
+        int i = 0;
+    }
+
+    auto destination = route->destination;
+    // THis could happen if the route destination failed to create
+    // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
+    if (!destination) {
+        return;
+    }
+
+    // FIXME?, should come before or after the override logic?
+    if (!destination->writeable()) {
+        return;
+    }
+
+    // Only consume the input if the route isn't a loopback.
+    // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
+    bool loopback = (source->getInput() == destination->getInput()) && (source->getInput() != Input::INVALID_INPUT);
+    // Each time we loop back we re-write the override 
+    if (loopback) {
+        _overrides[source] = destination = std::make_shared<StandardEndpoint>(source->getInput());
+    }
+
+    // Fetch the value, may have been overriden by previous loopback routes
+    if (source->isPose()) {
+        Pose value = getPose(source);
+        // no filters yet for pose
+        destination->apply(value, Pose(), source);
+    } else {
+        // Fetch the value, may have been overriden by previous loopback routes
+        float value = getValue(source);
+
+        // Apply each of the filters.
+        for (const auto& filter : route->filters) {
+            value = filter->apply(value);
+        }
+
+        destination->apply(value, 0, source);
+    }
 }
 
 Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) {
@@ -744,6 +754,7 @@ Endpoint::Pointer UserInputMapper::endpointFor(const QScriptValue& endpoint) {
 }
 
 Endpoint::Pointer UserInputMapper::endpointFor(const Input& inputId) const {
+    Locker locker(_lock);
     auto iterator = _endpointsByInput.find(inputId);
     if (_endpointsByInput.end() == iterator) {
         qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
@@ -767,6 +778,7 @@ Endpoint::Pointer UserInputMapper::compositeEndpointFor(Endpoint::Pointer first,
 
 
 Mapping::Pointer UserInputMapper::newMapping(const QString& mappingName) {
+    Locker locker(_lock);
     if (_mappingsByName.count(mappingName)) {
         qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
     }
@@ -799,8 +811,8 @@ Mapping::Pointer UserInputMapper::newMapping(const QString& mappingName) {
 //    return result;
 //}
 
-
 void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
+    Locker locker(_lock);
     qCDebug(controllers) << "Attempting to enable mapping " << mappingName;
     auto iterator = _mappingsByName.find(mappingName);
     if (_mappingsByName.end() == iterator) {
@@ -810,18 +822,14 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
 
     auto mapping = iterator->second;
     if (enable) {
-        _activeMappings.push_front(mapping);
+        enableMapping(mapping);
     } else {
-        auto activeIterator = std::find(_activeMappings.begin(), _activeMappings.end(), mapping);
-        if (_activeMappings.end() == activeIterator) {
-            qCWarning(controllers) << "Attempted to disable inactive mapping " << mappingName;
-            return;
-        }
-        _activeMappings.erase(activeIterator);
+        disableMapping(mapping);
     }
 }
 
 float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const {
+    Locker locker(_lock);
     auto valuesIterator = _overrides.find(endpoint);
     if (_overrides.end() != valuesIterator) {
         return valuesIterator->second->value();
@@ -854,6 +862,7 @@ Pose UserInputMapper::getPose(const Input& input) const {
 }
 
 Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) {
+    Locker locker(_lock);
     if (jsonFile.isEmpty()) {
         return Mapping::Pointer();
     }
@@ -1102,6 +1111,36 @@ Mapping::Pointer UserInputMapper::parseMapping(const QString& json) {
     return parseMapping(doc.object());
 }
 
+
+void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
+    Locker locker(_lock);
+    // New routes for a device get injected IN FRONT of existing routes.  Routes
+    // are processed in order so this ensures that the standard -> action processing 
+    // takes place after all of the hardware -> standard or hardware -> action processing
+    // because standard -> action is the first set of routes added.
+    for (auto route : mapping->routes) {
+        if (route->source->getInput().device == STANDARD_DEVICE) {
+            _standardRoutes.push_front(route);
+        } else {
+            _deviceRoutes.push_front(route);
+        }
+    }
+}
+
+void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
+    Locker locker(_lock);
+    const auto& deviceRoutes = mapping->routes;
+    std::set<Route::Pointer> routeSet(deviceRoutes.begin(), deviceRoutes.end());
+
+    // FIXME this seems to result in empty route pointers... need to find a better way to remove them.
+    std::remove_if(_deviceRoutes.begin(), _deviceRoutes.end(), [&](Route::Pointer route)->bool {
+        return routeSet.count(route) != 0;
+    });
+    std::remove_if(_standardRoutes.begin(), _standardRoutes.end(), [&](Route::Pointer route)->bool {
+        return routeSet.count(route) != 0;
+    });
+}
+
 }
 
 #include "UserInputMapper.moc"
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 345bba8c2b..70cd227e05 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -15,6 +15,7 @@
 #include <unordered_set>
 #include <functional>
 #include <memory>
+#include <mutex>
 
 #include <QtQml/QJSValue>
 #include <QtScript/QScriptValue>
@@ -119,10 +120,8 @@ namespace controller {
         void hardwareChanged();
 
     protected:
-        virtual void runMappings();
         // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
         uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
-
         InputDevice::Pointer _standardController;
         DevicesMap _registeredDevices;
         uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
@@ -142,6 +141,11 @@ namespace controller {
 
         friend class RouteBuilderProxy;
         friend class MappingBuilderProxy;
+
+        void runMappings();
+        void applyRoute(const Route::Pointer& route);
+        void enableMapping(const Mapping::Pointer& mapping);
+        void disableMapping(const Mapping::Pointer& mapping);
         Endpoint::Pointer endpointFor(const QJSValue& endpoint);
         Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
         Endpoint::Pointer endpointFor(const Input& endpoint) const;
@@ -163,9 +167,14 @@ namespace controller {
 
         EndpointOverrideMap _overrides;
         MappingNameMap _mappingsByName;
-        Mapping::Pointer _defaultMapping{ std::make_shared<Mapping>("Default") };
         MappingDeviceMap _mappingsByDevice;
-        MappingStack _activeMappings;
+
+        Route::List _deviceRoutes;
+        Route::List _standardRoutes;
+
+        using Locker = std::unique_lock<std::recursive_mutex>;
+
+        mutable std::recursive_mutex _lock;
     };
 
 }

From 044a28212d6b2430715c5d68243a6891b0a70b84 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 21 Oct 2015 20:44:38 -0700
Subject: [PATCH 092/301] Wiring step yaw to the avatar

---
 interface/resources/qml/TestControllers.qml |   3 +-
 interface/src/Application.cpp               |  20 ++--
 interface/src/avatar/Avatar.h               |  15 ---
 interface/src/avatar/MyAvatar.cpp           | 120 +++++++++-----------
 interface/src/avatar/MyAvatar.h             |  16 +++
 5 files changed, 78 insertions(+), 96 deletions(-)

diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index f1b8640c02..54b3cbf655 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -27,7 +27,8 @@ HifiControls.VrDialog {
         testMapping = Controller.newMapping();
         testMapping.from(standard.RY).invert().to(actions.Pitch);
         testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
-        testMapping.from(standard.RX).to(actions.StepYaw);
+        // Step yaw takes a number of degrees
+        testMapping.from(standard.RX).scale(15.0).to(actions.StepYaw);
     }
 
     function toggleMapping() {
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 4418f94b3a..3b54562770 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2718,15 +2718,13 @@ void Application::update(float deltaTime) {
     }
 
     // Transfer the user inputs to the driveKeys
+    // FIXME can we drop drive keys and just have the avatar read the action states directly?
     myAvatar->clearDriveKeys();
     if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
         if (!_controllerScriptingInterface->areActionsCaptured()) {
-            myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(controller::Action::LONGITUDINAL_FORWARD));
-            myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(controller::Action::LONGITUDINAL_BACKWARD));
-            myAvatar->setDriveKeys(UP, userInputMapper->getActionState(controller::Action::VERTICAL_UP));
-            myAvatar->setDriveKeys(DOWN, userInputMapper->getActionState(controller::Action::VERTICAL_DOWN));
-            myAvatar->setDriveKeys(LEFT, userInputMapper->getActionState(controller::Action::LATERAL_LEFT));
-            myAvatar->setDriveKeys(RIGHT, userInputMapper->getActionState(controller::Action::LATERAL_RIGHT));
+            myAvatar->setDriveKeys(TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z));
+            myAvatar->setDriveKeys(TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y));
+            myAvatar->setDriveKeys(TRANSLATE_X, userInputMapper->getActionState(controller::Action::TRANSLATE_X));
             if (deltaTime > FLT_EPSILON) {
                 // For rotations what we really want are meausures of "angles per second" (in order to prevent 
                 // fps-dependent spin rates) so we need to scale the units of the controller contribution.
@@ -2734,14 +2732,12 @@ void Application::update(float deltaTime) {
                 // controllers to provide a delta_per_second value rather than a raw delta.)
                 const float EXPECTED_FRAME_RATE = 60.0f;
                 float timeFactor = EXPECTED_FRAME_RATE * deltaTime;
-                myAvatar->setDriveKeys(ROT_UP, userInputMapper->getActionState(controller::Action::PITCH_UP) / timeFactor);
-                myAvatar->setDriveKeys(ROT_DOWN, userInputMapper->getActionState(controller::Action::PITCH_DOWN) / timeFactor);
-                myAvatar->setDriveKeys(ROT_LEFT, userInputMapper->getActionState(controller::Action::YAW_LEFT) / timeFactor);
-                myAvatar->setDriveKeys(ROT_RIGHT, userInputMapper->getActionState(controller::Action::YAW_RIGHT) / timeFactor);
+                myAvatar->setDriveKeys(PITCH, userInputMapper->getActionState(controller::Action::PITCH) / timeFactor);
+                myAvatar->setDriveKeys(YAW, -1.0f * userInputMapper->getActionState(controller::Action::YAW) / timeFactor);
+                myAvatar->setDriveKeys(STEP_YAW, -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW) / timeFactor);
             }
         }
-        myAvatar->setDriveKeys(BOOM_IN, userInputMapper->getActionState(controller::Action::BOOM_IN));
-        myAvatar->setDriveKeys(BOOM_OUT, userInputMapper->getActionState(controller::Action::BOOM_OUT));
+        myAvatar->setDriveKeys(ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z));
     }
     controller::Pose leftHand = userInputMapper->getPoseState(controller::Action::LEFT_HAND);
     controller::Pose rightHand = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);
diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h
index 9a46a145c2..6a1f216089 100644
--- a/interface/src/avatar/Avatar.h
+++ b/interface/src/avatar/Avatar.h
@@ -43,21 +43,6 @@ static const float BILLBOARD_DISTANCE = 5.56f;       // meters
 extern const float CHAT_MESSAGE_SCALE;
 extern const float CHAT_MESSAGE_HEIGHT;
 
-enum DriveKeys {
-    FWD = 0,
-    BACK,
-    LEFT,
-    RIGHT,
-    UP,
-    DOWN,
-    ROT_LEFT,
-    ROT_RIGHT,
-    ROT_UP,
-    ROT_DOWN,
-    BOOM_IN,
-    BOOM_OUT,
-    MAX_DRIVE_KEYS
-};
 
 enum ScreenTintLayer {
     SCREEN_TINT_BEFORE_LANDSCAPE = 0,
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 5202138147..8ada0ca481 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -242,6 +242,7 @@ void MyAvatar::simulate(float deltaTime) {
         PerformanceTimer perfTimer("transform");
         updateOrientation(deltaTime);
         updatePosition(deltaTime);
+        _lastStepPulse = _thisStepPulse;
     }
 
     {
@@ -1552,71 +1553,49 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
             !cameraInsideHead());
 }
 
+static quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second
+
 void MyAvatar::updateOrientation(float deltaTime) {
     //  Smoothly rotate body with arrow keys
-    float targetSpeed = 0.0f;
-
-    // FIXME - this comfort mode code is a total hack, remove it when we have new input mapping
-    bool isComfortMode = Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode);
-    bool isHMDMode = qApp->getAvatarUpdater()->isHMDMode();
-
-    if (!isHMDMode || !isComfortMode) {
-        targetSpeed = (_driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT]) * YAW_SPEED;
-
-        if (targetSpeed != 0.0f) {
-            const float ROTATION_RAMP_TIMESCALE = 0.1f;
-            float blend = deltaTime / ROTATION_RAMP_TIMESCALE;
-            if (blend > 1.0f) {
-                blend = 1.0f;
-            }
-            _bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed;
-        } else if (_bodyYawDelta != 0.0f) {
-            // attenuate body rotation speed
-            const float ROTATION_DECAY_TIMESCALE = 0.05f;
-            float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE;
-            if (attenuation < 0.0f) {
-                attenuation = 0.0f;
-            }
-            _bodyYawDelta *= attenuation;
-
-            float MINIMUM_ROTATION_RATE = 2.0f;
-            if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) {
-                _bodyYawDelta = 0.0f;
-            }
+    float targetSpeed = _driveKeys[YAW] * YAW_SPEED;
+    if (targetSpeed != 0.0f) {
+        const float ROTATION_RAMP_TIMESCALE = 0.1f;
+        float blend = deltaTime / ROTATION_RAMP_TIMESCALE;
+        if (blend > 1.0f) {
+            blend = 1.0f;
         }
+        _bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed;
+    } else if (_bodyYawDelta != 0.0f) {
+        // attenuate body rotation speed
+        const float ROTATION_DECAY_TIMESCALE = 0.05f;
+        float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE;
+        if (attenuation < 0.0f) {
+            attenuation = 0.0f;
+        }
+        _bodyYawDelta *= attenuation;
 
-        // update body orientation by movement inputs
-        setOrientation(getOrientation() *
-            glm::quat(glm::radians(glm::vec3(0.0f, _bodyYawDelta * deltaTime, 0.0f))));
-
-    } else {
-        // Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll
-        // get an instantaneous 15 degree turn. If you keep holding the key down you'll get another
-        // snap turn every half second.
-        _bodyYawDelta = 0.0f;
-
-        static quint64 lastPulse = 0;
-        quint64 now = usecTimestampNow();
-        quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second
-
-        float driveLeft = _driveKeys[ROT_LEFT];
-        float driveRight= _driveKeys[ROT_RIGHT];
-
-        if ((driveLeft != 0.0f || driveRight != 0.0f) && (now - lastPulse > COMFORT_MODE_PULSE_TIMING)) {
-            lastPulse = now;
-
-            const float SNAP_TURN_DELTA = 15.0f; // degrees
-            float direction = (driveLeft - driveRight) < 0.0f ? -1.0f : 1.0f;
-            float turnAmount = direction * SNAP_TURN_DELTA;
-
-            // update body orientation by movement inputs
-            setOrientation(getOrientation() *
-                glm::quat(glm::radians(glm::vec3(0.0f, turnAmount, 0.0f))));
-
+        float MINIMUM_ROTATION_RATE = 2.0f;
+        if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) {
+            _bodyYawDelta = 0.0f;
         }
     }
 
-    getHead()->setBasePitch(getHead()->getBasePitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime);
+    float totalBodyYaw = _bodyYawDelta * deltaTime;
+
+
+    // Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll
+    // get an instantaneous 15 degree turn. If you keep holding the key down you'll get another
+    // snap turn every half second.
+    quint64 now = usecTimestampNow();
+    if (_driveKeys[STEP_YAW] != 0.0f && now - _lastStepPulse > COMFORT_MODE_PULSE_TIMING) {
+        _thisStepPulse = now;
+        totalBodyYaw += _driveKeys[STEP_YAW];
+    }
+
+    // update body orientation by movement inputs
+    setOrientation(getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f))));
+
+    getHead()->setBasePitch(getHead()->getBasePitch() + _driveKeys[PITCH] * PITCH_SPEED * deltaTime);
 
     if (qApp->getAvatarUpdater()->isHMDMode()) {
         glm::quat orientation = glm::quat_cast(getSensorToWorldMatrix()) * getHMDSensorOrientation();
@@ -1676,15 +1655,20 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe
     float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f);
 
     glm::vec3 newLocalVelocity = localVelocity;
-    float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) +
-        (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) +
-        fabsf(_driveKeys[UP] - _driveKeys[DOWN]);
-    if (keyboardInput) {
-        // Compute keyboard input
-        glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT;
-        glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT;
-        glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP;
+    float stepControllerInput = fabsf(_driveKeys[STEP_TRANSLATE_Z]) + fabsf(_driveKeys[STEP_TRANSLATE_Z]) + fabsf(_driveKeys[STEP_TRANSLATE_Z]);
+    quint64 now = usecTimestampNow();
+    if (stepControllerInput && now - _lastStepPulse > COMFORT_MODE_PULSE_TIMING) {
+        _thisStepPulse = now;
+    }
 
+    float keyboardInput = fabsf(_driveKeys[TRANSLATE_Z]) + fabsf(_driveKeys[TRANSLATE_X]) + fabsf(_driveKeys[TRANSLATE_Y]);
+    if (keyboardInput || (_thisStepPulse == now)) {
+        // Compute keyboard input
+        glm::vec3 front = (_driveKeys[TRANSLATE_Z]) * IDENTITY_FRONT;
+        glm::vec3 right = (_driveKeys[TRANSLATE_X]) * IDENTITY_RIGHT;
+        glm::vec3 up = (_driveKeys[TRANSLATE_Y]) * IDENTITY_UP;
+
+        // FIXME how do I implement step translation as well?
         glm::vec3 direction = front + right + up;
         float directionLength = glm::length(direction);
 
@@ -1734,7 +1718,7 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe
         }
     }
 
-    float boomChange = _driveKeys[BOOM_OUT] - _driveKeys[BOOM_IN];
+    float boomChange = _driveKeys[ZOOM];
     _boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange;
     _boomLength = glm::clamp<float>(_boomLength, ZOOM_MIN, ZOOM_MAX);
 
@@ -1983,7 +1967,7 @@ void MyAvatar::clearDriveKeys() {
 }
 
 void MyAvatar::relayDriveKeysToCharacterController() {
-    if (_driveKeys[UP] > 0.0f) {
+    if (_driveKeys[TRANSLATE_Y] > 0.0f) {
         _characterController.jump();
     }
 }
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 4a0ae514f6..64814974b2 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -21,6 +21,20 @@
 
 class ModelItemID;
 
+enum DriveKeys {
+    TRANSLATE_X = 0,
+    TRANSLATE_Y,
+    TRANSLATE_Z,
+    YAW,
+    STEP_TRANSLATE_X,
+    STEP_TRANSLATE_Y,
+    STEP_TRANSLATE_Z,
+    STEP_YAW,
+    PITCH,
+    ZOOM,
+    MAX_DRIVE_KEYS
+};
+
 enum eyeContactTarget {
     LEFT_EYE,
     RIGHT_EYE,
@@ -376,6 +390,8 @@ private:
     AtRestDetector _hmdAtRestDetector;
     glm::vec3 _lastPosition;
     bool _lastIsMoving = false;
+    quint64 _lastStepPulse = 0;
+    quint64 _thisStepPulse = 0;
 };
 
 QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);

From 9fd61907f51aa79d136f5cbf1cb6a7032b3654d8 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Wed, 21 Oct 2015 20:50:07 -0700
Subject: [PATCH 093/301] Call back to Javascript asynchronously, so that we
 don't block and the script's engine doesn't have thread conflicts.

---
 interface/src/avatar/MyAvatar.h              |  2 +
 interface/src/avatar/SkeletonModel.cpp       |  1 -
 libraries/animation/src/AnimVariant.h        |  6 ++-
 libraries/animation/src/AnimVariantMap.cpp   |  7 ++-
 libraries/animation/src/Rig.cpp              | 50 ++++++++------------
 libraries/animation/src/Rig.h                |  8 ++--
 libraries/script-engine/src/ScriptEngine.cpp | 37 +++++++++++++--
 libraries/script-engine/src/ScriptEngine.h   |  5 ++
 8 files changed, 77 insertions(+), 39 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 49f6c33aca..1ce72cb33f 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -118,6 +118,8 @@ public:
     Q_INVOKABLE void addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { _rig->addAnimationStateHandler(handler, propertiesList); }
     // Removes a handler previously added by addAnimationStateHandler.
     Q_INVOKABLE void removeAnimationStateHandler(QScriptValue handler) { _rig->removeAnimationStateHandler(handler); }
+    // Processes a handler result. Not really for user code, but used by invokeAnimationCallback.
+    Q_INVOKABLE void animationStateHandlerResult(QScriptValue handler, QScriptValue result) { _rig->animationStateHandlerResult(handler, result); }
 
     // get/set avatar data
     void saveData();
diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp
index 5c98d4cd9b..003677bf90 100644
--- a/interface/src/avatar/SkeletonModel.cpp
+++ b/interface/src/avatar/SkeletonModel.cpp
@@ -112,7 +112,6 @@ const float PALM_PRIORITY = DEFAULT_PRIORITY;
 // Called within Model::simulate call, below.
 void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
     Head* head = _owningAvatar->getHead();
-    _rig->cleanupAnimationStateHandler();
     if (_owningAvatar->isMyAvatar()) {
         MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
         const FBXGeometry& geometry = _geometry->getFBXGeometry();
diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h
index 0a91c82d80..2d140bfa52 100644
--- a/libraries/animation/src/AnimVariant.h
+++ b/libraries/animation/src/AnimVariant.h
@@ -158,12 +158,14 @@ public:
     void setTrigger(const QString& key) { _triggers.insert(key); }
     void clearTriggers() { _triggers.clear(); }
 
+    void clearMap() { _map.clear(); }
     bool hasKey(const QString& key) const { return _map.find(key) != _map.end(); }
 
     // Answer a Plain Old Javascript Object (for the given engine) all of our values set as properties.
-    QScriptValue animVariantMapToScriptValue(QScriptEngine* engine);
+    QScriptValue animVariantMapToScriptValue(QScriptEngine* engine) const;
     // Side-effect us with the value of object's own properties. (No inherited properties.)
     void animVariantMapFromScriptValue(const QScriptValue& object);
+    void copyVariantsFrom(const AnimVariantMap& other);
 
 #ifdef NDEBUG
     void dump() const {
@@ -203,4 +205,6 @@ protected:
     std::set<QString> _triggers;
 };
 
+Q_DECLARE_METATYPE(AnimVariantMap)
+
 #endif // hifi_AnimVariant_h
diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
index f626e46c0f..0154c9698a 100644
--- a/libraries/animation/src/AnimVariantMap.cpp
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -14,7 +14,7 @@
 #include <RegisteredMetaTypes.h>
 #include "AnimVariant.h"
 
-QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine) {
+QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine) const {
     QScriptValue target = engine->newObject();
     for (auto& pair : _map) {
         switch (pair.second.getType()) {
@@ -43,6 +43,11 @@ QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine)
     }
     return target;
 }
+void AnimVariantMap::copyVariantsFrom(const AnimVariantMap& other) {
+    for (auto& pair : other._map) {
+        _map[pair.first] = pair.second;
+    }
+}
 void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) {
     // POTENTIAL OPTIMIZATION: cache the types we've seen. I.e, keep a dictionary mapping property names to an enumeration of types.
     // Whenever we identify a new outbound type in animVariantMapToScriptValue above, or a new inbound type in the code that follows here,
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 215e0095c0..14aef88e2f 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -605,40 +605,32 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
     _lastPosition = worldPosition;
 }
 
-void Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) {
+// Allow script to add/remove handlers and report results, from within their thread.
+// TODO: iterate multiple handlers, but with one shared arg.
+// TODO: fill the properties based on the union of requested properties. (Keep all properties objs and compute new union when add/remove handler.)
+void Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { // called in script thread
     _stateHandlers = handler;
 }
-void Rig::removeAnimationStateHandler(QScriptValue handler) {
-    _stateHandlersResultsToRemove = _stateHandlersResults;
-    _stateHandlers = _stateHandlersResults = QScriptValue();
+void Rig::removeAnimationStateHandler(QScriptValue handler) { // called in script thread
+    _stateHandlers = QScriptValue();
+    QMutexLocker locker(&_stateMutex); // guarding access to results
+    _stateHandlersResults.clearMap(); // TODO: When we have multiple handlers, we'll need to clear only his handler's results.
 }
-void Rig::cleanupAnimationStateHandler() {
-    if (!_stateHandlersResultsToRemove.isValid()) {
-        return;
-    }
-    QScriptValueIterator property(_stateHandlersResultsToRemove);
-    while (property.hasNext()) {
-        property.next();
-        _animVars.unset(property.name());
-    }
-    _stateHandlersResultsToRemove = QScriptValue();
+void Rig::animationStateHandlerResult(QScriptValue handler, QScriptValue result) { // called synchronously from script
+    // handler is currently ignored but might be used in storing individual results
+    QMutexLocker locker(&_stateMutex);
+    _stateHandlersResults.animVariantMapFromScriptValue(result); // Into our own copy.
 }
-void Rig::updateAnimationStateHandlers() {
-    if (!_stateHandlers.isValid()) {
-        return;
+void Rig::updateAnimationStateHandlers() { // called on avatar update thread (which may be main thread)
+    if (_stateHandlers.isValid()) {
+        // invokeMethod makes a copy of the args, and copies of AnimVariantMap do copy the underlying map, so this will correctly capture
+        // the state of _animVars and allow continued changes to _animVars in this thread without conflict.
+        QMetaObject::invokeMethod(_stateHandlers.engine(), "invokeAnimationCallback",  Qt::QueuedConnection,
+                                  Q_ARG(QScriptValue, _stateHandlers),
+                                  Q_ARG(AnimVariantMap, _animVars));
     }
-    // TODO: iterate multiple handlers, but with one shared arg.
-    // TODO: fill the properties based on the union of requested properties. (Keep all properties objs and compute new union when add/remove handler.)
-    // TODO: check QScriptEngine::hasUncaughtException()
-    // TODO: call asynchronously (through a signal on script), so that each script is single threaded, and so we never block here.
-    //       This will require inboundMaps to be kept in the list of per-handler data.
-    QScriptEngine* engine = _stateHandlers.engine();
-    QScriptValue outboundMap = _animVars.animVariantMapToScriptValue(engine);
-    QScriptValueList args;
-    args << outboundMap;
-    _stateHandlersResults = _stateHandlers.call(QScriptValue(), args);
-    _animVars.animVariantMapFromScriptValue(_stateHandlersResults);
-    //qCDebug(animation) << _animVars.lookup("foo", QString("not set"));
+    QMutexLocker locker(&_stateMutex); // as we examine/copy most recently computed state, if any. (Typically an earlier invocation.)
+    _animVars.copyVariantsFrom(_stateHandlersResults);
 }
 
 void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index 3f68deef1a..c29bb6ad04 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -202,7 +202,7 @@ public:
     bool disableHands {false}; // should go away with rig animation (and Rig::inverseKinematics)
     void addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList);
     void removeAnimationStateHandler(QScriptValue handler);
-    void cleanupAnimationStateHandler();
+    void animationStateHandlerResult(QScriptValue handler, QScriptValue result);
 
     bool getModelOffset(glm::vec3& modelOffsetOut) const;
 
@@ -248,9 +248,9 @@ public:
     float _rightHandOverlayAlpha = 0.0f;
 
 private:
-    QScriptValue _stateHandlers {};
-    QScriptValue _stateHandlersResults {};
-    QScriptValue _stateHandlersResultsToRemove {};
+    QScriptValue _stateHandlers;
+    AnimVariantMap _stateHandlersResults;
+    QMutex _stateMutex;
 };
 
 #endif /* defined(__hifi__Rig__) */
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 76590f266b..0ec1a09d6d 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -258,6 +258,15 @@ void ScriptEngine::errorInLoadingScript(const QUrl& url) {
     }
 }
 
+// Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of
+// invokeAnimationCallback requires that the type be registered.
+static QScriptValue animVarMapToScriptValue(QScriptEngine* engine, const AnimVariantMap& parameters) {
+    return parameters.animVariantMapToScriptValue(engine);
+}
+static void animVarMapFromScriptValue(const QScriptValue& value, AnimVariantMap& parameters) {
+    parameters.animVariantMapFromScriptValue(value);
+}
+
 void ScriptEngine::init() {
     if (_isInitialized) {
         return; // only initialize once
@@ -316,6 +325,7 @@ void ScriptEngine::init() {
     registerGlobalObject("Vec3", &_vec3Library);
     registerGlobalObject("Uuid", &_uuidLibrary);
     registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
+    qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue);
 
     // constants
     globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
@@ -718,6 +728,21 @@ void ScriptEngine::stop() {
     }
 }
 
+// Other threads can invoke this through invokeMethod, which causes the callback to be asynchronously executed in this script's thread.
+void ScriptEngine::invokeAnimationCallback(QScriptValue callback, AnimVariantMap parameters) {
+    checkThread();
+    QScriptValue javascriptParametgers = parameters.animVariantMapToScriptValue(this);
+    QScriptValueList callingArguments;
+    callingArguments << javascriptParametgers;
+    QScriptValue result = callback.call(QScriptValue(), callingArguments);
+    // We want to give the result back to the rig, but we don't have the rig or the avatar. But the global does.
+    // This is sort of like going through DependencyManager.get.
+    QScriptValue resultHandler = globalObject().property("MyAvatar").property("animationStateHandlerResult");
+    QScriptValueList resultArguments;
+    resultArguments << callback << result;
+    resultHandler.call(QScriptValue(), resultArguments); // Call it synchronously, on our own time and thread.
+}
+
 void ScriptEngine::timerFired() {
     QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
     QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);
@@ -898,14 +923,20 @@ void ScriptEngine::load(const QString& loadFile) {
     }
 }
 
-// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
-void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) {
+bool ScriptEngine::checkThread() const {
     if (QThread::currentThread() != thread()) {
         qDebug() << "*** ERROR *** ScriptEngine::generalHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
         assert(false);
+        return true;
+    }
+    return false;
+}
+
+// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
+void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) {
+    if (checkThread()) {
         return;
     }
-
     if (!_registeredHandlers.contains(entityID)) {
         return;
     }
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index 1d3986143a..77f1e2d5f1 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -21,6 +21,7 @@
 #include <QtScript/QScriptEngine>
 
 #include <AnimationCache.h>
+#include <AnimVariant.h>
 #include <AvatarData.h>
 #include <AvatarHashMap.h>
 #include <LimitedNodeList.h>
@@ -142,6 +143,9 @@ public:
     // NOTE - this is used by the TypedArray implemetation. we need to review this for thread safety
     ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; }
 
+public slots:
+    void invokeAnimationCallback(QScriptValue callback, AnimVariantMap parameters);
+
 signals:
     void scriptLoaded(const QString& scriptFilename);
     void errorLoadingScript(const QString& scriptFilename);
@@ -169,6 +173,7 @@ protected:
     bool _wantSignals = true;
     QHash<EntityItemID, EntityScriptDetails> _entityScripts;
 private:
+    bool checkThread() const;
     void init();
     QString getFilename() const;
     void waitTillDoneRunning();

From afcec347ffab06a3ac9ce7a5367d2393bdde93f9 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 21 Oct 2015 21:35:19 -0700
Subject: [PATCH 094/301] Wiring yaw action to avatar

---
 interface/resources/qml/TestControllers.qml |  4 ++-
 interface/src/Application.cpp               |  2 +-
 interface/src/avatar/MyAvatar.cpp           | 33 ++++++++++++++++-----
 interface/src/avatar/MyAvatar.h             |  2 +-
 4 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index 54b3cbf655..3d1e13c6e3 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -26,8 +26,10 @@ HifiControls.VrDialog {
     function buildMapping() {
         testMapping = Controller.newMapping();
         testMapping.from(standard.RY).invert().to(actions.Pitch);
-        testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
+        //testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
         // Step yaw takes a number of degrees
+        testMapping.from(standard.LB).invert().scale(15.0).to(actions.StepYaw);
+        testMapping.from(standard.RB).scale(15.0).to(actions.StepYaw);
         testMapping.from(standard.RX).scale(15.0).to(actions.StepYaw);
     }
 
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 3b54562770..0a634425bc 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2732,7 +2732,7 @@ void Application::update(float deltaTime) {
                 // controllers to provide a delta_per_second value rather than a raw delta.)
                 const float EXPECTED_FRAME_RATE = 60.0f;
                 float timeFactor = EXPECTED_FRAME_RATE * deltaTime;
-                myAvatar->setDriveKeys(PITCH, userInputMapper->getActionState(controller::Action::PITCH) / timeFactor);
+                myAvatar->setDriveKeys(PITCH, -1.0f * userInputMapper->getActionState(controller::Action::PITCH) / timeFactor);
                 myAvatar->setDriveKeys(YAW, -1.0f * userInputMapper->getActionState(controller::Action::YAW) / timeFactor);
                 myAvatar->setDriveKeys(STEP_YAW, -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW) / timeFactor);
             }
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 8ada0ca481..d822d37055 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -53,6 +53,7 @@
 
 using namespace std;
 
+static quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second
 const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
 const float YAW_SPEED = 150.0f;   // degrees/sec
 const float PITCH_SPEED = 100.0f; // degrees/sec
@@ -240,9 +241,31 @@ void MyAvatar::simulate(float deltaTime) {
 
     {
         PerformanceTimer perfTimer("transform");
+        bool stepAction = false;
+        // When there are no step values, we zero out the last step pulse. 
+        // This allows a user to do faster snapping by tapping a control
+        for (int i = STEP_TRANSLATE_X; !stepAction && i <= STEP_YAW; ++i) {
+            if (_driveKeys[i] != 0.0f) {
+                stepAction = true;
+            }
+        }
+        quint64 now = usecTimestampNow();
+        quint64 pulseDeltaTime = now - _lastStepPulse;
+        if (!stepAction) {
+            _lastStepPulse = 0;
+        }
+
+        if (stepAction && pulseDeltaTime > COMFORT_MODE_PULSE_TIMING) {
+            _pulseUpdate = true;
+        }
+
         updateOrientation(deltaTime);
         updatePosition(deltaTime);
-        _lastStepPulse = _thisStepPulse;
+
+        if (_pulseUpdate) {
+            _lastStepPulse = now;
+            _pulseUpdate = false;
+        }
     }
 
     {
@@ -1553,8 +1576,6 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
             !cameraInsideHead());
 }
 
-static quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second
-
 void MyAvatar::updateOrientation(float deltaTime) {
     //  Smoothly rotate body with arrow keys
     float targetSpeed = _driveKeys[YAW] * YAW_SPEED;
@@ -1588,7 +1609,6 @@ void MyAvatar::updateOrientation(float deltaTime) {
     // snap turn every half second.
     quint64 now = usecTimestampNow();
     if (_driveKeys[STEP_YAW] != 0.0f && now - _lastStepPulse > COMFORT_MODE_PULSE_TIMING) {
-        _thisStepPulse = now;
         totalBodyYaw += _driveKeys[STEP_YAW];
     }
 
@@ -1657,18 +1677,17 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe
     glm::vec3 newLocalVelocity = localVelocity;
     float stepControllerInput = fabsf(_driveKeys[STEP_TRANSLATE_Z]) + fabsf(_driveKeys[STEP_TRANSLATE_Z]) + fabsf(_driveKeys[STEP_TRANSLATE_Z]);
     quint64 now = usecTimestampNow();
+    // FIXME how do I implement step translation as well?
     if (stepControllerInput && now - _lastStepPulse > COMFORT_MODE_PULSE_TIMING) {
-        _thisStepPulse = now;
     }
 
     float keyboardInput = fabsf(_driveKeys[TRANSLATE_Z]) + fabsf(_driveKeys[TRANSLATE_X]) + fabsf(_driveKeys[TRANSLATE_Y]);
-    if (keyboardInput || (_thisStepPulse == now)) {
+    if (keyboardInput) {
         // Compute keyboard input
         glm::vec3 front = (_driveKeys[TRANSLATE_Z]) * IDENTITY_FRONT;
         glm::vec3 right = (_driveKeys[TRANSLATE_X]) * IDENTITY_RIGHT;
         glm::vec3 up = (_driveKeys[TRANSLATE_Y]) * IDENTITY_UP;
 
-        // FIXME how do I implement step translation as well?
         glm::vec3 direction = front + right + up;
         float directionLength = glm::length(direction);
 
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 64814974b2..c80a855149 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -391,7 +391,7 @@ private:
     glm::vec3 _lastPosition;
     bool _lastIsMoving = false;
     quint64 _lastStepPulse = 0;
-    quint64 _thisStepPulse = 0;
+    bool _pulseUpdate { false };
 };
 
 QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);

From 3e7364608bbc7e27283d93767e996d515b975832 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 22 Oct 2015 09:17:29 -0700
Subject: [PATCH 095/301] make handControllerGrab.js work with new API

---
 examples/controllers/handControllerGrab.js    | 22 ++++++++++---------
 interface/resources/controllers/standard.json | 13 ++---------
 2 files changed, 14 insertions(+), 21 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 80fb4c8e40..17d16d1718 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -245,7 +245,7 @@ function MyController(hand, triggerAction) {
     };
 
     this.updateSmoothedTrigger = function() {
-        var triggerValue = Controller.getActionValue(this.triggerAction);
+        var triggerValue = Controller.getValue(this.triggerAction);
         // smooth out trigger value
         this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
             (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO));
@@ -260,7 +260,7 @@ function MyController(hand, triggerAction) {
     };
 
     this.triggerSqueezed = function() {
-        var triggerValue = Controller.getActionValue(this.triggerAction);
+        var triggerValue = Controller.getValue(this.triggerAction);
         return triggerValue > TRIGGER_ON_VALUE;
     };
 
@@ -402,8 +402,9 @@ function MyController(hand, triggerAction) {
 
     this.distanceHolding = function() {
 
-        var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
-        var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
+        var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
+        var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
+        var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation);
         var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation",
                                                                                   "gravity", "ignoreForCollisions"]);
         var now = Date.now();
@@ -452,8 +453,9 @@ function MyController(hand, triggerAction) {
         }
 
         var handPosition = this.getHandPosition();
-        var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
-        var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
+        var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
+        var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
+        var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation);
         var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]);
 
         this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
@@ -595,7 +597,7 @@ function MyController(hand, triggerAction) {
 
         }
 
-        this.currentHandControllerTipPosition = Controller.getSpatialControlPosition(this.tip);
+        this.currentHandControllerTipPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition;;
 
         this.currentObjectTime = Date.now();
     };
@@ -613,7 +615,7 @@ function MyController(hand, triggerAction) {
         // of it's actual offset, let's try imparting a velocity which is at a fixed radius
         // from the palm.
 
-        var handControllerPosition = Controller.getSpatialControlPosition(this.tip);
+        var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
         var now = Date.now();
 
         var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters
@@ -856,8 +858,8 @@ function MyController(hand, triggerAction) {
     };
 }
 
-var rightController = new MyController(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK"));
-var leftController = new MyController(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK"));
+var rightController = new MyController(RIGHT_HAND, Controller.Standard.RT);
+var leftController = new MyController(LEFT_HAND, Controller.Standard.LT);
 
 function update() {
     rightController.update();
diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index ef6668ec07..2067d98380 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -12,17 +12,8 @@
         { "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" },
         { "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" },
 
-        { 
-            "from": "Standard.RT", 
-            "to": "Actions.BOOM_IN", 
-            "filters": [ { "type": "scale", "scale": 0.1 } ]
-        },
-
-        { 
-            "from": "Standard.LT", 
-            "to": "Actions.BOOM_OUT", 
-            "filters": [ { "type": "scale", "scale": 0.1 } ]
-        },
+        { "from": "Standard.LT", "to": "Actions.LEFT_HAND_CLICK" }, 
+        { "from": "Standard.RT", "to": "Actions.RIGHT_HAND_CLICK" },
 
         { "from": "Standard.LeftHand", "to": "Actions.LEFT_HAND" }, 
         { "from": "Standard.RightHand", "to": "Actions.RIGHT_HAND" }

From 4938e5ea8421c2fa5aa29df363f3492a0d9cabdf Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 21 Oct 2015 23:58:36 -0700
Subject: [PATCH 096/301] Fixing function based routes, makeAxis

---
 examples/tests/controllerInterfaceTest.js     | 21 ++++++++++++++++++-
 interface/resources/qml/TestControllers.qml   |  7 +++++--
 .../controllers/src/controllers/Input.cpp     |  9 ++++----
 libraries/controllers/src/controllers/Input.h |  2 +-
 .../src/controllers/UserInputMapper.cpp       |  9 +++++++-
 .../controllers/impl/MappingBuilderProxy.cpp  | 10 ++++-----
 .../controllers/impl/MappingBuilderProxy.h    |  6 +++---
 7 files changed, 46 insertions(+), 18 deletions(-)

diff --git a/examples/tests/controllerInterfaceTest.js b/examples/tests/controllerInterfaceTest.js
index 48ad8f0879..35a92daa6b 100644
--- a/examples/tests/controllerInterfaceTest.js
+++ b/examples/tests/controllerInterfaceTest.js
@@ -4,10 +4,29 @@ ControllerTest = function() {
     this.mappingEnabled = false;
     this.mapping = Controller.newMapping();
     this.mapping.from(standard.RX).to(actions.StepYaw);
+    this.mapping.from(standard.RY).invert().to(actions.Pitch);
+
+    var testMakeAxis = false;
+    if (testMakeAxis) {
+        this.mapping.makeAxis(standard.LB, standard.RB).pulse(0.25).scale(40.0).to(actions.StepYaw);
+    } 
+    
+    var testStepYaw = false;
+    if (!testMakeAxis && testStepYaw){
+        this.mapping.from(standard.LB).pulse(0.10).invert().scale(40.0).to(actions.StepYaw);
+        this.mapping.from(standard.RB).pulse(0.10).scale(15.0).to(actions.StepYaw);
+    }
+    
+    var testFunctionSource = false;
+    if (testFunctionSource) {
+        this.mapping.fromFunction(function(){
+            return Math.sin(Date.now() / 250); 
+        }).to(actions.Yaw);
+    }
+
     this.mapping.enable();
     this.mappingEnabled = true;
 
-
     print("Actions");
     for (var prop in Controller.Actions) {
         print("\t" + prop);
diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index 3d1e13c6e3..f967b8bf9c 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -26,10 +26,13 @@ HifiControls.VrDialog {
     function buildMapping() {
         testMapping = Controller.newMapping();
         testMapping.from(standard.RY).invert().to(actions.Pitch);
+        testMapping.fromQmlFunction(function(){
+            return Math.sin(Date.now() / 250); 
+        }).to(actions.Yaw);
         //testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
         // Step yaw takes a number of degrees
-        testMapping.from(standard.LB).invert().scale(15.0).to(actions.StepYaw);
-        testMapping.from(standard.RB).scale(15.0).to(actions.StepYaw);
+        testMapping.from(standard.LB).pulse(0.10).invert().scale(40.0).to(actions.StepYaw);
+        testMapping.from(standard.RB).pulse(0.10).scale(15.0).to(actions.StepYaw);
         testMapping.from(standard.RX).scale(15.0).to(actions.StepYaw);
     }
 
diff --git a/libraries/controllers/src/controllers/Input.cpp b/libraries/controllers/src/controllers/Input.cpp
index 29d2fed617..4f645c3f95 100644
--- a/libraries/controllers/src/controllers/Input.cpp
+++ b/libraries/controllers/src/controllers/Input.cpp
@@ -10,10 +10,9 @@
 
 namespace controller {
 
-    const Input Input::INVALID_INPUT = Input(UINT32_MAX);
-    const uint16_t Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
-    const uint16_t Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
-    const uint16_t Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
-
+    const uint16_t Input::INVALID_DEVICE = 0xffff;
+    const uint16_t Input::INVALID_CHANNEL = 0x1fff;
+    const uint16_t Input::INVALID_TYPE = (uint16_t)ChannelType::INVALID;
+    const Input Input::INVALID_INPUT = Input(INVALID_DEVICE, INVALID_CHANNEL, ChannelType::INVALID);
 }
 
diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h
index 6f997c9f91..7382d365ec 100644
--- a/libraries/controllers/src/controllers/Input.h
+++ b/libraries/controllers/src/controllers/Input.h
@@ -16,7 +16,7 @@
 namespace controller {
 
 enum class ChannelType {
-    UNKNOWN = 0,
+    INVALID = 0,
     BUTTON = 1,
     AXIS,
     POSE,
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index ae806ed613..f1138479bf 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -145,10 +145,17 @@ void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID)
                    QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue),  QScriptValue(sourceID) }));
 }
 
+static const Input INVALID_STANDARD_INPUT = Input(UserInputMapper::STANDARD_DEVICE, Input::INVALID_CHANNEL, ChannelType::INVALID);
+
 class CompositeEndpoint : public Endpoint, Endpoint::Pair {
 public:
     CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
-        : Endpoint(Input::INVALID_INPUT), Pair(first, second) { }
+        : Endpoint(Input::INVALID_INPUT), Pair(first, second) { 
+        if (first->getInput().device == UserInputMapper::STANDARD_DEVICE &&
+            second->getInput().device == UserInputMapper::STANDARD_DEVICE) {
+            this->_input = INVALID_STANDARD_INPUT;
+        }
+    }
 
     virtual float value() {
         float result = first->value() * -1.0f + second->value();
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index 462a319a90..91b11115d9 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -26,13 +26,13 @@ QObject* MappingBuilderProxy::from(int input) {
     return from(sourceEndpoint);
 }
 
-QObject* MappingBuilderProxy::from(const QJSValue& source) {
+QObject* MappingBuilderProxy::fromQmlFunction(const QJSValue& source) {
     qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString();
     auto sourceEndpoint = _parent.endpointFor(source);
     return from(sourceEndpoint);
 }
 
-QObject* MappingBuilderProxy::from(const QScriptValue& source) {
+QObject* MappingBuilderProxy::fromFunction(const QScriptValue& source) {
     qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString();
     auto sourceEndpoint = _parent.endpointFor(source);
     return from(sourceEndpoint);
@@ -49,9 +49,9 @@ QObject* MappingBuilderProxy::from(const Endpoint::Pointer& source) {
     }
 }
 
-QObject* MappingBuilderProxy::makeAxis(const QJSValue& source1, const QJSValue& source2) {
-    auto source1Endpoint = _parent.endpointFor(source1);
-    auto source2Endpoint = _parent.endpointFor(source2);
+QObject* MappingBuilderProxy::makeAxis(int source1, int source2) {
+    auto source1Endpoint = _parent.endpointFor(Input(source1));
+    auto source2Endpoint = _parent.endpointFor(Input(source2));
     return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint));
 }
 
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index 07c1730836..06ffcd8ea3 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -33,9 +33,9 @@ public:
         : _parent(parent), _mapping(mapping) { }
 
     Q_INVOKABLE QObject* from(int sourceInput);
-    Q_INVOKABLE QObject* from(const QJSValue& source);
-    Q_INVOKABLE QObject* from(const QScriptValue& source);
-    Q_INVOKABLE QObject* makeAxis(const QJSValue& source1, const QJSValue& source2);
+    Q_INVOKABLE QObject* fromQmlFunction(const QJSValue& source);
+    Q_INVOKABLE QObject* fromFunction(const QScriptValue& source);
+    Q_INVOKABLE QObject* makeAxis(int source1, const int source2);
 
     Q_INVOKABLE QObject* enable(bool enable = true);
     Q_INVOKABLE QObject* disable() { return enable(false); }

From 5d4cbfdacba62c81fb14df4c58e0b7dbffc8dfec Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 09:40:41 -0700
Subject: [PATCH 097/301] Resolving ambiguity between functions and inputs
 differently

---
 examples/tests/controllerInterfaceTest.js     | 35 ++++++++++---------
 interface/resources/qml/TestControllers.qml   | 17 ++++-----
 .../controllers/impl/MappingBuilderProxy.cpp  | 22 ++++++------
 .../controllers/impl/MappingBuilderProxy.h    |  9 ++---
 .../controllers/impl/RouteBuilderProxy.cpp    | 10 ++----
 .../src/controllers/impl/RouteBuilderProxy.h  |  7 ++--
 6 files changed, 49 insertions(+), 51 deletions(-)

diff --git a/examples/tests/controllerInterfaceTest.js b/examples/tests/controllerInterfaceTest.js
index 35a92daa6b..a4e0557c78 100644
--- a/examples/tests/controllerInterfaceTest.js
+++ b/examples/tests/controllerInterfaceTest.js
@@ -17,9 +17,9 @@ ControllerTest = function() {
         this.mapping.from(standard.RB).pulse(0.10).scale(15.0).to(actions.StepYaw);
     }
     
-    var testFunctionSource = false;
+    var testFunctionSource = true;
     if (testFunctionSource) {
-        this.mapping.fromFunction(function(){
+        this.mapping.from(function(){
             return Math.sin(Date.now() / 250); 
         }).to(actions.Yaw);
     }
@@ -27,22 +27,25 @@ ControllerTest = function() {
     this.mapping.enable();
     this.mappingEnabled = true;
 
-    print("Actions");
-    for (var prop in Controller.Actions) {
-        print("\t" + prop);
-    }
-    print("Standard");
-    for (var prop in Controller.Standard) {
-        print("\t" + prop);
-    }
-    print("Hardware");
-    for (var prop in Controller.Hardware) {
-        print("\t" + prop);
-        for (var prop2 in Controller.Hardware[prop]) {
-            print("\t\t" + prop2);
+    var dumpInputs = false;
+    if (dumpInputs) {
+        print("Actions");
+        for (var prop in Controller.Actions) {
+            print("\t" + prop);
         }
+        print("Standard");
+        for (var prop in Controller.Standard) {
+            print("\t" + prop);
+        }
+        print("Hardware");
+        for (var prop in Controller.Hardware) {
+            print("\t" + prop);
+            for (var prop2 in Controller.Hardware[prop]) {
+                print("\t\t" + prop2);
+            }
+        }
+        print("Done");
     }
-    print("Done");
 
     var that = this;
     Script.scriptEnding.connect(function() {
diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index f967b8bf9c..a21735b3cc 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -25,15 +25,15 @@ HifiControls.VrDialog {
 
     function buildMapping() {
         testMapping = Controller.newMapping();
-        testMapping.from(standard.RY).invert().to(actions.Pitch);
-        testMapping.fromQmlFunction(function(){
+        testMapping.fromQml(standard.RY).invert().toQml(actions.Pitch);
+        testMapping.fromQml(function(){
             return Math.sin(Date.now() / 250); 
-        }).to(actions.Yaw);
+        }).toQml(actions.Yaw);
         //testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
         // Step yaw takes a number of degrees
-        testMapping.from(standard.LB).pulse(0.10).invert().scale(40.0).to(actions.StepYaw);
-        testMapping.from(standard.RB).pulse(0.10).scale(15.0).to(actions.StepYaw);
-        testMapping.from(standard.RX).scale(15.0).to(actions.StepYaw);
+        testMapping.fromQml(standard.LB).pulse(0.10).invert().scale(40.0).toQml(actions.StepYaw);
+        testMapping.fromQml(standard.RB).pulse(0.10).scale(15.0).toQml(actions.StepYaw);
+        testMapping.fromQml(standard.RX).scale(15.0).toQml(actions.StepYaw);
     }
 
     function toggleMapping() {
@@ -91,8 +91,9 @@ HifiControls.VrDialog {
             Hydra { device: root.hydra; width: 180 }
         }
         
-        Row {
-            spacing: 8
+        Grid {
+            columns: 6
+            spacing: 4
             ScrollingGraph {
                 controlId: Controller.Actions.Yaw
                 label: "Yaw"
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
index 91b11115d9..1af3f271be 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp
@@ -20,19 +20,13 @@
 
 using namespace controller;
 
-QObject* MappingBuilderProxy::from(int input) {
-    qCDebug(controllers) << "Creating new Route builder proxy from " << input;
-    auto sourceEndpoint = _parent.endpointFor(Input(input));
-    return from(sourceEndpoint);
-}
-
-QObject* MappingBuilderProxy::fromQmlFunction(const QJSValue& source) {
+QObject* MappingBuilderProxy::fromQml(const QJSValue& source) {
     qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString();
     auto sourceEndpoint = _parent.endpointFor(source);
     return from(sourceEndpoint);
 }
 
-QObject* MappingBuilderProxy::fromFunction(const QScriptValue& source) {
+QObject* MappingBuilderProxy::from(const QScriptValue& source) {
     qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString();
     auto sourceEndpoint = _parent.endpointFor(source);
     return from(sourceEndpoint);
@@ -49,9 +43,15 @@ QObject* MappingBuilderProxy::from(const Endpoint::Pointer& source) {
     }
 }
 
-QObject* MappingBuilderProxy::makeAxis(int source1, int source2) {
-    auto source1Endpoint = _parent.endpointFor(Input(source1));
-    auto source2Endpoint = _parent.endpointFor(Input(source2));
+QObject* MappingBuilderProxy::makeAxisQml(const QJSValue& source1, const QJSValue& source2) {
+    auto source1Endpoint = _parent.endpointFor(source1);
+    auto source2Endpoint = _parent.endpointFor(source2);
+    return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint));
+}
+
+QObject* MappingBuilderProxy::makeAxis(const QScriptValue& source1, const QScriptValue& source2) {
+    auto source1Endpoint = _parent.endpointFor(source1);
+    auto source2Endpoint = _parent.endpointFor(source2);
     return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint));
 }
 
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index 06ffcd8ea3..93aa022647 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -32,10 +32,11 @@ public:
     MappingBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping)
         : _parent(parent), _mapping(mapping) { }
 
-    Q_INVOKABLE QObject* from(int sourceInput);
-    Q_INVOKABLE QObject* fromQmlFunction(const QJSValue& source);
-    Q_INVOKABLE QObject* fromFunction(const QScriptValue& source);
-    Q_INVOKABLE QObject* makeAxis(int source1, const int source2);
+    Q_INVOKABLE QObject* fromQml(const QJSValue& source);
+    Q_INVOKABLE QObject* makeAxisQml(const QJSValue& source1, const QJSValue& source2);
+
+    Q_INVOKABLE QObject* from(const QScriptValue& source);
+    Q_INVOKABLE QObject* makeAxis(const QScriptValue& source1, const QScriptValue& source2);
 
     Q_INVOKABLE QObject* enable(bool enable = true);
     Q_INVOKABLE QObject* disable() { return enable(false); }
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index 14bcbca80e..186cf2e84e 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -20,13 +20,7 @@
 
 using namespace controller;
 
-void RouteBuilderProxy::to(int destinationInput) {
-    qCDebug(controllers) << "Completing route " << destinationInput;
-    auto destinationEndpoint = _parent.endpointFor(Input(destinationInput));
-    return to(destinationEndpoint);
-}
-
-void RouteBuilderProxy::to(const QJSValue& destination) {
+void RouteBuilderProxy::toQml(const QJSValue& destination) {
     qCDebug(controllers) << "Completing route " << destination.toString();
     auto destinationEndpoint = _parent.endpointFor(destination);
     return to(destinationEndpoint);
@@ -45,7 +39,7 @@ void RouteBuilderProxy::to(const Endpoint::Pointer& destination) {
     deleteLater();
 }
 
-QObject* RouteBuilderProxy::filter(const QJSValue& expression) {
+QObject* RouteBuilderProxy::filterQml(const QJSValue& expression) {
     if (expression.isCallable()) {
         addFilter([=](float value) {
             QJSValue originalExpression = expression;
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 1b66a3d996..6bceba995a 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -31,11 +31,10 @@ class RouteBuilderProxy : public QObject {
         RouteBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping, Route::Pointer route)
             : _parent(parent), _mapping(mapping), _route(route) { }
 
-        Q_INVOKABLE void to(int destination);
-        Q_INVOKABLE void to(const QJSValue& destination);
-        Q_INVOKABLE void to(const QScriptValue& destination);
+        Q_INVOKABLE void toQml(const QJSValue& destination);
+        Q_INVOKABLE QObject* filterQml(const QJSValue& expression);
 
-        Q_INVOKABLE QObject* filter(const QJSValue& expression);
+        Q_INVOKABLE void to(const QScriptValue& destination);
         Q_INVOKABLE QObject* filter(const QScriptValue& expression);
         Q_INVOKABLE QObject* clamp(float min, float max);
         Q_INVOKABLE QObject* pulse(float interval);

From 6cf0bdcffede8b783b7255b19c0e31505c8a38db Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 10:00:11 -0700
Subject: [PATCH 098/301] Testing function destination and fixing bug in rule
 ordering for multi-soure

---
 examples/tests/controllerInterfaceTest.js     | 14 ++++++++++++-
 .../src/controllers/UserInputMapper.cpp       | 21 +++++++++++++++----
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/examples/tests/controllerInterfaceTest.js b/examples/tests/controllerInterfaceTest.js
index a4e0557c78..0dccd1209a 100644
--- a/examples/tests/controllerInterfaceTest.js
+++ b/examples/tests/controllerInterfaceTest.js
@@ -1,11 +1,13 @@
 ControllerTest = function() {
     var standard = Controller.Standard;
     var actions = Controller.Actions;
+    var xbox = Controller.Hardware.GamePad;
     this.mappingEnabled = false;
     this.mapping = Controller.newMapping();
     this.mapping.from(standard.RX).to(actions.StepYaw);
     this.mapping.from(standard.RY).invert().to(actions.Pitch);
 
+
     var testMakeAxis = false;
     if (testMakeAxis) {
         this.mapping.makeAxis(standard.LB, standard.RB).pulse(0.25).scale(40.0).to(actions.StepYaw);
@@ -17,12 +19,22 @@ ControllerTest = function() {
         this.mapping.from(standard.RB).pulse(0.10).scale(15.0).to(actions.StepYaw);
     }
     
-    var testFunctionSource = true;
+    var testFunctionSource = false;
     if (testFunctionSource) {
         this.mapping.from(function(){
             return Math.sin(Date.now() / 250); 
         }).to(actions.Yaw);
     }
+    
+    var testFunctionDest = true;
+    if (testFunctionDest) {
+        this.mapping.from(standard.DU).pulse(1.0).to(function(value){
+            if (value != 0.0) {
+                print(value);
+            }
+        });
+
+    }
 
     this.mapping.enable();
     this.mappingEnabled = true;
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index f1138479bf..107b6f8192 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -195,7 +195,20 @@ class AnyEndpoint : public Endpoint {
     friend class UserInputMapper;
 public:
     using Pointer = std::shared_ptr<AnyEndpoint>;
-    AnyEndpoint() : Endpoint(Input::INVALID_INPUT) {}
+    AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPUT), _children(children) {
+        bool standard = true;
+        // Ensure if we're building a composite of standard devices the composite itself
+        // is treated as a standard device for rule processing order
+        for (auto endpoint : children) {
+            if (endpoint->getInput().device != UserInputMapper::STANDARD_DEVICE) {
+                standard = false;
+                break;
+            }
+        }
+        if (standard) {
+            this->_input = INVALID_STANDARD_INPUT;
+        }
+    }
 
     virtual float value() override {
         float result = 0;
@@ -1020,15 +1033,15 @@ Endpoint::Pointer UserInputMapper::parseDestination(const QJsonValue& value) {
 
 Endpoint::Pointer UserInputMapper::parseSource(const QJsonValue& value) {
     if (value.isArray()) {
-        AnyEndpoint::Pointer result = std::make_shared<AnyEndpoint>();
+        Endpoint::List children;
         for (auto arrayItem : value.toArray()) {
             Endpoint::Pointer destination = parseEndpoint(arrayItem);
             if (!destination) {
                 return Endpoint::Pointer();
             }
-            result->_children.push_back(destination);
+            children.push_back(destination);
         }
-        return result;
+        return std::make_shared<AnyEndpoint>(children);
     }
 
     return parseEndpoint(value);

From 67f2a0c6c803263171a98ab02588079beb1a4ba8 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 22 Oct 2015 11:39:51 -0700
Subject: [PATCH 099/301] CR feedback on mappings

---
 interface/resources/controllers/standard.json | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 2067d98380..5d6e8ce32f 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -12,10 +12,10 @@
         { "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" },
         { "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" },
 
-        { "from": "Standard.LT", "to": "Actions.LEFT_HAND_CLICK" }, 
-        { "from": "Standard.RT", "to": "Actions.RIGHT_HAND_CLICK" },
+        { "from": "Standard.LT", "to": "Actions.LeftHandClick" }, 
+        { "from": "Standard.RT", "to": "Actions.RightHandClick" },
 
-        { "from": "Standard.LeftHand", "to": "Actions.LEFT_HAND" }, 
-        { "from": "Standard.RightHand", "to": "Actions.RIGHT_HAND" }
+        { "from": "Standard.LeftHand", "to": "Actions.LeftHand" }, 
+        { "from": "Standard.RightHand", "to": "Actions.RightHand" }
     ]
 }

From b5ccd49959bbb2d8706e6edbafb8d9c5a9e90595 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 22 Oct 2015 11:42:50 -0700
Subject: [PATCH 100/301] Make ubuntu happy.

---
 libraries/animation/src/Rig.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index c29bb6ad04..648a7f2c16 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -37,6 +37,7 @@
 #define __hifi__Rig__
 
 #include <QObject>
+#include <QMutex>
 #include <QScriptValue>
 
 #include "JointState.h"  // We might want to change this (later) to something that doesn't depend on gpu, fbx and model. -HRS

From 30429e8138776e3f56d2effc82972fb43dd26b3b Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 22 Oct 2015 11:43:22 -0700
Subject: [PATCH 101/301] Don't use late-breaking results that got reported
 after the handler was removed.

---
 libraries/animation/src/Rig.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 14aef88e2f..2a64114112 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -619,6 +619,9 @@ void Rig::removeAnimationStateHandler(QScriptValue handler) { // called in scrip
 void Rig::animationStateHandlerResult(QScriptValue handler, QScriptValue result) { // called synchronously from script
     // handler is currently ignored but might be used in storing individual results
     QMutexLocker locker(&_stateMutex);
+    if (!_stateHandlers.isValid()) {
+        return; // Don't use late-breaking results that got reported after the handler was removed.
+    }
     _stateHandlersResults.animVariantMapFromScriptValue(result); // Into our own copy.
 }
 void Rig::updateAnimationStateHandlers() { // called on avatar update thread (which may be main thread)

From c826b48c92d189c80c6109183b018f2769a2ddf3 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 22 Oct 2015 15:05:59 -0700
Subject: [PATCH 102/301] fix airGuitar.js

---
 examples/controllers/hydra/airGuitar.js | 163 ++++++++++++++----------
 1 file changed, 95 insertions(+), 68 deletions(-)

diff --git a/examples/controllers/hydra/airGuitar.js b/examples/controllers/hydra/airGuitar.js
index 7fbbfc48bd..b286cc6084 100644
--- a/examples/controllers/hydra/airGuitar.js
+++ b/examples/controllers/hydra/airGuitar.js
@@ -32,6 +32,8 @@ var guitarModel = HIFI_PUBLIC_BUCKET + "models/attachments/guitar.fst";
 
 //  Load sounds that will be played
 
+var heyManWave = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav");
+
 var chords = new Array();
 // Nylon string guitar
 chords[1] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+A.raw");
@@ -56,96 +58,121 @@ var NUM_GUITARS = 3;
 var guitarSelector = NUM_CHORDS;
 var whichChord = 1;
 
-var leftHanded = true; 
+var leftHanded = false;
+var strumHand, chordHand, strumTrigger, chordTrigger;
 if (leftHanded) {
-    var strumHand = 0;
-    var chordHand = 1; 
+    strumHand = Controller.Standard.LeftHand;
+    chordHand = Controller.Standard.RightHand;
+    strumTrigger = Controller.Standard.LT;
+    chordTrigger = Controller.Standard.RT;
+    changeGuitar = Controller.Standard.RB;
+    chord1 = Controller.Standard.X;
+    chord2 = Controller.Standard.Y;
+    chord3 = Controller.Standard.A;
+    chord4 = Controller.Standard.B;
 } else {
-    var strumHand = 1;
-    var chordHand = 0;
+    strumHand = Controller.Standard.RightHand;
+    chordHand = Controller.Standard.LeftHand;
+    strumTrigger = Controller.Standard.RT;
+    chordTrigger = Controller.Standard.LT;
+    changeGuitar = Controller.Standard.LB;
+    chord1 = Controller.Standard.DU; // these may not be correct, maybe we should map directly to Hydra??
+    chord2 = Controller.Standard.DD;
+    chord3 = Controller.Standard.DL;
+    chord4 = Controller.Standard.DR;
 }
 
 var lastPosition = { x: 0.0,
                  y: 0.0, 
                  z: 0.0 }; 
 
-var soundPlaying = false; 
+var audioInjector = null;
 var selectorPressed = false;
 var position;
 
 MyAvatar.attach(guitarModel, "Hips", {x: -0.2, y: 0.0, z: 0.1}, Quat.fromPitchYawRollDegrees(90, 00, 90), 1.0);
 
 function checkHands(deltaTime) {
-    for (var palm = 0; palm < 2; palm++) {
-        var palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1);
-        var volume = length(palmVelocity) / 5.0;
-        var position = Controller.getSpatialControlPosition(palm * 2 + 1);
-        var myPelvis = MyAvatar.position;
-        var trigger = Controller.getTriggerValue(strumHand);
-        var chord = Controller.getTriggerValue(chordHand);
+    var strumVelocity = Controller.getPoseValue(strumHand).velocity;
+    var volume = length(strumVelocity) / 5.0;
 
-        if (volume > 1.0) volume = 1.0;
-        if ((chord > 0.1) && soundPlaying.isPlaying) {
-            // If chord finger trigger pulled, stop current chord
-            print("stopped sound");
-            soundPlaying.stop();
-        }
-
-        var BUTTON_COUNT = 6;
-
-        //  Change guitars if button FWD (5) pressed
-        if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 5)) {
-            if (!selectorPressed) {
-                guitarSelector += NUM_CHORDS;
-                if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) {
-                    guitarSelector = 0;
-                } 
-                selectorPressed = true;
-            }
-        } else {
-            selectorPressed = false;
-        }
-
-        if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 1)) {
-            whichChord = 1;
-        } else if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 2)) {
-            whichChord = 2;
-        } else if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 3)) {
-            whichChord = 3;
-        } else if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 4)) {
-              whichChord = 4;
-        }
-
-        if (palm == strumHand) {
-
-            var STRUM_HEIGHT_ABOVE_PELVIS = 0.10;
-            var strumTriggerHeight = myPelvis.y + STRUM_HEIGHT_ABOVE_PELVIS;
-            //printVector(position);
-            if ( ( ((position.y < strumTriggerHeight) && (lastPosition.y >= strumTriggerHeight)) ||
-                   ((position.y > strumTriggerHeight) && (lastPosition.y <= strumTriggerHeight)) ) && (trigger > 0.1) ){
-                // If hand passes downward or upward through 'strings', and finger trigger pulled, play
-                playChord(position, volume);
-            }
-            lastPosition = Controller.getSpatialControlPosition(palm * 2 + 1);
-        } 
+    if (volume == 0.0) {
+        volume = 1.0;
     }
+
+    var strumHandPosition = leftHanded ? MyAvatar.leftHandPosition : MyAvatar.rightHandPosition;
+    var myPelvis = MyAvatar.position;
+    var strumming = Controller.getValue(strumTrigger);
+    var chord = Controller.getValue(chordTrigger);
+
+    if (volume > 1.0) volume = 1.0;
+    if ((chord > 0.1) && audioInjector && audioInjector.isPlaying) {
+        // If chord finger trigger pulled, stop current chord
+        print("stopping chord because cord trigger pulled");
+        audioInjector.stop();
+    }
+
+    //  Change guitars if button FWD (5) pressed
+    if (Controller.getValue(changeGuitar)) {
+        print("changeGuitar:" + changeGuitar);
+        if (!selectorPressed) {
+            guitarSelector += NUM_CHORDS;
+            if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) {
+                guitarSelector = 0;
+            } 
+            selectorPressed = true;
+        }
+    } else {
+        selectorPressed = false;
+    }
+    //print("selectorPressed:" + selectorPressed);
+
+    if (Controller.getValue(chord1)) {
+        whichChord = 1;
+    } else if (Controller.getValue(chord2)) {
+        whichChord = 2;
+    } else if (Controller.getValue(chord3)) {
+        whichChord = 3;
+    } else if (Controller.getValue(chord4)) {
+        whichChord = 4;
+    }
+
+    var STRUM_HEIGHT_ABOVE_PELVIS = 0.10;
+    var strummingHeight = myPelvis.y + STRUM_HEIGHT_ABOVE_PELVIS;
+
+    var strumNowAbove = strumHandPosition.y > strummingHeight;
+    var strumNowBelow = strumHandPosition.y <= strummingHeight;
+    var strumWasAbove = lastPosition.y > strummingHeight;
+    var strumWasBelow = lastPosition.y <= strummingHeight;
+    var strumUp = strumNowAbove && strumWasBelow;
+    var strumDown = strumNowBelow && strumWasAbove;
+
+    if ((strumUp || strumDown) && (strumming > 0.1)) {
+        // If hand passes downward or upward through 'strings', and finger trigger pulled, play
+        playChord(strumHandPosition, volume);
+    }
+    lastPosition = strumHandPosition;
 }
 
 function playChord(position, volume) {
-    if (soundPlaying.isPlaying) {
+    if (audioInjector && audioInjector.isPlaying) {
         print("stopped sound");
-        soundPlaying.stop();
+        audioInjector.stop();
     }
   
-    print("Played sound: " + whichChord + " at volume " + options.volume);
-  if (!soundPlaying) {
-      soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], {
-        position: position,
-      volume: volume
-      });    
-  } else {
-    soundPlaying.restart();
-  }
+    print("Played sound: " + whichChord + " at volume " + volume);
+    if (!audioInjector) {
+
+        // FIXME - we apparenlty broke RAW file playback, so we need WAV files for all these chords. In the mean
+        // time, we will just play the heyMan wave file for all chords
+        var chord = heyManWave; // chords[guitarSelector + whichChord];
+
+        audioInjector = Audio.playSound(chord, { position: position, volume: volume });
+        print("audioInjector: " + JSON.stringify(audioInjector));
+    } else {
+        print("audioInjector: " + JSON.stringify(audioInjector));
+        audioInjector.restart();
+    }
     
 }
 

From 759e6525069991a04005910cc36b514ffa876122 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 22 Oct 2015 15:13:14 -0700
Subject: [PATCH 103/301] Thread test per comments.

---
 libraries/animation/src/AnimVariantMap.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
index 0154c9698a..219a44b644 100644
--- a/libraries/animation/src/AnimVariantMap.cpp
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -11,10 +11,15 @@
 
 #include <QScriptEngine>
 #include <QScriptValueIterator>
+#include <QThread.h>
 #include <RegisteredMetaTypes.h>
 #include "AnimVariant.h"
 
 QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine) const {
+    if (QThread::currentThread() != engine->thread()) {
+        qCWarning(animation) << "Cannot create Javacript object from non-script thread" << QThread::currentThread();
+        return QScriptValue();
+    }
     QScriptValue target = engine->newObject();
     for (auto& pair : _map) {
         switch (pair.second.getType()) {

From 1d0464ede5d118be676e8ea9daf9821ef9d6c88f Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 22 Oct 2015 15:15:10 -0700
Subject: [PATCH 104/301] Name change and thread checks per comments.

---
 interface/src/avatar/MyAvatar.h              |  2 +-
 libraries/animation/src/Rig.cpp              |  3 +-
 libraries/script-engine/src/ScriptEngine.cpp | 29 ++++++++++----------
 libraries/script-engine/src/ScriptEngine.h   |  3 +-
 4 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 1ce72cb33f..4f32989bf5 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -118,7 +118,7 @@ public:
     Q_INVOKABLE void addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { _rig->addAnimationStateHandler(handler, propertiesList); }
     // Removes a handler previously added by addAnimationStateHandler.
     Q_INVOKABLE void removeAnimationStateHandler(QScriptValue handler) { _rig->removeAnimationStateHandler(handler); }
-    // Processes a handler result. Not really for user code, but used by invokeAnimationCallback.
+    // Processes a handler result. Not really for user code, but used by callAnimationStateHandler.
     Q_INVOKABLE void animationStateHandlerResult(QScriptValue handler, QScriptValue result) { _rig->animationStateHandlerResult(handler, result); }
 
     // get/set avatar data
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 2a64114112..0437e9cca8 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -624,11 +624,12 @@ void Rig::animationStateHandlerResult(QScriptValue handler, QScriptValue result)
     }
     _stateHandlersResults.animVariantMapFromScriptValue(result); // Into our own copy.
 }
+
 void Rig::updateAnimationStateHandlers() { // called on avatar update thread (which may be main thread)
     if (_stateHandlers.isValid()) {
         // invokeMethod makes a copy of the args, and copies of AnimVariantMap do copy the underlying map, so this will correctly capture
         // the state of _animVars and allow continued changes to _animVars in this thread without conflict.
-        QMetaObject::invokeMethod(_stateHandlers.engine(), "invokeAnimationCallback",  Qt::QueuedConnection,
+        QMetaObject::invokeMethod(_stateHandlers.engine(), "callAnimationStateHandler",  Qt::QueuedConnection,
                                   Q_ARG(QScriptValue, _stateHandlers),
                                   Q_ARG(AnimVariantMap, _animVars));
     }
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 0ec1a09d6d..5808340855 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -259,7 +259,7 @@ void ScriptEngine::errorInLoadingScript(const QUrl& url) {
 }
 
 // Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of
-// invokeAnimationCallback requires that the type be registered.
+// callAnimationStateHandler requires that the type be registered.
 static QScriptValue animVarMapToScriptValue(QScriptEngine* engine, const AnimVariantMap& parameters) {
     return parameters.animVariantMapToScriptValue(engine);
 }
@@ -340,7 +340,7 @@ void ScriptEngine::init() {
 void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
     if (QThread::currentThread() != thread()) {
 #ifdef THREAD_DEBUGGING
-        qDebug() << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]  name:" << name;
+        qDebug() << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
 #endif
         QMetaObject::invokeMethod(this, "registerValue",
             Q_ARG(const QString&, valueName),
@@ -729,8 +729,16 @@ void ScriptEngine::stop() {
 }
 
 // Other threads can invoke this through invokeMethod, which causes the callback to be asynchronously executed in this script's thread.
-void ScriptEngine::invokeAnimationCallback(QScriptValue callback, AnimVariantMap parameters) {
-    checkThread();
+void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters) {
+    if (QThread::currentThread() != thread()) {
+#ifdef THREAD_DEBUGGING
+        qDebug() << "*** WARNING *** ScriptEngine::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]  name:" << name;
+#endif
+        QMetaObject::invokeMethod(this, "callAnimationStateHandler",
+                                  Q_ARG(QScriptValue, callback),
+                                  Q_ARG(AnimVariantMap, parameters));
+        return;
+    }
     QScriptValue javascriptParametgers = parameters.animVariantMapToScriptValue(this);
     QScriptValueList callingArguments;
     callingArguments << javascriptParametgers;
@@ -923,19 +931,12 @@ void ScriptEngine::load(const QString& loadFile) {
     }
 }
 
-bool ScriptEngine::checkThread() const {
+// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
+void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) {
     if (QThread::currentThread() != thread()) {
         qDebug() << "*** ERROR *** ScriptEngine::generalHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
         assert(false);
-        return true;
-    }
-    return false;
-}
-
-// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
-void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) {
-    if (checkThread()) {
-        return;
+        return ;
     }
     if (!_registeredHandlers.contains(entityID)) {
         return;
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index 77f1e2d5f1..7500e1d776 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -144,7 +144,7 @@ public:
     ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; }
 
 public slots:
-    void invokeAnimationCallback(QScriptValue callback, AnimVariantMap parameters);
+    void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters);
 
 signals:
     void scriptLoaded(const QString& scriptFilename);
@@ -173,7 +173,6 @@ protected:
     bool _wantSignals = true;
     QHash<EntityItemID, EntityScriptDetails> _entityScripts;
 private:
-    bool checkThread() const;
     void init();
     QString getFilename() const;
     void waitTillDoneRunning();

From ecc920199d6752671fabea491c24779c0b7b32f2 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 22 Oct 2015 15:24:24 -0700
Subject: [PATCH 105/301] Return id suitable for use with remover, per
 comments.

---
 interface/src/avatar/MyAvatar.h | 2 +-
 libraries/animation/src/Rig.cpp | 3 ++-
 libraries/animation/src/Rig.h   | 2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 4f32989bf5..435e6af5ef 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -115,7 +115,7 @@ public:
     // adding one of the other handlers. While any handler may change a value in animStateDictionaryIn (or supply different values in animStateDictionaryOut)
     // a handler must not remove properties from animStateDictionaryIn, nor change property values that it does not intend to change.
     // It is not specified in what order multiple handlers are called.
-    Q_INVOKABLE void addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { _rig->addAnimationStateHandler(handler, propertiesList); }
+    Q_INVOKABLE QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { return _rig->addAnimationStateHandler(handler, propertiesList); }
     // Removes a handler previously added by addAnimationStateHandler.
     Q_INVOKABLE void removeAnimationStateHandler(QScriptValue handler) { _rig->removeAnimationStateHandler(handler); }
     // Processes a handler result. Not really for user code, but used by callAnimationStateHandler.
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 0437e9cca8..b4113fd4a5 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -608,8 +608,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
 // Allow script to add/remove handlers and report results, from within their thread.
 // TODO: iterate multiple handlers, but with one shared arg.
 // TODO: fill the properties based on the union of requested properties. (Keep all properties objs and compute new union when add/remove handler.)
-void Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { // called in script thread
+QScriptValue Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { // called in script thread
     _stateHandlers = handler;
+    return handler; // suitable for giving to removeAnimationStateHandler
 }
 void Rig::removeAnimationStateHandler(QScriptValue handler) { // called in script thread
     _stateHandlers = QScriptValue();
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index 648a7f2c16..83f1a02b8a 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -201,7 +201,7 @@ public:
     AnimNode::ConstPointer getAnimNode() const { return _animNode; }
     AnimSkeleton::ConstPointer getAnimSkeleton() const { return _animSkeleton; }
     bool disableHands {false}; // should go away with rig animation (and Rig::inverseKinematics)
-    void addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList);
+    QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList);
     void removeAnimationStateHandler(QScriptValue handler);
     void animationStateHandlerResult(QScriptValue handler, QScriptValue result);
 

From f0a4e25e895017a4fb75f593564669761fb09e16 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 22 Oct 2015 15:25:14 -0700
Subject: [PATCH 106/301] Name change per comments.

---
 interface/src/avatar/AvatarManager.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h
index c71f2bc25b..ffc7cc8f92 100644
--- a/interface/src/avatar/AvatarManager.h
+++ b/interface/src/avatar/AvatarManager.h
@@ -53,9 +53,11 @@ public:
     Q_INVOKABLE void setLocalLights(const QVector<AvatarManager::LocalLight>& localLights);
     Q_INVOKABLE QVector<AvatarManager::LocalLight> getLocalLights() const;
     // Currently, your own avatar will be included as the null avatar id.
-    Q_INVOKABLE QVector<QUuid> getAvatars() const { return _avatarHash.keys().toVector(); }
+    Q_INVOKABLE QVector<QUuid> getAvatarIdentifiers() const { return _avatarHash.keys().toVector(); } // FIXME: see #6154
+    Q_INVOKABLE QVector<QUuid> getAvatars() const { return getAvatarIdentifiers(); } // FIXME: remove before merge. Compatability for testing scripts.
     // Minor Bug: A bogus avatarID answers your own avatar.
-    Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID) const { return _avatarHash[avatarID].get(); }
+    Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID) const { return _avatarHash[avatarID].get(); } // FIXME: see #6154
+
 
     void getObjectsToDelete(VectorOfMotionStates& motionStates);
     void getObjectsToAdd(VectorOfMotionStates& motionStates);

From 913842ac30575a208d7ed9c7ec0affc8b4e94eaa Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 22 Oct 2015 15:31:17 -0700
Subject: [PATCH 107/301] Thread check, for consistency.

---
 libraries/animation/src/AnimVariantMap.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
index 219a44b644..170662f092 100644
--- a/libraries/animation/src/AnimVariantMap.cpp
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -54,6 +54,10 @@ void AnimVariantMap::copyVariantsFrom(const AnimVariantMap& other) {
     }
 }
 void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) {
+    if (QThread::currentThread() != source.engine()->thread()) {
+        qCWarning(animation) << "Cannot examine Javacript object from non-script thread" << QThread::currentThread();
+        return;
+    }
     // POTENTIAL OPTIMIZATION: cache the types we've seen. I.e, keep a dictionary mapping property names to an enumeration of types.
     // Whenever we identify a new outbound type in animVariantMapToScriptValue above, or a new inbound type in the code that follows here,
     // we would enter it into the dictionary. Then switch on that type here, with the code that follow being executed only if

From 471f43899d288e8fcad0c480e0ddc5769988cc07 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 15:49:27 -0700
Subject: [PATCH 108/301] Moving aliases / bisected versions below main actions

---
 .../controllers/src/controllers/Actions.cpp   | 26 ++++++++++---------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp
index b0d2d24edf..a9bd32b1d8 100644
--- a/libraries/controllers/src/controllers/Actions.cpp
+++ b/libraries/controllers/src/controllers/Actions.cpp
@@ -48,18 +48,6 @@ namespace controller {
                 makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateX"),
                 makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateY"),
                 makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateZ"),
-                makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),
-                makeAxisPair(Action::LONGITUDINAL_FORWARD, "Forward"),
-                makeAxisPair(Action::LATERAL_LEFT, "StrafeLeft"),
-                makeAxisPair(Action::LATERAL_RIGHT, "StrafeRight"),
-                makeAxisPair(Action::VERTICAL_DOWN, "Down"),
-                makeAxisPair(Action::VERTICAL_UP, "Up"),
-                makeAxisPair(Action::YAW_LEFT, "YawLeft"),
-                makeAxisPair(Action::YAW_RIGHT, "YawRight"),
-                makeAxisPair(Action::PITCH_DOWN, "PitchDown"),
-                makeAxisPair(Action::PITCH_UP, "PitchUp"),
-                makeAxisPair(Action::BOOM_IN, "BoomIn"),
-                makeAxisPair(Action::BOOM_OUT, "BoomOut"),
 
                 makePosePair(Action::LEFT_HAND, "LeftHand"),
                 makePosePair(Action::RIGHT_HAND, "RightHand"),
@@ -73,6 +61,20 @@ namespace controller {
                 makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"),
                 makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"),
 
+                // Aliases and bisected versions
+                makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),
+                makeAxisPair(Action::LONGITUDINAL_FORWARD, "Forward"),
+                makeAxisPair(Action::LATERAL_LEFT, "StrafeLeft"),
+                makeAxisPair(Action::LATERAL_RIGHT, "StrafeRight"),
+                makeAxisPair(Action::VERTICAL_DOWN, "Down"),
+                makeAxisPair(Action::VERTICAL_UP, "Up"),
+                makeAxisPair(Action::YAW_LEFT, "YawLeft"),
+                makeAxisPair(Action::YAW_RIGHT, "YawRight"),
+                makeAxisPair(Action::PITCH_DOWN, "PitchDown"),
+                makeAxisPair(Action::PITCH_UP, "PitchUp"),
+                makeAxisPair(Action::BOOM_IN, "BoomIn"),
+                makeAxisPair(Action::BOOM_OUT, "BoomOut"),
+
                 // Deprecated aliases
                 // FIXME remove after we port all scripts
                 makeAxisPair(Action::LONGITUDINAL_BACKWARD, "LONGITUDINAL_BACKWARD"),

From 8c163a52e9a005dc3b027203c531dce81f190966 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 15:49:58 -0700
Subject: [PATCH 109/301] Attempting to fix log graphs

---
 interface/resources/qml/ScrollingGraph.qml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/interface/resources/qml/ScrollingGraph.qml b/interface/resources/qml/ScrollingGraph.qml
index 26ca9a61ff..55523a23f4 100644
--- a/interface/resources/qml/ScrollingGraph.qml
+++ b/interface/resources/qml/ScrollingGraph.qml
@@ -23,6 +23,11 @@ Rectangle {
 
     function update() {
         value = Controller.getValue(controlId);
+        if (log) {
+            var log = Math.log(10) / Math.log(Math.abs(value));
+            var sign = Math.sign(value);
+            value = log * sign;
+        }
         canvas.requestPaint();
     }
 

From d1da2f5aab07ec445cdbbce323b6ed139e2b5375 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 15:51:09 -0700
Subject: [PATCH 110/301] Adding more items to the standard controller
 abstraction

---
 .../src/controllers/StandardController.cpp    | 20 +++++++++++++++----
 .../src/controllers/StandardControls.h        |  8 ++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index 5734174284..fc62f85b81 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -73,10 +73,26 @@ void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
         availableInputs.append(makePair(LT, "LT"));
         availableInputs.append(makePair(RT, "RT"));
 
+
+        // Finger abstractions
+        availableInputs.append(makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"));
+        availableInputs.append(makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"));
+        availableInputs.append(makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"));
+        availableInputs.append(makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"));
+
+        availableInputs.append(makePair(LEFT_PRIMARY_INDEX, "LeftPrimaryIndex"));
+        availableInputs.append(makePair(LEFT_SECONDARY_INDEX, "LeftSecondaryIndex"));
+        availableInputs.append(makePair(RIGHT_PRIMARY_INDEX, "RightPrimaryIndex"));
+        availableInputs.append(makePair(RIGHT_SECONDARY_INDEX, "RightSecondaryIndex"));
+
+        availableInputs.append(makePair(LEFT_GRIP, "LeftGrip"));
+        availableInputs.append(makePair(RIGHT_GRIP, "RightGrip"));
+
         // Poses
         availableInputs.append(makePair(LEFT_HAND, "LeftHand"));
         availableInputs.append(makePair(RIGHT_HAND, "RightHand"));
 
+
         // Aliases, PlayStation style names
         availableInputs.append(makePair(LB, "L1"));
         availableInputs.append(makePair(RB, "R1"));
@@ -95,10 +111,6 @@ void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
         availableInputs.append(makePair(DR, "Right"));
 
 
-        availableInputs.append(makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"));
-        availableInputs.append(makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"));
-        availableInputs.append(makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"));
-        availableInputs.append(makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"));
 
         return availableInputs;
     };
diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h
index b051f68c13..066a3e5e60 100644
--- a/libraries/controllers/src/controllers/StandardControls.h
+++ b/libraries/controllers/src/controllers/StandardControls.h
@@ -42,6 +42,14 @@ namespace controller {
         RIGHT_PRIMARY_THUMB,
         RIGHT_SECONDARY_THUMB,
 
+        LEFT_PRIMARY_INDEX,
+        LEFT_SECONDARY_INDEX,
+        RIGHT_PRIMARY_INDEX,
+        RIGHT_SECONDARY_INDEX,
+
+        LEFT_GRIP,
+        RIGHT_GRIP,
+
         NUM_STANDARD_BUTTONS
     };
 

From e40741b5cb52bcfad1a18934b5fe365d0e439029 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 15:52:10 -0700
Subject: [PATCH 111/301] Removing overrides / loopback support, adding route
 debugging

---
 libraries/controllers/src/controllers/Route.h |  2 +
 .../src/controllers/UserInputMapper.cpp       | 64 +++++++++++--------
 .../src/controllers/UserInputMapper.h         |  1 -
 3 files changed, 39 insertions(+), 28 deletions(-)

diff --git a/libraries/controllers/src/controllers/Route.h b/libraries/controllers/src/controllers/Route.h
index f290799482..5ad3d36628 100644
--- a/libraries/controllers/src/controllers/Route.h
+++ b/libraries/controllers/src/controllers/Route.h
@@ -24,6 +24,8 @@ namespace controller {
         Endpoint::Pointer destination;
         Conditional::Pointer conditional;
         Filter::List filters;
+        QString json;
+        bool debug { false };
 
         using Pointer = std::shared_ptr<Route>;
         using List = std::list<Pointer>;
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 107b6f8192..e73e4d0e68 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -655,7 +655,6 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
 
 void UserInputMapper::runMappings() {
     static auto deviceNames = getDeviceNames();
-    _overrides.clear();
 
     for (auto endpointEntry : this->_endpointsByInput) {
         endpointEntry.second->reset();
@@ -680,55 +679,55 @@ void UserInputMapper::runMappings() {
 
 
 void UserInputMapper::applyRoute(const Route::Pointer& route) {
+    if (route->debug) {
+        qCDebug(controllers) << "Applying route " << route->json;
+    }
+
     if (route->conditional) {
         if (!route->conditional->satisfied()) {
+            if (route->debug) {
+                qCDebug(controllers) << "Conditional failed";
+            }
             return;
         }
     }
 
     auto source = route->source;
-    if (_overrides.count(source)) {
-        source = _overrides[source];
-    }
 
-    // Endpoints can only be read once (though a given mapping can route them to 
+    // Most endpoints can only be read once (though a given mapping can route them to 
     // multiple places).  Consider... If the default is to wire the A button to JUMP
     // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
     // I press the button.  The exception is if I'm wiring a control back to itself
     // in order to adjust my interface, like inverting the Y axis on an analog stick
     if (!source->readable()) {
+        if (route->debug) {
+            qCDebug(controllers) << "Source unreadable";
+        }
         return;
     }
 
-
-    auto input = source->getInput();
-    float value = source->value();
-    if (value != 0.0) {
-        int i = 0;
-    }
-
     auto destination = route->destination;
     // THis could happen if the route destination failed to create
     // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
     if (!destination) {
+        if (route->debug) {
+            qCDebug(controllers) << "Bad Destination";
+        }
         return;
     }
 
-    // FIXME?, should come before or after the override logic?
     if (!destination->writeable()) {
+        if (route->debug) {
+            qCDebug(controllers) << "Destination unwritable";
+        }
         return;
     }
 
-    // Only consume the input if the route isn't a loopback.
-    // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
-    bool loopback = (source->getInput() == destination->getInput()) && (source->getInput() != Input::INVALID_INPUT);
-    // Each time we loop back we re-write the override 
-    if (loopback) {
-        _overrides[source] = destination = std::make_shared<StandardEndpoint>(source->getInput());
-    }
-
     // Fetch the value, may have been overriden by previous loopback routes
     if (source->isPose()) {
+        if (route->debug) {
+            qCDebug(controllers) << "Applying pose";
+        }
         Pose value = getPose(source);
         // no filters yet for pose
         destination->apply(value, Pose(), source);
@@ -736,11 +735,18 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
         // Fetch the value, may have been overriden by previous loopback routes
         float value = getValue(source);
 
+        if (route->debug) {
+            qCDebug(controllers) << "Value was " << value;
+        }
         // Apply each of the filters.
         for (const auto& filter : route->filters) {
             value = filter->apply(value);
         }
 
+        if (route->debug) {
+            qCDebug(controllers) << "Filtered value was " << value;
+        }
+
         destination->apply(value, 0, source);
     }
 }
@@ -850,11 +856,6 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
 
 float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const {
     Locker locker(_lock);
-    auto valuesIterator = _overrides.find(endpoint);
-    if (_overrides.end() != valuesIterator) {
-        return valuesIterator->second->value();
-    }
-
     return endpoint->value();
 }
 
@@ -900,6 +901,7 @@ Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) {
 static const QString JSON_NAME = QStringLiteral("name");
 static const QString JSON_CHANNELS = QStringLiteral("channels");
 static const QString JSON_CHANNEL_FROM = QStringLiteral("from");
+static const QString JSON_CHANNEL_DEBUG = QStringLiteral("debug");
 static const QString JSON_CHANNEL_WHEN = QStringLiteral("when");
 static const QString JSON_CHANNEL_TO = QStringLiteral("to");
 static const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
@@ -1052,9 +1054,12 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
         return Route::Pointer();
     }
 
-    const auto& obj = value.toObject();
+    auto obj = value.toObject();
     Route::Pointer result = std::make_shared<Route>();
+
+    result->json = QString(QJsonDocument(obj).toJson());
     result->source = parseSource(obj[JSON_CHANNEL_FROM]);
+    result->debug = obj[JSON_CHANNEL_DEBUG].toBool();
     if (!result->source) {
         qWarning() << "Invalid route source " << obj[JSON_CHANNEL_FROM];
         return Route::Pointer();
@@ -1067,6 +1072,11 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
         return Route::Pointer();
     }
 
+    if (result->source == result->destination) {
+        qWarning() << "Loopback routes not supported " << obj;
+        return Route::Pointer();
+    }
+
     if (obj.contains(JSON_CHANNEL_WHEN)) {
         auto conditionalsValue = obj[JSON_CHANNEL_WHEN];
         result->conditional = parseConditional(conditionalsValue);
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 70cd227e05..4bfedfcf1a 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -165,7 +165,6 @@ namespace controller {
         EndpointToInputMap _inputsByEndpoint;
         EndpointPairMap _compositeEndpoints;
 
-        EndpointOverrideMap _overrides;
         MappingNameMap _mappingsByName;
         MappingDeviceMap _mappingsByDevice;
 

From a9aea9b47712f467d12a3fef40adf33653ddfe15 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 15:53:19 -0700
Subject: [PATCH 112/301] Working on TestController display

---
 interface/resources/qml/TestControllers.qml | 31 +++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml
index a21735b3cc..482616203f 100644
--- a/interface/resources/qml/TestControllers.qml
+++ b/interface/resources/qml/TestControllers.qml
@@ -91,8 +91,7 @@ HifiControls.VrDialog {
             Hydra { device: root.hydra; width: 180 }
         }
         
-        Grid {
-            columns: 6
+        Row {
             spacing: 4
             ScrollingGraph {
                 controlId: Controller.Actions.Yaw
@@ -117,13 +116,41 @@ HifiControls.VrDialog {
                 max: 2.0
                 size: 64
             }
+
             ScrollingGraph {
                 controlId: Controller.Actions.StepYaw
                 label: "StepYaw"
+                min: -20.0
+                max: 20.0
+                size: 64
+            }
+        }
+
+        Row {
+            ScrollingGraph {
+                controlId: Controller.Actions.TranslateZ
+                label: "TranslateZ"
                 min: -2.0
                 max: 2.0
                 size: 64
             }
+
+            ScrollingGraph {
+                controlId: Controller.Actions.Forward
+                label: "Forward"
+                min: -2.0
+                max: 2.0
+                size: 64
+            }
+
+            ScrollingGraph {
+                controlId: Controller.Actions.Backward
+                label: "Backward"
+                min: -2.0
+                max: 2.0
+                size: 64
+            }
+
         }
     }
 } // dialog

From 2db87e0d2d094c0891f35a6eced4428e5af065d4 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 22 Oct 2015 15:55:36 -0700
Subject: [PATCH 113/301] Remove hydramove.js and expose the velocity and
 angular Velocity for hydra

---
 examples/controllers/hydra/hydraMove.js       | 303 ------------------
 .../src/input-plugins/SixenseManager.cpp      |  20 +-
 .../src/input-plugins/SixenseManager.h        |   2 +-
 3 files changed, 18 insertions(+), 307 deletions(-)
 delete mode 100644 examples/controllers/hydra/hydraMove.js

diff --git a/examples/controllers/hydra/hydraMove.js b/examples/controllers/hydra/hydraMove.js
deleted file mode 100644
index 46715839c3..0000000000
--- a/examples/controllers/hydra/hydraMove.js
+++ /dev/null
@@ -1,303 +0,0 @@
-//
-//  hydraMove.js
-//  examples
-//
-//  Created by Brad Hefta-Gaub on February 10, 2014
-//  Updated by Philip Rosedale on September 8, 2014
-//
-//  Copyright 2014 High Fidelity, Inc.
-//
-//  This is an example script that demonstrates use of the Controller and MyAvatar classes to implement
-//  avatar flying through the hydra/controller joysticks
-//
-//  The joysticks (on hydra) will drive the avatar much like a playstation controller. 
-// 
-//  Pressing the '4' or the 'FWD' button and moving/banking the hand will allow you to  move and fly.  
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-var damping = 0.9;
-var position = { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z };
-var joysticksCaptured = false;
-var THRUST_CONTROLLER = 0;
-var VIEW_CONTROLLER = 1;
-var INITIAL_THRUST_MULTIPLIER = 1.0;
-var THRUST_INCREASE_RATE = 1.05;
-var MAX_THRUST_MULTIPLIER = 75.0;
-var thrustMultiplier = INITIAL_THRUST_MULTIPLIER;
-var grabDelta = { x: 0, y: 0, z: 0};
-var grabStartPosition = { x: 0, y: 0, z: 0};
-var grabDeltaVelocity = { x: 0, y: 0, z: 0};
-var grabStartRotation = { x: 0, y: 0, z: 0, w: 1};
-var grabCurrentRotation = { x: 0, y: 0, z: 0, w: 1};
-var grabbingWithRightHand = false;
-var wasGrabbingWithRightHand = false;
-var grabbingWithLeftHand = false;
-var wasGrabbingWithLeftHand = false;
-
-var EPSILON = 0.000001;
-var velocity = { x: 0, y: 0, z: 0};
-var THRUST_MAG_UP = 100.0;
-var THRUST_MAG_DOWN = 100.0;
-var THRUST_MAG_FWD = 150.0;
-var THRUST_MAG_BACK = 100.0;
-var THRUST_MAG_LATERAL = 150.0;
-var THRUST_JUMP = 120.0;
-
-var YAW_MAG = 100.0;
-var PITCH_MAG = 100.0;
-var THRUST_MAG_HAND_JETS = THRUST_MAG_FWD;
-var JOYSTICK_YAW_MAG = YAW_MAG;
-var JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5;
-
-
-var LEFT_PALM = 0;
-var LEFT_BUTTON_4 = 4;
-var LEFT_BUTTON_FWD = 5;
-var RIGHT_PALM = 2;
-var RIGHT_BUTTON_4 = 10;
-var RIGHT_BUTTON_FWD = 11;
-
-
-
-function printVector(text, v, decimals) {
-    print(text + " " + v.x.toFixed(decimals) + ", " + v.y.toFixed(decimals) + ", " + v.z.toFixed(decimals));
-}
-
-var debug = false;
-var RED_COLOR = { red: 255, green: 0, blue: 0 };
-var GRAY_COLOR = { red: 25, green: 25, blue: 25 };
-var defaultPosition = { x: 0, y: 0, z: 0};
-var RADIUS = 0.05;
-var greenSphere = -1;
-var redSphere = -1;
- 
-function createDebugOverlay() {
-
-    if (greenSphere == -1) {
-        greenSphere = Overlays.addOverlay("sphere", {
-                                position: defaultPosition,
-                                size: RADIUS,
-                                color: GRAY_COLOR,
-                                alpha: 0.75,
-                                visible: true,
-                                solid: true,
-                                anchor: "MyAvatar"
-                                });
-        redSphere = Overlays.addOverlay("sphere", {
-                                position: defaultPosition,
-                                size: RADIUS,
-                                color: RED_COLOR,
-                                alpha: 0.5,
-                                visible: true,
-                                solid: true,
-                                anchor: "MyAvatar"
-                                });
-    }
-}
-
-function destroyDebugOverlay() {
-    if (greenSphere != -1) {
-        Overlays.deleteOverlay(greenSphere);
-        Overlays.deleteOverlay(redSphere);
-        greenSphere = -1;
-        redSphere = -1;
-    }
-}
-
-function displayDebug() {
-    if (!(grabbingWithRightHand || grabbingWithLeftHand)) {
-        if (greenSphere != -1) {
-            destroyDebugOverlay();
-        }
-    } else {
-        // update debug indicator
-        if (greenSphere == -1) {    
-            createDebugOverlay();
-        }
-
-        var displayOffset = { x:0, y:0.5, z:-0.5 };
-
-        Overlays.editOverlay(greenSphere, { position: Vec3.sum(grabStartPosition, displayOffset) } );
-        Overlays.editOverlay(redSphere, { position: Vec3.sum(Vec3.sum(grabStartPosition, grabDelta), displayOffset), size: RADIUS + (0.25 * Vec3.length(grabDelta)) } );
-    }
-}
-
-function getJoystickPosition(palm) {
-    // returns CONTROLLER_ID position in avatar local frame
-    var invRotation = Quat.inverse(MyAvatar.orientation);
-    var palmWorld = Controller.getSpatialControlPosition(palm);
-    var palmRelative = Vec3.subtract(palmWorld, MyAvatar.position);
-    var palmLocal = Vec3.multiplyQbyV(invRotation, palmRelative);
-    return palmLocal;
-}
-
-// Used by handleGrabBehavior() for managing the grab position changes
-function getAndResetGrabDelta() {
-    var HAND_GRAB_SCALE_DISTANCE = 2.0;
-    var delta = Vec3.multiply(grabDelta, (MyAvatar.scale * HAND_GRAB_SCALE_DISTANCE));
-    grabDelta = { x: 0, y: 0, z: 0};
-    var avatarRotation = MyAvatar.orientation;
-    var result = Vec3.multiplyQbyV(avatarRotation, Vec3.multiply(delta, -1));
-    return result;
-}
-
-function getGrabRotation() {
-    var quatDiff = Quat.multiply(grabCurrentRotation, Quat.inverse(grabStartRotation));
-    return quatDiff;
-}
-
-// When move button is pressed, process results 
-function handleGrabBehavior(deltaTime) {
-    // check for and handle grab behaviors
-    grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4);
-    grabbingWithLeftHand = Controller.isButtonPressed(LEFT_BUTTON_4);
-    stoppedGrabbingWithLeftHand = false;
-    stoppedGrabbingWithRightHand = false;
-    
-    if (grabbingWithRightHand && !wasGrabbingWithRightHand) {
-        // Just starting grab, capture starting rotation
-        grabStartRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
-        grabStartPosition = getJoystickPosition(RIGHT_PALM);
-        if (debug) printVector("start position", grabStartPosition, 3);
-    }
-    if (grabbingWithRightHand) {
-        grabDelta = Vec3.subtract(getJoystickPosition(RIGHT_PALM), grabStartPosition);
-        grabCurrentRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
-    }
-    if (!grabbingWithRightHand && wasGrabbingWithRightHand) {
-        // Just ending grab, capture velocity
-        grabDeltaVelocity = Controller.getSpatialControlVelocity(RIGHT_PALM);
-        stoppedGrabbingWithRightHand = true;
-    }
-
-    if (grabbingWithLeftHand && !wasGrabbingWithLeftHand) {
-        // Just starting grab, capture starting rotation
-        grabStartRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
-        grabStartPosition = getJoystickPosition(LEFT_PALM);
-        if (debug) printVector("start position", grabStartPosition, 3);
-    }
-
-    if (grabbingWithLeftHand) {
-        grabDelta = Vec3.subtract(getJoystickPosition(LEFT_PALM), grabStartPosition);
-        grabCurrentRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
-    }
-    if (!grabbingWithLeftHand && wasGrabbingWithLeftHand) {
-        // Just ending grab, capture velocity
-        grabDeltaVelocity = Controller.getSpatialControlVelocity(LEFT_PALM);
-        stoppedGrabbingWithLeftHand = true;
-    }
-
-    grabbing = grabbingWithRightHand || grabbingWithLeftHand;
-    stoppedGrabbing = stoppedGrabbingWithRightHand || stoppedGrabbingWithLeftHand;
-
-    if (grabbing) {
-    
-        var headOrientation = MyAvatar.headOrientation;
-        var front = Quat.getFront(headOrientation);
-        var right = Quat.getRight(headOrientation);
-        var up = Quat.getUp(headOrientation);
-
-        if (debug) {
-            printVector("grabDelta: ", grabDelta, 3);
-        }
-
-        var thrust = Vec3.multiply(grabDelta, Math.abs(Vec3.length(grabDelta)));
-
-        var THRUST_GRAB_SCALING = 100000.0;
-        
-        var thrustFront = Vec3.multiply(front, MyAvatar.scale * -thrust.z * THRUST_GRAB_SCALING * deltaTime);
-        MyAvatar.addThrust(thrustFront);
-        var thrustRight = Vec3.multiply(right, MyAvatar.scale * thrust.x * THRUST_GRAB_SCALING * deltaTime);
-        MyAvatar.addThrust(thrustRight);
-        var thrustUp = Vec3.multiply(up, MyAvatar.scale * thrust.y * THRUST_GRAB_SCALING * deltaTime);
-        MyAvatar.addThrust(thrustUp);
-        
-        // add some rotation...
-        var deltaRotation = getGrabRotation();
-        var PITCH_SCALING = 2.5;
-        var PITCH_DEAD_ZONE = 2.0;
-        var YAW_SCALING = 2.5;
-        var ROLL_SCALING = 2.0;     
-
-        var euler = Quat.safeEulerAngles(deltaRotation);
- 
-        //  Adjust body yaw by roll from controller
-        var orientation = Quat.multiply(Quat.angleAxis(((euler.y * YAW_SCALING) + 
-                                                        (euler.z * ROLL_SCALING)) * deltaTime, {x:0, y: 1, z:0}), MyAvatar.orientation);
-        MyAvatar.orientation = orientation;
-
-        //  Adjust head pitch from controller
-        var pitch = 0.0; 
-        if (Math.abs(euler.x) > PITCH_DEAD_ZONE) {
-            pitch = (euler.x < 0.0) ? (euler.x + PITCH_DEAD_ZONE) : (euler.x - PITCH_DEAD_ZONE);
-        }
-        MyAvatar.headPitch = MyAvatar.headPitch + (pitch * PITCH_SCALING * deltaTime);
-  
-        //  TODO: Add some camera roll proportional to the rate of turn (so it feels like an airplane or roller coaster)
-
-    }
-
-    wasGrabbingWithRightHand = grabbingWithRightHand;
-    wasGrabbingWithLeftHand = grabbingWithLeftHand;
-}
-
-// Update for joysticks and move button
-var THRUST_DEAD_ZONE = 0.1;
-var ROTATE_DEAD_ZONE = 0.1;
-function flyWithHydra(deltaTime) {
-    var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER);
-    
-    if (Math.abs(thrustJoystickPosition.x) > THRUST_DEAD_ZONE || Math.abs(thrustJoystickPosition.y) > THRUST_DEAD_ZONE) {
-        if (thrustMultiplier < MAX_THRUST_MULTIPLIER) {
-            thrustMultiplier *= 1 + (deltaTime * THRUST_INCREASE_RATE);
-        }
-        var headOrientation = MyAvatar.headOrientation;
-
-        var front = Quat.getFront(headOrientation);
-        var right = Quat.getRight(headOrientation);
-        var up = Quat.getUp(headOrientation);
-    
-        var thrustFront = Vec3.multiply(front, MyAvatar.scale * THRUST_MAG_HAND_JETS * 
-                                        thrustJoystickPosition.y * thrustMultiplier * deltaTime);
-        MyAvatar.addThrust(thrustFront);
-        var thrustRight = Vec3.multiply(right, MyAvatar.scale * THRUST_MAG_HAND_JETS * 
-                                        thrustJoystickPosition.x * thrustMultiplier * deltaTime);
-        MyAvatar.addThrust(thrustRight);
-    } else {
-        thrustMultiplier = INITIAL_THRUST_MULTIPLIER;
-    }
-
-    // View Controller
-    var viewJoystickPosition = Controller.getJoystickPosition(VIEW_CONTROLLER);
-    if (Math.abs(viewJoystickPosition.x) > ROTATE_DEAD_ZONE || Math.abs(viewJoystickPosition.y) > ROTATE_DEAD_ZONE) {
-
-        // change the body yaw based on our x controller
-        var orientation = MyAvatar.orientation;
-        var deltaOrientation = Quat.fromPitchYawRollDegrees(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0);
-        MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation);
-
-        // change the headPitch based on our x controller
-        var newPitch = MyAvatar.headPitch + (viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime);
-        MyAvatar.headPitch = newPitch;
-    }
-    handleGrabBehavior(deltaTime);
-    displayDebug();
-
-}
-    
-Script.update.connect(flyWithHydra);
-Controller.captureJoystick(THRUST_CONTROLLER);
-Controller.captureJoystick(VIEW_CONTROLLER);
-
-// Map keyPress and mouse move events to our callbacks
-function scriptEnding() {
-    // re-enabled the standard application for touch events
-    Controller.releaseJoystick(THRUST_CONTROLLER);
-    Controller.releaseJoystick(VIEW_CONTROLLER);
-}
-Script.scriptEnding.connect(scriptEnding);
-
-
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 3dc983cb34..29e60ca5ec 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -230,7 +230,8 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
             if (!jointsCaptured) {
                 //  Rotation of Palm
                 glm::quat rotation(data->rot_quat[3], data->rot_quat[0], data->rot_quat[1], data->rot_quat[2]);
-                handlePoseEvent(position, rotation, left);
+                handlePoseEvent(deltaTime, position, rotation, left);
+                
             } else {
                 _poseStateMap.clear();
             }
@@ -384,7 +385,7 @@ void SixenseManager::handleButtonEvent(unsigned int buttons, bool left) {
     }
 }
 
-void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, bool left) {
+void SixenseManager::handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left) {
 #ifdef HAVE_SIXENSE
     // From ABOVE the sixense coordinate frame looks like this:
     //
@@ -400,6 +401,7 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, boo
     //                      |
     //                      |
     //                      z
+    auto prevPose = _poseStateMap[left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND];
 
     // Transform the measured position into body frame.
     position = _avatarRotation * (position + _avatarPosition);
@@ -443,8 +445,20 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, boo
     // TODO: find a shortcut with fewer rotations.
     rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand;
 
+    glm::vec3 velocity(0.0f);
+    glm::quat angularVelocity;
 
-    _poseStateMap[left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND] = controller::Pose(position, rotation);
+    if (prevPose.isValid() && deltaTime > std::numeric_limits<float>::epsilon()) {
+        velocity = (position - prevPose.getTranslation()) / deltaTime;
+
+        auto deltaRot = rotation * glm::conjugate(prevPose.getRotation());
+        auto axis = glm::axis(deltaRot);
+        auto angle = glm::angle(deltaRot);
+        angularVelocity = glm::angleAxis(angle / deltaTime, axis);
+
+    }
+
+    _poseStateMap[left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND] = controller::Pose(position, rotation, velocity, angularVelocity);
 #endif // HAVE_SIXENSE
 }
 
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index 91cdb5f60e..368321e669 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -75,7 +75,7 @@ public slots:
 private:    
     void handleButtonEvent(unsigned int buttons, bool left);
     void handleAxisEvent(float x, float y, float trigger, bool left);
-    void handlePoseEvent(glm::vec3 position, glm::quat rotation, bool left);
+    void handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left);
 
     void updateCalibration(void* controllers);
     

From 51c8d48c8c34ab852af1db263443725e2e0d9a8e Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 16:12:31 -0700
Subject: [PATCH 114/301] Fix broken conditional caused by invalid route
 ordering

---
 .../src/controllers/UserInputMapper.cpp       | 30 +++++++++----------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index e73e4d0e68..2ed81aecba 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -655,7 +655,6 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
 
 void UserInputMapper::runMappings() {
     static auto deviceNames = getDeviceNames();
-
     for (auto endpointEntry : this->_endpointsByInput) {
         endpointEntry.second->reset();
     }
@@ -674,7 +673,6 @@ void UserInputMapper::runMappings() {
         }
         applyRoute(route);
     }
-
 }
 
 
@@ -1148,26 +1146,28 @@ void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
     // are processed in order so this ensures that the standard -> action processing 
     // takes place after all of the hardware -> standard or hardware -> action processing
     // because standard -> action is the first set of routes added.
-    for (auto route : mapping->routes) {
-        if (route->source->getInput().device == STANDARD_DEVICE) {
-            _standardRoutes.push_front(route);
-        } else {
-            _deviceRoutes.push_front(route);
-        }
-    }
+    Route::List standardRoutes = mapping->routes;
+    standardRoutes.remove_if([](const Route::Pointer& value) {
+        return (value->source->getInput().device == STANDARD_DEVICE);
+    });
+    _standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end());
+
+    Route::List deviceRoutes = mapping->routes;
+    deviceRoutes.remove_if([](const Route::Pointer& value) {
+        return (value->source->getInput().device != STANDARD_DEVICE);
+    });
+    _deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
 }
 
 void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
     Locker locker(_lock);
     const auto& deviceRoutes = mapping->routes;
     std::set<Route::Pointer> routeSet(deviceRoutes.begin(), deviceRoutes.end());
-
-    // FIXME this seems to result in empty route pointers... need to find a better way to remove them.
-    std::remove_if(_deviceRoutes.begin(), _deviceRoutes.end(), [&](Route::Pointer route)->bool {
-        return routeSet.count(route) != 0;
+    _deviceRoutes.remove_if([&](const Route::Pointer& value){
+        return routeSet.count(value) != 0;
     });
-    std::remove_if(_standardRoutes.begin(), _standardRoutes.end(), [&](Route::Pointer route)->bool {
-        return routeSet.count(route) != 0;
+    _standardRoutes.remove_if([&](const Route::Pointer& value) {
+        return routeSet.count(value) != 0;
     });
 }
 

From 0ad4634eac482dc3e68d57a78513573de3c9164f Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 22 Oct 2015 16:13:12 -0700
Subject: [PATCH 115/301] Check that the velocity information is passed
 correctly and fixed clap.js

---
 examples/clap.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/examples/clap.js b/examples/clap.js
index 4ec740e3f8..54ca937786 100644
--- a/examples/clap.js
+++ b/examples/clap.js
@@ -71,8 +71,12 @@ function maybePlaySound(deltaTime) {
     var palm2Position = MyAvatar.getRightPalmPosition();
     var distanceBetween = Vec3.length(Vec3.subtract(palm1Position, palm2Position));
 
-    var palm1Velocity = Controller.getSpatialControlVelocity(1);
-    var palm2Velocity = Controller.getSpatialControlVelocity(3);
+    var palmPose = Controller.getPoseValue(Controller.Standard.LeftHand);
+
+
+
+    var palm1Velocity = Controller.getPoseValue(Controller.Standard.LeftHand).velocity;
+    var palm2Velocity = Controller.getPoseValue(Controller.Standard.RightHand).velocity;
     var closingVelocity = Vec3.length(Vec3.subtract(palm1Velocity, palm2Velocity));
 
     const CLAP_SPEED = 0.7;

From 2b7ceffd643824b2abeb5dbd14819fd500a93bfc Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 22 Oct 2015 16:23:09 -0700
Subject: [PATCH 116/301] Get rid of
 globalObject().property("MyAvatar").property("animationStateHandlerResult").

---
 libraries/animation/src/AnimVariant.h        |  2 ++
 libraries/animation/src/Rig.cpp              |  6 +++++-
 libraries/script-engine/src/ScriptEngine.cpp | 21 +++++++++++++-------
 libraries/script-engine/src/ScriptEngine.h   |  2 +-
 4 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h
index 2d140bfa52..4190abfed8 100644
--- a/libraries/animation/src/AnimVariant.h
+++ b/libraries/animation/src/AnimVariant.h
@@ -205,6 +205,8 @@ protected:
     std::set<QString> _triggers;
 };
 
+typedef std::function<void(QScriptValue, QScriptValue)> AnimVariantResultHandler;
+Q_DECLARE_METATYPE(AnimVariantResultHandler);
 Q_DECLARE_METATYPE(AnimVariantMap)
 
 #endif // hifi_AnimVariant_h
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index b4113fd4a5..7ab39c2f34 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -628,11 +628,15 @@ void Rig::animationStateHandlerResult(QScriptValue handler, QScriptValue result)
 
 void Rig::updateAnimationStateHandlers() { // called on avatar update thread (which may be main thread)
     if (_stateHandlers.isValid()) {
+        auto handleResult = [this](QScriptValue handler, QScriptValue result) {
+            animationStateHandlerResult(handler, result);
+        };
         // invokeMethod makes a copy of the args, and copies of AnimVariantMap do copy the underlying map, so this will correctly capture
         // the state of _animVars and allow continued changes to _animVars in this thread without conflict.
         QMetaObject::invokeMethod(_stateHandlers.engine(), "callAnimationStateHandler",  Qt::QueuedConnection,
                                   Q_ARG(QScriptValue, _stateHandlers),
-                                  Q_ARG(AnimVariantMap, _animVars));
+                                  Q_ARG(AnimVariantMap, _animVars),
+                                  Q_ARG(AnimVariantResultHandler, handleResult));
     }
     QMutexLocker locker(&_stateMutex); // as we examine/copy most recently computed state, if any. (Typically an earlier invocation.)
     _animVars.copyVariantsFrom(_stateHandlersResults);
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 5808340855..acfa0c027b 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -260,12 +260,23 @@ void ScriptEngine::errorInLoadingScript(const QUrl& url) {
 
 // Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of
 // callAnimationStateHandler requires that the type be registered.
+// These two are meaningful, if we ever do want to use them...
 static QScriptValue animVarMapToScriptValue(QScriptEngine* engine, const AnimVariantMap& parameters) {
     return parameters.animVariantMapToScriptValue(engine);
 }
 static void animVarMapFromScriptValue(const QScriptValue& value, AnimVariantMap& parameters) {
     parameters.animVariantMapFromScriptValue(value);
 }
+// ... while these two are not. But none of the four are ever used.
+static QScriptValue resultHandlerToScriptValue(QScriptEngine* engine, const AnimVariantResultHandler& resultHandler) {
+    qCCritical(scriptengine) << "Attempt to marshall result handler to javascript";
+    assert(false);
+    return QScriptValue();
+}
+static void resultHandlerFromScriptValue(const QScriptValue& value, AnimVariantResultHandler& resultHandler) {
+    qCCritical(scriptengine) << "Attempt to marshall result handler from javascript";
+    assert(false);
+}
 
 void ScriptEngine::init() {
     if (_isInitialized) {
@@ -326,6 +337,7 @@ void ScriptEngine::init() {
     registerGlobalObject("Uuid", &_uuidLibrary);
     registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
     qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue);
+    qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue);
 
     // constants
     globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
@@ -729,7 +741,7 @@ void ScriptEngine::stop() {
 }
 
 // Other threads can invoke this through invokeMethod, which causes the callback to be asynchronously executed in this script's thread.
-void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters) {
+void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, AnimVariantResultHandler resultHandler) {
     if (QThread::currentThread() != thread()) {
 #ifdef THREAD_DEBUGGING
         qDebug() << "*** WARNING *** ScriptEngine::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]  name:" << name;
@@ -743,12 +755,7 @@ void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantM
     QScriptValueList callingArguments;
     callingArguments << javascriptParametgers;
     QScriptValue result = callback.call(QScriptValue(), callingArguments);
-    // We want to give the result back to the rig, but we don't have the rig or the avatar. But the global does.
-    // This is sort of like going through DependencyManager.get.
-    QScriptValue resultHandler = globalObject().property("MyAvatar").property("animationStateHandlerResult");
-    QScriptValueList resultArguments;
-    resultArguments << callback << result;
-    resultHandler.call(QScriptValue(), resultArguments); // Call it synchronously, on our own time and thread.
+    resultHandler(callback, result);
 }
 
 void ScriptEngine::timerFired() {
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index 7500e1d776..b6f736c846 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -144,7 +144,7 @@ public:
     ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; }
 
 public slots:
-    void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters);
+    void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, AnimVariantResultHandler resultHandler);
 
 signals:
     void scriptLoaded(const QString& scriptFilename);

From 92ddedd44b4d1487ea2e802351617136ab38cf0d Mon Sep 17 00:00:00 2001
From: howard-stearns <howard.stearns@gmail.com>
Date: Thu, 22 Oct 2015 16:44:15 -0700
Subject: [PATCH 117/301] Make msvc happy.

---
 libraries/animation/src/AnimVariant.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h
index 4190abfed8..7a80321f7b 100644
--- a/libraries/animation/src/AnimVariant.h
+++ b/libraries/animation/src/AnimVariant.h
@@ -12,6 +12,7 @@
 #define hifi_AnimVariant_h
 
 #include <cassert>
+#include <functional>
 #include <glm/glm.hpp>
 #include <glm/gtx/quaternion.hpp>
 #include <map>

From 84cfeaec13f79615e788815b14ef937dc76a10d5 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 22 Oct 2015 17:01:06 -0700
Subject: [PATCH 118/301] Linux QT wants .h-less headers.

---
 libraries/animation/src/AnimVariantMap.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
index 170662f092..59f10a96e0 100644
--- a/libraries/animation/src/AnimVariantMap.cpp
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -11,7 +11,7 @@
 
 #include <QScriptEngine>
 #include <QScriptValueIterator>
-#include <QThread.h>
+#include <QThread>
 #include <RegisteredMetaTypes.h>
 #include "AnimVariant.h"
 

From 3e4bada313c65e485a35d014ee11dad213b46ef2 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 22 Oct 2015 18:03:47 -0700
Subject: [PATCH 119/301] remove uneeded var

---
 examples/clap.js | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/examples/clap.js b/examples/clap.js
index 54ca937786..9b21075ae7 100644
--- a/examples/clap.js
+++ b/examples/clap.js
@@ -71,10 +71,6 @@ function maybePlaySound(deltaTime) {
     var palm2Position = MyAvatar.getRightPalmPosition();
     var distanceBetween = Vec3.length(Vec3.subtract(palm1Position, palm2Position));
 
-    var palmPose = Controller.getPoseValue(Controller.Standard.LeftHand);
-
-
-
     var palm1Velocity = Controller.getPoseValue(Controller.Standard.LeftHand).velocity;
     var palm2Velocity = Controller.getPoseValue(Controller.Standard.RightHand).velocity;
     var closingVelocity = Vec3.length(Vec3.subtract(palm1Velocity, palm2Velocity));

From eaaec516c27b5578f09c28d9093806c4796d1342 Mon Sep 17 00:00:00 2001
From: EdgarPironti <pacepiro@hotmail.it>
Date: Thu, 22 Oct 2015 18:41:57 -0700
Subject: [PATCH 120/301] fix controllerExample

---
 .../avatarcontrol/controllerExample.js        | 47 ++++---------------
 1 file changed, 9 insertions(+), 38 deletions(-)

diff --git a/examples/example/avatarcontrol/controllerExample.js b/examples/example/avatarcontrol/controllerExample.js
index 66a9e40c56..fe23ce0e8e 100644
--- a/examples/example/avatarcontrol/controllerExample.js
+++ b/examples/example/avatarcontrol/controllerExample.js
@@ -10,25 +10,19 @@
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
-
 // initialize our triggers
 var triggerPulled = new Array();
-var numberOfTriggers = Controller.getNumberOfTriggers();
-for (t = 0; t < numberOfTriggers; t++) {
+var NUMBER_OF_TRIGGERS = 2;	
+for (t = 0; t < NUMBER_OF_TRIGGERS; t++) {
     triggerPulled[t] = false;
 }
-
+var triggers = new Array();
+triggers[0] = Controller.Standard.LT;
+triggers[1] = Controller.Standard.RT;
 function checkController(deltaTime) {
-    var numberOfTriggers = Controller.getNumberOfTriggers();
-    var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
-    var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
     var triggerToggled = false;
-
-    // this is expected for hydras
-    if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
-        for (var t = 0; t < numberOfTriggers; t++) {
-            var triggerValue = Controller.getTriggerValue(t);
-
+	for (var t = 0; t < NUMBER_OF_TRIGGERS; t++) {
+            var triggerValue = Controller.getValue(triggers[t]]);
             if (triggerPulled[t]) {
                 // must release to at least 0.1
                 if (triggerValue < 0.1) {
@@ -41,17 +35,14 @@ function checkController(deltaTime) {
                     triggerToggled = true;
                 }
             }
-
             if (triggerToggled) {
                 print("a trigger was toggled");
             }
         }
-    }
+	
 }
-
 // register the call back so it fires before each data send
 Script.update.connect(checkController);
-
 function printKeyEvent(eventName, event) {
     print(eventName);
     print("    event.key=" + event.key);
@@ -64,7 +55,6 @@ function printKeyEvent(eventName, event) {
 }
 function keyPressEvent(event) {
     printKeyEvent("keyPressEvent", event);
-
     if (event.text == "A") {
         print("the A key was pressed");
     }
@@ -72,10 +62,8 @@ function keyPressEvent(event) {
         print("the <space> key was pressed");
     }
 }
-
 function keyReleaseEvent(event) {
     printKeyEvent("keyReleaseEvent", event);
-
     if (event.text == "A") {
         print("the A key was released");
     }
@@ -83,11 +71,9 @@ function keyReleaseEvent(event) {
         print("the <space> key was pressed");
     }
 }
-
 // Map keyPress and mouse move events to our callbacks
 Controller.keyPressEvent.connect(keyPressEvent);
 Controller.keyReleaseEvent.connect(keyReleaseEvent);
-
 // prevent the A key from going through to the application
 Controller.captureKeyEvents({ text: "A" });
 Controller.captureKeyEvents({ key: "A".charCodeAt(0) }); // same as above, just another example of how to capture the key
@@ -95,8 +81,6 @@ Controller.captureKeyEvents({ text: " " });
 Controller.captureKeyEvents({ text: "@", isMeta: true });
 Controller.captureKeyEvents({ text: "page up" });
 Controller.captureKeyEvents({ text: "page down" });
-
-
 function printMouseEvent(eventName, event) {
     print(eventName);
     print("    event.x,y=" + event.x + ", " + event.y);
@@ -109,22 +93,18 @@ function printMouseEvent(eventName, event) {
     print("    event.isMeta=" + event.isMeta);
     print("    event.isAlt=" + event.isAlt);
 }
-
 function mouseMoveEvent(event) {
     printMouseEvent("mouseMoveEvent", event);
 }
 function mousePressEvent(event) {
     printMouseEvent("mousePressEvent", event);
 }
-
 function mouseReleaseEvent(event) {
     printMouseEvent("mouseReleaseEvent", event);
 }
-
 Controller.mouseMoveEvent.connect(mouseMoveEvent);
 Controller.mousePressEvent.connect(mousePressEvent);
 Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
-
 function printTouchEvent(eventName, event) {
     print(eventName);
     
@@ -143,7 +123,6 @@ function printTouchEvent(eventName, event) {
     print("    event.radius=" + event.radius);
     print("    event.isPinching=" + event.isPinching);
     print("    event.isPinchOpening=" + event.isPinchOpening);
-
     print("    event.angle=" + event.angle);
     for (var i = 0; i < event.points.length; i++) {
         print("    event.angles[" + i + "]:" + event.angles[i]);
@@ -151,15 +130,12 @@ function printTouchEvent(eventName, event) {
     print("    event.isRotating=" + event.isRotating);
     print("    event.rotating=" + event.rotating);
 }
-
 function touchBeginEvent(event) {
     printTouchEvent("touchBeginEvent", event);
 }
-
 function touchUpdateEvent(event) {
     printTouchEvent("touchUpdateEvent", event);
 }
-
 function touchEndEvent(event) {
     printTouchEvent("touchEndEvent", event);
 }
@@ -167,8 +143,6 @@ function touchEndEvent(event) {
 Controller.touchBeginEvent.connect(touchBeginEvent);
 Controller.touchUpdateEvent.connect(touchUpdateEvent);
 Controller.touchEndEvent.connect(touchEndEvent);
-
-
 function wheelEvent(event) {
     print("wheelEvent");
     print("    event.x,y=" + event.x + ", " + event.y);
@@ -182,9 +156,7 @@ function wheelEvent(event) {
     print("    event.isMeta=" + event.isMeta);
     print("    event.isAlt=" + event.isAlt);
 }
-
 Controller.wheelEvent.connect(wheelEvent);
-
 function scriptEnding() {
     // re-enabled the standard application for touch events
     Controller.releaseKeyEvents({ text: "A" });
@@ -194,5 +166,4 @@ function scriptEnding() {
     Controller.releaseKeyEvents({ text: "page up" });
     Controller.releaseKeyEvents({ text: "page down" });
 }
-
-Script.scriptEnding.connect(scriptEnding);
+Script.scriptEnding.connect(scriptEnding);
\ No newline at end of file

From ae2f7f6ff687ab86f70a8fc8a77cefb29c9e9f04 Mon Sep 17 00:00:00 2001
From: AlessandroSigna <alesigna92@gmail.com>
Date: Thu, 22 Oct 2015 18:50:23 -0700
Subject: [PATCH 121/301] Fix paddleBall.js

---
 examples/controllers/hydra/paddleBall.js | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/examples/controllers/hydra/paddleBall.js b/examples/controllers/hydra/paddleBall.js
index 13c6e2eb62..91b2520e1d 100644
--- a/examples/controllers/hydra/paddleBall.js
+++ b/examples/controllers/hydra/paddleBall.js
@@ -32,14 +32,14 @@ var SPRING_FORCE = 15.0;
 var lastSoundTime = 0; 
 var gameOn = false; 
 var leftHanded = true; 
-var controllerID;
+var hand;
 
 
 function setControllerID() {
     if (leftHanded)  {
-        controllerID = 1;
+        hand = Controller.Standard.LeftHand;
     } else {
-        controllerID = 3; 
+        hand = Controller.Standard.RightHand; 
     }
 }
 
@@ -63,7 +63,7 @@ var ball, paddle, paddleModel, line;
 function createEntities() {
     ball = Entities.addEntity(
                 { type: "Sphere",
-                position: Controller.getSpatialControlPosition(controllerID),   
+                position: Controller.getPoseValue(hand).translation,
                 dimensions: { x: BALL_SIZE, y: BALL_SIZE, z: BALL_SIZE }, 
                   color: BALL_COLOR,
                   gravity: {  x: 0, y: GRAVITY, z: 0 },
@@ -73,27 +73,27 @@ function createEntities() {
 
     paddle = Entities.addEntity(
                 { type: "Box",
-                position: Controller.getSpatialControlPosition(controllerID),   
+                position: Controller.getPoseValue(hand).translation,  
                 dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 0.80 }, 
                   color: PADDLE_COLOR,
                   gravity: {  x: 0, y: 0, z: 0 },
                 ignoreCollisions: false,
                 damping: 0.10,
                 visible: false,
-                rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)),
+                rotation: Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation,
                 collisionsWillMove: false });
 
     modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx";
     paddleModel = Entities.addEntity(
                 { type: "Model",
-                position: Vec3.sum(Controller.getSpatialControlPosition(controllerID), PADDLE_BOX_OFFSET),   
+                position: Vec3.sum(Controller.getPoseValue(hand).translation, PADDLE_BOX_OFFSET),   
                 dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 }, 
                   color: PADDLE_COLOR,
                   gravity: {  x: 0, y: 0, z: 0 },
                 ignoreCollisions: true,
                 modelURL: modelURL,
                 damping: 0.10,
-                rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)),
+                rotation: Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation,
                 collisionsWillMove: false });
 
     line = Overlays.addOverlay("line3d", {
@@ -118,7 +118,7 @@ function deleteEntities() {
 }
 
 function update(deltaTime) {
-    var palmPosition = Controller.getSpatialControlPosition(controllerID);
+    var palmPosition = Controller.getPoseValue(hand).translation;
     var controllerActive = (Vec3.length(palmPosition) > 0);
 
     if (!gameOn && controllerActive) {
@@ -133,7 +133,7 @@ function update(deltaTime) {
     }
 
         var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
-        var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), paddleOrientation);
+        var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation), paddleOrientation);
         var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(), 
                                     Vec3.multiplyQbyV(paddleWorldOrientation, leftHanded ? HOLD_POSITION_LEFT_OFFSET : HOLD_POSITION_RIGHT_OFFSET ));
 
@@ -146,10 +146,10 @@ function update(deltaTime) {
         Entities.editEntity(ball, { velocity: ballVelocity });
         Overlays.editOverlay(line, { start: props.position, end: holdPosition });
         Entities.editEntity(paddle, { position: holdPosition, 
-                                      velocity: Controller.getSpatialControlVelocity(controllerID),
+                                      velocity: Controller.getPoseValue(hand).velocity,
                                       rotation: paddleWorldOrientation });
         Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)), 
-                                      velocity: Controller.getSpatialControlVelocity(controllerID),
+                                      velocity: Controller.getPoseValue(hand).velocity,
                                       rotation: paddleWorldOrientation });
 
 }

From 91804fbc04a2d586e2f80dad4d80abf116696dfa Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 22:02:09 -0700
Subject: [PATCH 122/301] Fix ordering of standard vs device routes

---
 .../src/controllers/UserInputMapper.cpp       | 43 +++++++++++++------
 1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 2ed81aecba..8cd6618bfc 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -18,6 +18,7 @@
 #include <QtCore/QJsonArray>
 
 #include <PathUtils.h>
+#include <NumericalConstants.h>
 
 #include "StandardController.h"
 #include "Logging.h"
@@ -653,7 +654,16 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
     return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
 }
 
+static auto lastDebugTime = usecTimestampNow();
+static auto debugRoutes = false;
+static const auto DEBUG_INTERVAL = USECS_PER_SECOND;
+
 void UserInputMapper::runMappings() {
+    auto now = usecTimestampNow();
+    if (now - lastDebugTime > DEBUG_INTERVAL) {
+        lastDebugTime = now;
+        debugRoutes = true;
+    }
     static auto deviceNames = getDeviceNames();
     for (auto endpointEntry : this->_endpointsByInput) {
         endpointEntry.second->reset();
@@ -673,17 +683,17 @@ void UserInputMapper::runMappings() {
         }
         applyRoute(route);
     }
+    debugRoutes = false;
 }
 
-
 void UserInputMapper::applyRoute(const Route::Pointer& route) {
-    if (route->debug) {
+    if (debugRoutes && route->debug) {
         qCDebug(controllers) << "Applying route " << route->json;
     }
 
     if (route->conditional) {
         if (!route->conditional->satisfied()) {
-            if (route->debug) {
+            if (debugRoutes && route->debug) {
                 qCDebug(controllers) << "Conditional failed";
             }
             return;
@@ -698,7 +708,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
     // I press the button.  The exception is if I'm wiring a control back to itself
     // in order to adjust my interface, like inverting the Y axis on an analog stick
     if (!source->readable()) {
-        if (route->debug) {
+        if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Source unreadable";
         }
         return;
@@ -708,14 +718,14 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
     // THis could happen if the route destination failed to create
     // FIXME: Maybe do not create the route if the destination failed and avoid this case ?
     if (!destination) {
-        if (route->debug) {
+        if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Bad Destination";
         }
         return;
     }
 
     if (!destination->writeable()) {
-        if (route->debug) {
+        if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Destination unwritable";
         }
         return;
@@ -723,17 +733,24 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
 
     // Fetch the value, may have been overriden by previous loopback routes
     if (source->isPose()) {
-        if (route->debug) {
-            qCDebug(controllers) << "Applying pose";
-        }
         Pose value = getPose(source);
+        static const Pose IDENTITY_POSE { vec3(), quat() };
+        if (debugRoutes && route->debug) {
+            if (!value.valid) {
+                qCDebug(controllers) << "Applying invalid pose";
+            } else if (value == IDENTITY_POSE) {
+                qCDebug(controllers) << "Applying identity pose";
+            } else {
+                qCDebug(controllers) << "Applying valid pose";
+            }
+        }
         // no filters yet for pose
         destination->apply(value, Pose(), source);
     } else {
         // Fetch the value, may have been overriden by previous loopback routes
         float value = getValue(source);
 
-        if (route->debug) {
+        if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Value was " << value;
         }
         // Apply each of the filters.
@@ -741,7 +758,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
             value = filter->apply(value);
         }
 
-        if (route->debug) {
+        if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Filtered value was " << value;
         }
 
@@ -1148,13 +1165,13 @@ void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
     // because standard -> action is the first set of routes added.
     Route::List standardRoutes = mapping->routes;
     standardRoutes.remove_if([](const Route::Pointer& value) {
-        return (value->source->getInput().device == STANDARD_DEVICE);
+        return (value->source->getInput().device != STANDARD_DEVICE);
     });
     _standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end());
 
     Route::List deviceRoutes = mapping->routes;
     deviceRoutes.remove_if([](const Route::Pointer& value) {
-        return (value->source->getInput().device != STANDARD_DEVICE);
+        return (value->source->getInput().device == STANDARD_DEVICE);
     });
     _deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
 }

From 63df9fb959b78bf1a34d5b7bb5f042acfaa5b2de Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 22 Oct 2015 22:37:18 -0700
Subject: [PATCH 123/301] Fixing raw sound playback and air guitar

---
 examples/controllers/hydra/airGuitar.js | 37 +++++++++++++--------
 libraries/audio/src/Sound.cpp           | 43 ++++++++++---------------
 2 files changed, 41 insertions(+), 39 deletions(-)

diff --git a/examples/controllers/hydra/airGuitar.js b/examples/controllers/hydra/airGuitar.js
index b286cc6084..f8606808c1 100644
--- a/examples/controllers/hydra/airGuitar.js
+++ b/examples/controllers/hydra/airGuitar.js
@@ -90,7 +90,7 @@ var audioInjector = null;
 var selectorPressed = false;
 var position;
 
-MyAvatar.attach(guitarModel, "Hips", {x: -0.2, y: 0.0, z: 0.1}, Quat.fromPitchYawRollDegrees(90, 00, 90), 1.0);
+MyAvatar.attach(guitarModel, "Hips", {x: leftHanded ? -0.2 : 0.2, y: 0.0, z: 0.1}, Quat.fromPitchYawRollDegrees(90, 00, leftHanded ? 75 : -75), 1.0);
 
 function checkHands(deltaTime) {
     var strumVelocity = Controller.getPoseValue(strumHand).velocity;
@@ -114,27 +114,32 @@ function checkHands(deltaTime) {
 
     //  Change guitars if button FWD (5) pressed
     if (Controller.getValue(changeGuitar)) {
-        print("changeGuitar:" + changeGuitar);
         if (!selectorPressed) {
+            print("changeGuitar:" + changeGuitar);
             guitarSelector += NUM_CHORDS;
             if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) {
                 guitarSelector = 0;
             } 
+            print("new guitarBase: " + guitarSelector);
+            stopAudio(true);
             selectorPressed = true;
         }
     } else {
         selectorPressed = false;
     }
-    //print("selectorPressed:" + selectorPressed);
 
     if (Controller.getValue(chord1)) {
         whichChord = 1;
+        stopAudio(true);
     } else if (Controller.getValue(chord2)) {
         whichChord = 2;
+        stopAudio(true);
     } else if (Controller.getValue(chord3)) {
         whichChord = 3;
+        stopAudio(true);
     } else if (Controller.getValue(chord4)) {
         whichChord = 4;
+        stopAudio(true);
     }
 
     var STRUM_HEIGHT_ABOVE_PELVIS = 0.10;
@@ -154,26 +159,27 @@ function checkHands(deltaTime) {
     lastPosition = strumHandPosition;
 }
 
-function playChord(position, volume) {
+function stopAudio(killInjector) {
     if (audioInjector && audioInjector.isPlaying) {
         print("stopped sound");
         audioInjector.stop();
     }
-  
+    if (killInjector) {
+        audioInjector = null;
+    }
+}
+
+
+function playChord(position, volume) {
+    stopAudio();
     print("Played sound: " + whichChord + " at volume " + volume);
     if (!audioInjector) {
-
-        // FIXME - we apparenlty broke RAW file playback, so we need WAV files for all these chords. In the mean
-        // time, we will just play the heyMan wave file for all chords
-        var chord = heyManWave; // chords[guitarSelector + whichChord];
-
+        var index = guitarSelector + whichChord;
+        var chord = chords[guitarSelector + whichChord];
         audioInjector = Audio.playSound(chord, { position: position, volume: volume });
-        print("audioInjector: " + JSON.stringify(audioInjector));
     } else {
-        print("audioInjector: " + JSON.stringify(audioInjector));
         audioInjector.restart();
     }
-    
 }
 
 function keyPressEvent(event) {
@@ -181,15 +187,19 @@ function keyPressEvent(event) {
     keyVolume = 0.4;
     if (event.text == "1") {
         whichChord = 1;
+        stopAudio(true);
         playChord(MyAvatar.position, keyVolume);
     } else if (event.text == "2") {
         whichChord = 2;
+        stopAudio(true);
         playChord(MyAvatar.position, keyVolume);
     } else if (event.text == "3") {
         whichChord = 3;
+        stopAudio(true);
         playChord(MyAvatar.position, keyVolume);
     } else if (event.text == "4") {
         whichChord = 4;
+        stopAudio(true);
         playChord(MyAvatar.position, keyVolume);
     }
 }
@@ -197,6 +207,7 @@ function keyPressEvent(event) {
 function scriptEnding() {
     MyAvatar.detachOne(guitarModel);
 }
+
 // Connect a call back that happens every frame
 Script.update.connect(checkHands);
 Script.scriptEnding.connect(scriptEnding);
diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp
index 2457bda74a..2ce2c47fef 100644
--- a/libraries/audio/src/Sound.cpp
+++ b/libraries/audio/src/Sound.cpp
@@ -59,39 +59,30 @@ Sound::Sound(const QUrl& url, bool isStereo) :
 void Sound::downloadFinished(const QByteArray& data) {
     // replace our byte array with the downloaded data
     QByteArray rawAudioByteArray = QByteArray(data);
-    QString fileName = getURL().fileName();
-
-    const QString WAV_EXTENSION = ".wav";
+    QString fileName = getURL().fileName().toLower();
 
+    static const QString WAV_EXTENSION = ".wav";
+    static const QString RAW_EXTENSION = ".raw";
     if (fileName.endsWith(WAV_EXTENSION)) {
 
-        QString headerContentType = "audio/x-wav";
-        //QByteArray headerContentType = reply->rawHeader("Content-Type");
+        QByteArray outputAudioByteArray;
 
-        // WAV audio file encountered
-        if (headerContentType == "audio/x-wav"
-            || headerContentType == "audio/wav"
-            || headerContentType == "audio/wave"
-            || fileName.endsWith(WAV_EXTENSION)) {
-
-            QByteArray outputAudioByteArray;
-
-            interpretAsWav(rawAudioByteArray, outputAudioByteArray);
-            downSample(outputAudioByteArray);
-        } else {
-            // check if this was a stereo raw file
-            // since it's raw the only way for us to know that is if the file was called .stereo.raw
-            if (fileName.toLower().endsWith("stereo.raw")) {
-                _isStereo = true;
-                qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << getURL() << "as stereo audio file.";
-            }
-
-            // Process as RAW file
-            downSample(rawAudioByteArray);
+        interpretAsWav(rawAudioByteArray, outputAudioByteArray);
+        downSample(outputAudioByteArray);
+        trimFrames();
+    } else if (fileName.endsWith(RAW_EXTENSION)) {
+        // check if this was a stereo raw file
+        // since it's raw the only way for us to know that is if the file was called .stereo.raw
+        if (fileName.toLower().endsWith("stereo.raw")) {
+            _isStereo = true;
+            qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << getURL() << "as stereo audio file.";
         }
+
+        // Process as RAW file
+        downSample(rawAudioByteArray);
         trimFrames();
     } else {
-        qCDebug(audio) << "Network reply without 'Content-Type'.";
+        qCDebug(audio) << "Unknown sound file type";
     }
 
     _isReady = true;

From 71dfff7c3579c9395c03c1d356cd6535c011660b Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 12:00:40 -0700
Subject: [PATCH 124/301] first cut at adding MyAvatar.xxxHandPose

---
 interface/src/avatar/MyAvatar.cpp | 28 ++++++++++++++++++++++++++++
 interface/src/avatar/MyAvatar.h   | 20 ++++++++++++++++----
 libraries/avatars/src/HandData.h  |  1 +
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index d822d37055..6e08ca24cf 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -596,6 +596,34 @@ glm::vec3 MyAvatar::getRightHandTipPosition() const {
     return palmData ? palmData->getTipPosition() : glm::vec3(0.0f);
 }
 
+controller::Pose MyAvatar::getLeftHandPose() const {
+    const int LEFT_HAND = 0;
+    auto palmData = getActivePalm(LEFT_HAND);
+    return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
+        palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+}
+
+controller::Pose MyAvatar::getRightHandPose() const {
+    const int RIGHT_HAND = 1;
+    auto palmData = getActivePalm(RIGHT_HAND);
+    return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
+        palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+}
+
+controller::Pose MyAvatar::getLeftHandTipPose() const {
+    const int LEFT_HAND = 0;
+    auto palmData = getActivePalm(LEFT_HAND);
+    return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
+        palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+}
+
+controller::Pose MyAvatar::getRightHandTipPose() const {
+    const int RIGHT_HAND = 1;
+    auto palmData = getActivePalm(RIGHT_HAND);
+    return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
+        palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+}
+
 // virtual
 void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
     // don't render if we've been asked to disable local rendering
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index c80a855149..0a3d7dedf4 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -16,6 +16,8 @@
 #include <DynamicCharacterController.h>
 #include <Rig.h>
 
+#include <controllers/Pose.h>
+
 #include "Avatar.h"
 #include "AtRestDetector.h"
 
@@ -64,10 +66,15 @@ class MyAvatar : public Avatar {
     //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
 
 
-    Q_PROPERTY(glm::vec3 leftHandPosition  READ getLeftHandPosition)
-    Q_PROPERTY(glm::vec3 rightHandPosition  READ getRightHandPosition)
-    Q_PROPERTY(glm::vec3 leftHandTipPosition  READ getLeftHandTipPosition)
-    Q_PROPERTY(glm::vec3 rightHandTipPosition  READ getRightHandTipPosition)
+    Q_PROPERTY(glm::vec3 leftHandPosition READ getLeftHandPosition)
+    Q_PROPERTY(glm::vec3 rightHandPosition READ getRightHandPosition)
+    Q_PROPERTY(glm::vec3 leftHandTipPosition READ getLeftHandTipPosition)
+    Q_PROPERTY(glm::vec3 rightHandTipPosition READ getRightHandTipPosition)
+
+    Q_PROPERTY(controller::Pose leftHandPose READ getLeftHandPose)
+    Q_PROPERTY(controller::Pose rightHandPose READ getRightHandPose)
+    Q_PROPERTY(controller::Pose leftHandTipPose READ getLeftHandTipPose)
+    Q_PROPERTY(controller::Pose rightHandTipPose READ getRightHandTipPose)
 
 public:
     MyAvatar(RigPointer rig);
@@ -160,6 +167,11 @@ public:
     Q_INVOKABLE glm::vec3 getLeftHandTipPosition() const;
     Q_INVOKABLE glm::vec3 getRightHandTipPosition() const;
 
+    Q_INVOKABLE controller::Pose getLeftHandPose() const;
+    Q_INVOKABLE controller::Pose getRightHandPose() const;
+    Q_INVOKABLE controller::Pose getLeftHandTipPose() const;
+    Q_INVOKABLE controller::Pose getRightHandTipPose() const;
+
     AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
     void updateLookAtTargetAvatar();
     void clearLookAtTargetAvatar();
diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h
index 7514e38055..7cc9faad3d 100644
--- a/libraries/avatars/src/HandData.h
+++ b/libraries/avatars/src/HandData.h
@@ -103,6 +103,7 @@ public:
     const glm::vec3& getRawVelocity()  const { return _rawVelocity; }
     void setRawAngularVelocity(const glm::vec3& angularVelocity) { _rawAngularVelocity = angularVelocity; }
     const glm::vec3& getRawAngularVelocity() const { return _rawAngularVelocity; }
+    glm::quat getRawAngularVelocityAsQuat() const { return glm::quat(); } // FIXME
     void addToPosition(const glm::vec3& delta);
 
     void addToPenetration(const glm::vec3& penetration) { _totalPenetration += penetration; }

From 4a58eeb810bdee721e44842477b15c5eb832e30c Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 12:14:33 -0700
Subject: [PATCH 125/301] expose deltaRotation as part of MyAvatar.xxxHandPose

---
 interface/src/Application.cpp     | 2 ++
 interface/src/avatar/MyAvatar.cpp | 8 ++++----
 libraries/avatars/src/HandData.h  | 6 +++++-
 3 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 0a634425bc..dd04b89b66 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -4851,8 +4851,10 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de
         angularVelocity = glm::normalize(glm::axis(deltaRotation));
         angularVelocity *= (rotationAngle / deltaTime);
         palm->setRawAngularVelocity(angularVelocity);
+        palm->setRawDeltaRotation(deltaRotation); // FIXME - do we really want both RawAngularVelocity and RawDeltaRotation
     } else {
         palm->setRawAngularVelocity(glm::vec3(0.0f));
+        palm->setRawDeltaRotation(glm::quat());
     }
 
     if (controller::InputDevice::getLowVelocityFilter()) {
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 6e08ca24cf..09f702eb83 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -600,28 +600,28 @@ controller::Pose MyAvatar::getLeftHandPose() const {
     const int LEFT_HAND = 0;
     auto palmData = getActivePalm(LEFT_HAND);
     return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
-        palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+        palmData->getVelocity(), palmData->getRawDeltaRotation()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getRightHandPose() const {
     const int RIGHT_HAND = 1;
     auto palmData = getActivePalm(RIGHT_HAND);
     return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
-        palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+        palmData->getVelocity(), palmData->getRawDeltaRotation()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getLeftHandTipPose() const {
     const int LEFT_HAND = 0;
     auto palmData = getActivePalm(LEFT_HAND);
     return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
-        palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+        palmData->getTipVelocity(), palmData->getRawDeltaRotation()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getRightHandTipPose() const {
     const int RIGHT_HAND = 1;
     auto palmData = getActivePalm(RIGHT_HAND);
     return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
-        palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+        palmData->getTipVelocity(), palmData->getRawDeltaRotation()) : controller::Pose();
 }
 
 // virtual
diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h
index 7cc9faad3d..a194620f3a 100644
--- a/libraries/avatars/src/HandData.h
+++ b/libraries/avatars/src/HandData.h
@@ -101,9 +101,12 @@ public:
     void setRawPosition(const glm::vec3& pos)  { _rawPosition = pos; }
     void setRawVelocity(const glm::vec3& velocity) { _rawVelocity = velocity; }
     const glm::vec3& getRawVelocity()  const { return _rawVelocity; }
+
     void setRawAngularVelocity(const glm::vec3& angularVelocity) { _rawAngularVelocity = angularVelocity; }
     const glm::vec3& getRawAngularVelocity() const { return _rawAngularVelocity; }
-    glm::quat getRawAngularVelocityAsQuat() const { return glm::quat(); } // FIXME
+    void setRawDeltaRotation(glm::quat rawDeltaRotation) { _rawDeltaRotation = rawDeltaRotation; } // FIXME, is this really what we want?
+    glm::quat getRawDeltaRotation() const { return _rawDeltaRotation; }
+
     void addToPosition(const glm::vec3& delta);
 
     void addToPenetration(const glm::vec3& penetration) { _totalPenetration += penetration; }
@@ -156,6 +159,7 @@ private:
     glm::vec3 _rawPosition;
     glm::vec3 _rawVelocity;
     glm::vec3 _rawAngularVelocity;
+    glm::quat _rawDeltaRotation;
     glm::quat _lastRotation;
     
     glm::vec3 _tipPosition;

From f90844449d33b0c86bb355b2dbd8dffc22290665 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 13:16:05 -0700
Subject: [PATCH 126/301] fix angular velocity

---
 interface/src/Application.cpp     | 2 --
 interface/src/avatar/MyAvatar.cpp | 8 ++++----
 libraries/avatars/src/HandData.h  | 3 +--
 3 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index dd04b89b66..0a634425bc 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -4851,10 +4851,8 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de
         angularVelocity = glm::normalize(glm::axis(deltaRotation));
         angularVelocity *= (rotationAngle / deltaTime);
         palm->setRawAngularVelocity(angularVelocity);
-        palm->setRawDeltaRotation(deltaRotation); // FIXME - do we really want both RawAngularVelocity and RawDeltaRotation
     } else {
         palm->setRawAngularVelocity(glm::vec3(0.0f));
-        palm->setRawDeltaRotation(glm::quat());
     }
 
     if (controller::InputDevice::getLowVelocityFilter()) {
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 09f702eb83..6e08ca24cf 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -600,28 +600,28 @@ controller::Pose MyAvatar::getLeftHandPose() const {
     const int LEFT_HAND = 0;
     auto palmData = getActivePalm(LEFT_HAND);
     return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
-        palmData->getVelocity(), palmData->getRawDeltaRotation()) : controller::Pose();
+        palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getRightHandPose() const {
     const int RIGHT_HAND = 1;
     auto palmData = getActivePalm(RIGHT_HAND);
     return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
-        palmData->getVelocity(), palmData->getRawDeltaRotation()) : controller::Pose();
+        palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getLeftHandTipPose() const {
     const int LEFT_HAND = 0;
     auto palmData = getActivePalm(LEFT_HAND);
     return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
-        palmData->getTipVelocity(), palmData->getRawDeltaRotation()) : controller::Pose();
+        palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getRightHandTipPose() const {
     const int RIGHT_HAND = 1;
     auto palmData = getActivePalm(RIGHT_HAND);
     return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
-        palmData->getTipVelocity(), palmData->getRawDeltaRotation()) : controller::Pose();
+        palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 // virtual
diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h
index a194620f3a..855da63870 100644
--- a/libraries/avatars/src/HandData.h
+++ b/libraries/avatars/src/HandData.h
@@ -104,8 +104,7 @@ public:
 
     void setRawAngularVelocity(const glm::vec3& angularVelocity) { _rawAngularVelocity = angularVelocity; }
     const glm::vec3& getRawAngularVelocity() const { return _rawAngularVelocity; }
-    void setRawDeltaRotation(glm::quat rawDeltaRotation) { _rawDeltaRotation = rawDeltaRotation; } // FIXME, is this really what we want?
-    glm::quat getRawDeltaRotation() const { return _rawDeltaRotation; }
+    glm::quat getRawAngularVelocityAsQuat() const { return glm::quat(_rawAngularVelocity); }
 
     void addToPosition(const glm::vec3& delta);
 

From e8be92cab837ec32764134663261440af0d73d7a Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 23 Oct 2015 09:18:44 -0700
Subject: [PATCH 127/301] Adding input action event

---
 interface/src/Application.cpp                  |  1 -
 .../scripting/ControllerScriptingInterface.h   |  2 --
 .../src/controllers/ScriptingInterface.cpp     |  3 +++
 .../src/controllers/ScriptingInterface.h       |  3 +++
 .../src/controllers/UserInputMapper.cpp        | 18 ++++++++++++++++++
 .../src/controllers/UserInputMapper.h          |  2 ++
 6 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 0a634425bc..92680ed3e0 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -627,7 +627,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
 
     // Setup the userInputMapper with the actions
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    connect(userInputMapper.data(), &UserInputMapper::actionEvent, _controllerScriptingInterface, &ControllerScriptingInterface::actionEvent);
     connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
         if (state && action == toInt(controller::Action::TOGGLE_MUTE)) {
             DependencyManager::get<AudioClient>()->toggleMute();
diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h
index 8be530c6ce..3133f93804 100644
--- a/interface/src/scripting/ControllerScriptingInterface.h
+++ b/interface/src/scripting/ControllerScriptingInterface.h
@@ -120,8 +120,6 @@ signals:
 
     void wheelEvent(const WheelEvent& event);
 
-    void actionEvent(int action, float state);
-
 private:
     QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript
 
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 40c65549a8..bb09705684 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -44,6 +44,9 @@ static QVariantMap createDeviceMap(const controller::DeviceProxy::Pointer device
 controller::ScriptingInterface::ScriptingInterface() {
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
 
+    connect(userInputMapper.data(), &UserInputMapper::actionEvent, this, &controller::ScriptingInterface::actionEvent);
+    connect(userInputMapper.data(), &UserInputMapper::inputEvent, this, &controller::ScriptingInterface::inputEvent);
+
     // FIXME make this thread safe
     connect(userInputMapper.data(), &UserInputMapper::hardwareChanged, [=] {
         updateMaps();
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index 85b1c3c6d9..db724044fa 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -129,6 +129,9 @@ namespace controller {
         virtual void captureActionEvents() { _actionsCaptured = true; }
         virtual void releaseActionEvents() { _actionsCaptured = false; }
 
+    signals:
+        void actionEvent(int action, float state);
+        void inputEvent(int action, float state);
 
     private:
         // Update the exposed variant maps reporting active hardware
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 8cd6618bfc..07f1f975a2 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -516,6 +516,24 @@ void UserInputMapper::update(float deltaTime) {
         }
         // TODO: emit signal for pose changes
     }
+
+    auto standardInputs = getStandardInputs();
+    if (_lastStandardStates.size() != standardInputs.size()) {
+        _lastStandardStates.resize(standardInputs.size());
+        for (auto& lastValue : _lastStandardStates) {
+            lastValue = 0;
+        }
+    }
+
+    for (int i = 0; i < standardInputs.size(); ++i) {
+        const auto& input = standardInputs[i].first;
+        float value = getValue(input);
+        float& oldValue = _lastStandardStates[i];
+        if (value != oldValue) {
+            oldValue = value;
+            emit inputEvent(input.id, value);
+        }
+    }
 }
 
 Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const {
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 4bfedfcf1a..0989fdb311 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -117,6 +117,7 @@ namespace controller {
 
     signals:
         void actionEvent(int action, float state);
+        void inputEvent(int input, float state);
         void hardwareChanged();
 
     protected:
@@ -130,6 +131,7 @@ namespace controller {
         std::vector<float> _actionScales = std::vector<float>(toInt(Action::NUM_ACTIONS), 1.0f);
         std::vector<float> _lastActionStates = std::vector<float>(toInt(Action::NUM_ACTIONS), 0.0f);
         std::vector<Pose> _poseStates = std::vector<Pose>(toInt(Action::NUM_ACTIONS));
+        std::vector<float> _lastStandardStates = std::vector<float>();
 
         glm::mat4 _sensorToWorldMat;
 

From be148686a76d5c6b8115dc79a61effb041f011b2 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 23 Oct 2015 09:34:01 -0700
Subject: [PATCH 128/301] Fixing omnitool

---
 examples/libraries/omniTool.js | 54 ++++++++++++++++++----------------
 examples/libraries/utils.js    |  8 +----
 2 files changed, 29 insertions(+), 33 deletions(-)

diff --git a/examples/libraries/omniTool.js b/examples/libraries/omniTool.js
index 26c299cdfb..a7fee1a4cf 100644
--- a/examples/libraries/omniTool.js
+++ b/examples/libraries/omniTool.js
@@ -15,16 +15,18 @@ Script.include("omniTool/models/invisibleWand.js");
 
 OmniToolModules = {};
 OmniToolModuleType = null;
+LOG_DEBUG = 1;
 
-OmniTool = function(side) {
+OmniTool = function(left) {
     this.OMNI_KEY = "OmniTool";
     this.MAX_FRAMERATE = 60;
     this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
-    this.SIDE = side;
-    this.PALM = 2 * side;
-    this.ACTION = findAction(side ? "ACTION2" : "ACTION1");
-    this.ALT_ACTION = findAction(side ? "ACTION1" : "ACTION2");
-
+    this.left = left;
+    var actions = Controller.Actions;
+    var standard = Controller.Standard;
+    this.palmControl = left ? actions.LeftHand : actions.RightHand;
+    this.action = left ? standard.LeftPrimaryThumb : standard.RightPrimaryThumb;
+    logDebug("Init OmniTool " + (left ? "left" : "right"));
     this.highlighter = new Highlighter();
     this.ignoreEntities = {};
     this.nearestOmniEntity = {
@@ -47,21 +49,21 @@ OmniTool = function(side) {
     this.showWand(false);
 
     // Connect to desired events
-    var _this = this;
-    Controller.actionEvent.connect(function(action, state) {
-        _this.onActionEvent(action, state);
+    var that = this;
+    Controller.inputEvent.connect(function(action, state) {
+        that.onInputEvent(action, state);
     });
 
     Script.update.connect(function(deltaTime) {
-        _this.lastUpdateInterval += deltaTime;
-        if (_this.lastUpdateInterval >= _this.UPDATE_INTERVAL) {
-            _this.onUpdate(_this.lastUpdateInterval);
-            _this.lastUpdateInterval = 0;
+        that.lastUpdateInterval += deltaTime;
+        if (that.lastUpdateInterval >= that.UPDATE_INTERVAL) {
+            that.onUpdate(that.lastUpdateInterval);
+            that.lastUpdateInterval = 0;
         }
     });
 
     Script.scriptEnding.connect(function() {
-        _this.onCleanup();
+        that.onCleanup();
     });
 }
 
@@ -86,15 +88,14 @@ OmniTool.prototype.onCleanup = function(action) {
     this.unloadModule();
 }
 
-OmniTool.prototype.onActionEvent = function(action, state) {
-    // FIXME figure out the issues when only one spatial controller is active 
-    // logDebug("Action: " + action + " " + state);
-
-    if (this.module && this.module.onActionEvent) {
-        this.module.onActionEvent(action, state);
+OmniTool.prototype.onInputEvent = function(action, state) {
+    // FIXME figure out the issues when only one spatial controller is active
+    var actionNames = Controller.getActionNames();
+    if (this.module && this.module.onInputEvent) {
+        this.module.onInputEvent(action, state);
     }
 
-    if (action == this.ACTION) {
+    if (action == this.action) {
         if (state) {
             this.onClick();
         } else {
@@ -127,7 +128,7 @@ OmniTool.prototype.setActive = function(active) {
     if (active === this.active) {
         return;
     }
-    logDebug("OmniTool changing active state: " + active);
+    logDebug("OmniTool " + this.left  + " changing active state: " + active);
     this.active = active;
     this.model.setVisible(this.active);
     if (this.module && this.module.onActiveChanged) {
@@ -138,17 +139,17 @@ OmniTool.prototype.setActive = function(active) {
 
 OmniTool.prototype.onUpdate = function(deltaTime) {
     // FIXME this returns data if either the left or right controller is not on the base
-    this.position = Controller.getSpatialControlPosition(this.PALM);
+    this.pose = Controller.getPoseValue(this.palmControl);
+    this.position = this.left ? MyAvatar.leftHandTipPosition : MyAvatar.rightHandTipPosition;
     // When on the base, hydras report a position of 0
     this.setActive(Vec3.length(this.position) > 0.001);
     if (!this.active) {
         return;
     }
     
-    
     if (this.model) {
         // Update the wand
-        var rawRotation = Controller.getSpatialControlRawRotation(this.PALM);
+        var rawRotation = this.pose.rotation;
         this.rotation = Quat.multiply(MyAvatar.orientation, rawRotation);
         this.model.setTransform({
             rotation: this.rotation,
@@ -306,6 +307,7 @@ OmniTool.prototype.scan = function() {
 }
 
 OmniTool.prototype.unloadModule = function() {
+    logDebug("Unloading omniTool module")
     if (this.module && this.module.onUnload) {
         this.module.onUnload();
     }
@@ -348,4 +350,4 @@ OmniTool.prototype.activateNewOmniModule = function() {
 }
 
 // FIXME find a good way to sync the two omni tools
-OMNI_TOOLS = [ new OmniTool(0), new OmniTool(1) ];
+OMNI_TOOLS = [ new OmniTool(true), new OmniTool(false) ];
diff --git a/examples/libraries/utils.js b/examples/libraries/utils.js
index ab86007e4b..25900471c1 100644
--- a/examples/libraries/utils.js
+++ b/examples/libraries/utils.js
@@ -31,13 +31,7 @@ scaleLine = function (start, end, scale) {
 }
 
 findAction = function(name) {
-    var actions = Controller.getAllActions();
-    for (var i = 0; i < actions.length; i++) {
-        if (actions[i].actionName == name) {
-            return i;
-        }
-    }
-    return 0;
+    return Controller.findAction(name);
 }
 
 addLine = function(origin, vector, color) {

From 56deef9d6ebfb1950e08eed5cb141f1dfbdacf2d Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 23 Oct 2015 12:15:30 -0700
Subject: [PATCH 129/301] Moving omniTool to a route mapped input

---
 examples/libraries/omniTool.js                | 31 ++++-----
 .../controllers/src/controllers/Endpoint.h    |  1 +
 .../controllers/src/controllers/Forward.h     | 37 +++++++++++
 .../src/controllers/UserInputMapper.cpp       | 51 ++++++++++++++-
 .../src/controllers/UserInputMapper.h         | 64 +++++++++----------
 .../controllers/impl/RouteBuilderProxy.cpp    |  5 ++
 .../src/controllers/impl/RouteBuilderProxy.h  |  1 +
 7 files changed, 139 insertions(+), 51 deletions(-)
 create mode 100644 libraries/controllers/src/controllers/Forward.h

diff --git a/examples/libraries/omniTool.js b/examples/libraries/omniTool.js
index a7fee1a4cf..4c995d6528 100644
--- a/examples/libraries/omniTool.js
+++ b/examples/libraries/omniTool.js
@@ -22,10 +22,10 @@ OmniTool = function(left) {
     this.MAX_FRAMERATE = 60;
     this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
     this.left = left;
+    this.triggered = false;
     var actions = Controller.Actions;
     var standard = Controller.Standard;
     this.palmControl = left ? actions.LeftHand : actions.RightHand;
-    this.action = left ? standard.LeftPrimaryThumb : standard.RightPrimaryThumb;
     logDebug("Init OmniTool " + (left ? "left" : "right"));
     this.highlighter = new Highlighter();
     this.ignoreEntities = {};
@@ -50,9 +50,6 @@ OmniTool = function(left) {
 
     // Connect to desired events
     var that = this;
-    Controller.inputEvent.connect(function(action, state) {
-        that.onInputEvent(action, state);
-    });
 
     Script.update.connect(function(deltaTime) {
         that.lastUpdateInterval += deltaTime;
@@ -65,6 +62,12 @@ OmniTool = function(left) {
     Script.scriptEnding.connect(function() {
         that.onCleanup();
     });
+
+    this.mapping = Controller.newMapping();
+    this.mapping.from(left ? standard.LeftPrimaryThumb : standard.RightPrimaryThumb).to(function(value){
+        that.onUpdateTrigger(value);
+    })
+    this.mapping.enable();
 }
 
 OmniTool.prototype.showWand = function(show) {
@@ -83,29 +86,23 @@ OmniTool.prototype.showWand = function(show) {
     }
 }
 
-
 OmniTool.prototype.onCleanup = function(action) {
+    this.mapping.disable();
     this.unloadModule();
 }
 
-OmniTool.prototype.onInputEvent = function(action, state) {
-    // FIXME figure out the issues when only one spatial controller is active
-    var actionNames = Controller.getActionNames();
-    if (this.module && this.module.onInputEvent) {
-        this.module.onInputEvent(action, state);
-    }
 
-    if (action == this.action) {
-        if (state) {
+OmniTool.prototype.onUpdateTrigger = function (value) {
+    //logDebug("Trigger update value " + value);
+    var triggered = value != 0;
+    if (triggered != this.triggered) {
+        this.triggered = triggered;
+        if (this.triggered) {
             this.onClick();
         } else {
             this.onRelease();
         }
     }
-
-    // FIXME Does not work
-    //// with only one controller active (listed as 2 here because 'tip' + 'palm')
-    //// then treat the alt action button as the action button
 }
 
 OmniTool.prototype.getOmniToolData = function(entityId) {
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index 7a94b06e7e..36ff9388b0 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -36,6 +36,7 @@ namespace controller {
         using WriteLambda = std::function<void(float)>;
 
         Endpoint(const Input& input) : _input(input) {}
+        virtual uint8_t priority() const { return 0x7f; }
         virtual float value() = 0;
         virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
         virtual Pose pose() { return Pose(); }
diff --git a/libraries/controllers/src/controllers/Forward.h b/libraries/controllers/src/controllers/Forward.h
new file mode 100644
index 0000000000..e1a62556d4
--- /dev/null
+++ b/libraries/controllers/src/controllers/Forward.h
@@ -0,0 +1,37 @@
+//
+//  Created by Bradley Austin Davis 2015/10/20
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Forward_h
+#define hifi_Controllers_Forward_h
+
+namespace controller {
+
+class Endpoint;
+using EndpointPointer = std::shared_ptr<Endpoint>;
+using EndpointList = std::list<EndpointPointer>;
+
+class Filter;
+using FilterPointer = std::shared_ptr<Filter>;
+using FilterList = std::list<FilterPointer>;
+
+class Route;
+using RoutePointer = std::shared_ptr<Route>;
+using RouteList = std::list<RoutePointer>;
+
+class Conditional;
+using ConditionalPointer = std::shared_ptr<Conditional>;
+using ConditionalList = std::list<ConditionalPointer>;
+
+class Mapping;
+using MappingPointer = std::shared_ptr<Mapping>;
+using MappingList = std::list<MappingPointer>;
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 07f1f975a2..0ec9ce899d 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -21,8 +21,13 @@
 #include <NumericalConstants.h>
 
 #include "StandardController.h"
+
 #include "Logging.h"
 
+#include "Endpoint.h"
+#include "Route.h"
+#include "Mapping.h"
+
 namespace controller {
     const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
     const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
@@ -211,6 +216,9 @@ public:
         }
     }
 
+    // Process later than normal
+    virtual uint8_t priority() const override { return 0x6F; }
+
     virtual float value() override {
         float result = 0;
         for (auto& child : _children) {
@@ -674,19 +682,27 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
 
 static auto lastDebugTime = usecTimestampNow();
 static auto debugRoutes = false;
+static auto debuggableRoutes = false;
 static const auto DEBUG_INTERVAL = USECS_PER_SECOND;
 
 void UserInputMapper::runMappings() {
     auto now = usecTimestampNow();
-    if (now - lastDebugTime > DEBUG_INTERVAL) {
+    if (debuggableRoutes && now - lastDebugTime > DEBUG_INTERVAL) {
         lastDebugTime = now;
         debugRoutes = true;
     }
+
+    if (debugRoutes) {
+        qCDebug(controllers) << "Beginning mapping frame";
+    }
     static auto deviceNames = getDeviceNames();
     for (auto endpointEntry : this->_endpointsByInput) {
         endpointEntry.second->reset();
     }
 
+    if (debugRoutes) {
+        qCDebug(controllers) << "Processing device routes";
+    }
     // Now process the current values for each level of the stack
     for (const auto& route : _deviceRoutes) {
         if (!route) {
@@ -695,12 +711,19 @@ void UserInputMapper::runMappings() {
         applyRoute(route);
     }
 
+    if (debugRoutes) {
+        qCDebug(controllers) << "Processing standard routes";
+    }
     for (const auto& route : _standardRoutes) {
         if (!route) {
             continue;
         }
         applyRoute(route);
     }
+
+    if (debugRoutes) {
+        qCDebug(controllers) << "Done with mappings";
+    }
     debugRoutes = false;
 }
 
@@ -1174,6 +1197,22 @@ Mapping::Pointer UserInputMapper::parseMapping(const QString& json) {
     return parseMapping(doc.object());
 }
 
+template <typename T>
+bool hasDebuggableRoute(const T& routes) {
+    for (auto route : routes) {
+        if (route->debug) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void sortRoutes(Route::List& routes) {
+    std::stable_sort(routes.begin(), routes.end(), [](const Route::Pointer a, const Route::Pointer b) {
+        return a->source->priority() < b->source->priority();
+    });
+}
+
 
 void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
     Locker locker(_lock);
@@ -1186,12 +1225,18 @@ void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
         return (value->source->getInput().device != STANDARD_DEVICE);
     });
     _standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end());
+    sortRoutes(_standardRoutes);
 
     Route::List deviceRoutes = mapping->routes;
     deviceRoutes.remove_if([](const Route::Pointer& value) {
         return (value->source->getInput().device == STANDARD_DEVICE);
     });
     _deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
+    sortRoutes(_standardRoutes);
+
+    if (!debuggableRoutes) {
+        debuggableRoutes = hasDebuggableRoute(_deviceRoutes) || hasDebuggableRoute(_standardRoutes);
+    }
 }
 
 void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
@@ -1204,6 +1249,10 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
     _standardRoutes.remove_if([&](const Route::Pointer& value) {
         return routeSet.count(value) != 0;
     });
+
+    if (debuggableRoutes) {
+        debuggableRoutes = hasDebuggableRoute(_deviceRoutes) || hasDebuggableRoute(_standardRoutes);
+    }
 }
 
 }
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 0989fdb311..31924b4724 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -23,13 +23,12 @@
 #include <DependencyManager.h>
 #include <RegisteredMetaTypes.h>
 
+#include "Forward.h"
 #include "Pose.h"
 #include "Input.h"
 #include "InputDevice.h"
 #include "DeviceProxy.h"
 #include "StandardControls.h"
-#include "Mapping.h"
-#include "Endpoint.h"
 #include "Actions.h"
 
 namespace controller {
@@ -45,15 +44,14 @@ namespace controller {
     public:
         using InputPair = Input::NamedPair;
         // FIXME move to unordered set / map
-        using EndpointToInputMap = std::map<Endpoint::Pointer, Input>;
-        using MappingNameMap = std::map<QString, Mapping::Pointer>;
-        using MappingDeviceMap = std::map<uint16_t, Mapping::Pointer>;
-        using MappingStack = std::list<Mapping::Pointer>;
-        using InputToEndpointMap = std::map<Input, Endpoint::Pointer>;
-        using EndpointSet = std::unordered_set<Endpoint::Pointer>;
-        using EndpointOverrideMap = std::map<Endpoint::Pointer, Endpoint::Pointer>;
-        using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
-        using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
+        using EndpointToInputMap = std::map<EndpointPointer, Input>;
+        using MappingNameMap = std::map<QString, MappingPointer>;
+        using MappingDeviceMap = std::map<uint16_t, MappingPointer>;
+        using MappingStack = std::list<MappingPointer>;
+        using InputToEndpointMap = std::map<Input, EndpointPointer>;
+        using EndpointSet = std::unordered_set<EndpointPointer>;
+        using EndpointPair = std::pair<EndpointPointer, EndpointPointer>;
+        using EndpointPairMap = std::map<EndpointPair, EndpointPointer>;
         using DevicesMap = std::map<int, DeviceProxy::Pointer>;
         using uint16 = uint16_t;
         using uint32 = uint32_t;
@@ -107,9 +105,9 @@ namespace controller {
         uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
         DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
 
-        Mapping::Pointer newMapping(const QString& mappingName);
-        Mapping::Pointer parseMapping(const QString& json);
-        Mapping::Pointer loadMapping(const QString& jsonFile);
+        MappingPointer newMapping(const QString& mappingName);
+        MappingPointer parseMapping(const QString& json);
+        MappingPointer loadMapping(const QString& jsonFile);
 
         void enableMapping(const QString& mappingName, bool enable = true);
         float getValue(const Input& input) const;
@@ -138,30 +136,30 @@ namespace controller {
         int recordDeviceOfType(const QString& deviceName);
         QHash<const QString&, int> _deviceCounts;
 
-        float getValue(const Endpoint::Pointer& endpoint) const;
-        Pose getPose(const Endpoint::Pointer& endpoint) const;
+        float getValue(const EndpointPointer& endpoint) const;
+        Pose getPose(const EndpointPointer& endpoint) const;
 
         friend class RouteBuilderProxy;
         friend class MappingBuilderProxy;
 
         void runMappings();
-        void applyRoute(const Route::Pointer& route);
-        void enableMapping(const Mapping::Pointer& mapping);
-        void disableMapping(const Mapping::Pointer& mapping);
-        Endpoint::Pointer endpointFor(const QJSValue& endpoint);
-        Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
-        Endpoint::Pointer endpointFor(const Input& endpoint) const;
-        Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
+        void applyRoute(const RoutePointer& route);
+        void enableMapping(const MappingPointer& mapping);
+        void disableMapping(const MappingPointer& mapping);
+        EndpointPointer endpointFor(const QJSValue& endpoint);
+        EndpointPointer endpointFor(const QScriptValue& endpoint);
+        EndpointPointer endpointFor(const Input& endpoint) const;
+        EndpointPointer compositeEndpointFor(EndpointPointer first, EndpointPointer second);
         
-        Mapping::Pointer parseMapping(const QJsonValue& json);
-        Route::Pointer parseRoute(const QJsonValue& value);
-        Endpoint::Pointer parseDestination(const QJsonValue& value);
-        Endpoint::Pointer parseSource(const QJsonValue& value);
-        Endpoint::Pointer parseEndpoint(const QJsonValue& value);
-        Conditional::Pointer parseConditional(const QJsonValue& value);
+        MappingPointer parseMapping(const QJsonValue& json);
+        RoutePointer parseRoute(const QJsonValue& value);
+        EndpointPointer parseDestination(const QJsonValue& value);
+        EndpointPointer parseSource(const QJsonValue& value);
+        EndpointPointer parseEndpoint(const QJsonValue& value);
+        ConditionalPointer parseConditional(const QJsonValue& value);
 
-        static Filter::Pointer parseFilter(const QJsonValue& value);
-        static Filter::List parseFilters(const QJsonValue& value);
+        static FilterPointer parseFilter(const QJsonValue& value);
+        static FilterList parseFilters(const QJsonValue& value);
 
         InputToEndpointMap _endpointsByInput;
         EndpointToInputMap _inputsByEndpoint;
@@ -170,8 +168,8 @@ namespace controller {
         MappingNameMap _mappingsByName;
         MappingDeviceMap _mappingsByDevice;
 
-        Route::List _deviceRoutes;
-        Route::List _standardRoutes;
+        RouteList _deviceRoutes;
+        RouteList _standardRoutes;
 
         using Locker = std::unique_lock<std::recursive_mutex>;
 
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index 186cf2e84e..c0d0758e4e 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -39,6 +39,11 @@ void RouteBuilderProxy::to(const Endpoint::Pointer& destination) {
     deleteLater();
 }
 
+QObject* RouteBuilderProxy::debug(bool enable) {
+    _route->debug = enable;
+    return this;
+}
+
 QObject* RouteBuilderProxy::filterQml(const QJSValue& expression) {
     if (expression.isCallable()) {
         addFilter([=](float value) {
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 6bceba995a..0484c5890d 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -35,6 +35,7 @@ class RouteBuilderProxy : public QObject {
         Q_INVOKABLE QObject* filterQml(const QJSValue& expression);
 
         Q_INVOKABLE void to(const QScriptValue& destination);
+        Q_INVOKABLE QObject* debug(bool enable = true);
         Q_INVOKABLE QObject* filter(const QScriptValue& expression);
         Q_INVOKABLE QObject* clamp(float min, float max);
         Q_INVOKABLE QObject* pulse(float interval);

From 4110324b35ade2d8c71377b8aafaa73c1dbd572f Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 23 Oct 2015 12:55:04 -0700
Subject: [PATCH 130/301] Add another bit to channel types so we can fit rumble

---
 libraries/controllers/src/controllers/Input.cpp |  9 ++++-----
 libraries/controllers/src/controllers/Input.h   | 10 ++++++----
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/libraries/controllers/src/controllers/Input.cpp b/libraries/controllers/src/controllers/Input.cpp
index 4f645c3f95..6f8bd547a2 100644
--- a/libraries/controllers/src/controllers/Input.cpp
+++ b/libraries/controllers/src/controllers/Input.cpp
@@ -9,10 +9,9 @@
 #include "Input.h"
 
 namespace controller {
-
-    const uint16_t Input::INVALID_DEVICE = 0xffff;
-    const uint16_t Input::INVALID_CHANNEL = 0x1fff;
-    const uint16_t Input::INVALID_TYPE = (uint16_t)ChannelType::INVALID;
-    const Input Input::INVALID_INPUT = Input(INVALID_DEVICE, INVALID_CHANNEL, ChannelType::INVALID);
+    const Input Input::INVALID_INPUT = Input(0x7fffffff);
+    const uint16_t Input::INVALID_DEVICE = Input::INVALID_INPUT.device;
+    const uint16_t Input::INVALID_CHANNEL = Input::INVALID_INPUT.channel;
+    const uint16_t Input::INVALID_TYPE = Input::INVALID_INPUT.type;
 }
 
diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h
index 7382d365ec..db99e820da 100644
--- a/libraries/controllers/src/controllers/Input.h
+++ b/libraries/controllers/src/controllers/Input.h
@@ -16,10 +16,12 @@
 namespace controller {
 
 enum class ChannelType {
-    INVALID = 0,
-    BUTTON = 1,
+    UNKNOWN = 0,
+    BUTTON,
     AXIS,
     POSE,
+    RUMBLE,
+    INVALID = 0x7
 };
 
 // Input is the unique identifier to find a n input channel of a particular device
@@ -30,8 +32,8 @@ struct Input {
         uint32_t id{ 0 }; // by default Input is 0 meaning invalid
         struct {
             uint16_t device; // Up to 64K possible devices
-            uint16_t channel : 13 ; // 2^13 possible channel per Device
-            uint16_t type : 2; // 2 bits to store the Type directly in the ID
+            uint16_t channel : 12 ; // 2^12 possible channel per Device
+            uint16_t type : 3; // 2 bits to store the Type directly in the ID
             uint16_t padding : 1; // 2 bits to store the Type directly in the ID
         };
     };

From 54c20a8dd7f094c752a469671e66aacb67ea062a Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 23 Oct 2015 12:56:03 -0700
Subject: [PATCH 131/301] Taking a different tack on proper ordering of routes

---
 .../controllers/src/controllers/Endpoint.h    |  1 -
 .../src/controllers/UserInputMapper.cpp       | 94 +++++++++++--------
 .../src/controllers/UserInputMapper.h         |  7 +-
 3 files changed, 60 insertions(+), 42 deletions(-)

diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h
index 36ff9388b0..7a94b06e7e 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/Endpoint.h
@@ -36,7 +36,6 @@ namespace controller {
         using WriteLambda = std::function<void(float)>;
 
         Endpoint(const Input& input) : _input(input) {}
-        virtual uint8_t priority() const { return 0x7f; }
         virtual float value() = 0;
         virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
         virtual Pose pose() { return Pose(); }
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 0ec9ce899d..e924718fca 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -216,9 +216,6 @@ public:
         }
     }
 
-    // Process later than normal
-    virtual uint8_t priority() const override { return 0x6F; }
-
     virtual float value() override {
         float result = 0;
         for (auto& child : _children) {
@@ -234,7 +231,15 @@ public:
         qFatal("AnyEndpoint is read only");
     }
 
-    virtual bool writeable() const override { return false; }
+    // AnyEndpoint is used for reading, so return false if any child returns false (has been written to)
+    virtual bool writeable() const override { 
+        for (auto& child : _children) {
+            if (!child->writeable()) {
+                return false;
+            }
+        }
+        return true;
+    }
 
     virtual bool readable() const override { 
         for (auto& child : _children) {
@@ -286,13 +291,11 @@ public:
 
     virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
 
-    virtual bool writeable() const { return !_written; }
+    virtual bool writeable() const { return false; }
     virtual bool readable() const { return !_read; }
-    virtual void reset() { _written = _read = false; }
+    virtual void reset() { _read = false; }
 
 private:
-
-    bool _written { false };
     bool _read { false };
 };
 
@@ -695,7 +698,6 @@ void UserInputMapper::runMappings() {
     if (debugRoutes) {
         qCDebug(controllers) << "Beginning mapping frame";
     }
-    static auto deviceNames = getDeviceNames();
     for (auto endpointEntry : this->_endpointsByInput) {
         endpointEntry.second->reset();
     }
@@ -704,22 +706,12 @@ void UserInputMapper::runMappings() {
         qCDebug(controllers) << "Processing device routes";
     }
     // Now process the current values for each level of the stack
-    for (const auto& route : _deviceRoutes) {
-        if (!route) {
-            continue;
-        }
-        applyRoute(route);
-    }
+    applyRoutes(_deviceRoutes);
 
     if (debugRoutes) {
         qCDebug(controllers) << "Processing standard routes";
     }
-    for (const auto& route : _standardRoutes) {
-        if (!route) {
-            continue;
-        }
-        applyRoute(route);
-    }
+    applyRoutes(_standardRoutes);
 
     if (debugRoutes) {
         qCDebug(controllers) << "Done with mappings";
@@ -727,21 +719,53 @@ void UserInputMapper::runMappings() {
     debugRoutes = false;
 }
 
-void UserInputMapper::applyRoute(const Route::Pointer& route) {
+// Encapsulate the logic that routes should not be read before they are written
+void UserInputMapper::applyRoutes(const Route::List& routes) {
+    Route::List deferredRoutes;
+
+    for (const auto& route : routes) {
+        if (!route) {
+            continue;
+        }
+
+        // Try all the deferred routes
+        deferredRoutes.remove_if([](Route::Pointer route) {
+            return UserInputMapper::applyRoute(route);
+        });
+
+        if (!applyRoute(route)) {
+            deferredRoutes.push_back(route);
+        }
+    }
+
+    bool force = true;
+    for (const auto& route : deferredRoutes) {
+        UserInputMapper::applyRoute(route, force);
+    }
+}
+
+
+bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
     if (debugRoutes && route->debug) {
         qCDebug(controllers) << "Applying route " << route->json;
     }
 
+    // If the source hasn't been written yet, defer processing of this route
+    auto source = route->source;
+    if (!force && source->writeable()) {
+        return false;
+    }
+
     if (route->conditional) {
+        // FIXME for endpoint conditionals we need to check if they've been written
         if (!route->conditional->satisfied()) {
             if (debugRoutes && route->debug) {
                 qCDebug(controllers) << "Conditional failed";
             }
-            return;
+            return true;
         }
     }
 
-    auto source = route->source;
 
     // Most endpoints can only be read once (though a given mapping can route them to 
     // multiple places).  Consider... If the default is to wire the A button to JUMP
@@ -752,7 +776,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
         if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Source unreadable";
         }
-        return;
+        return true;
     }
 
     auto destination = route->destination;
@@ -762,14 +786,14 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
         if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Bad Destination";
         }
-        return;
+        return true;
     }
 
     if (!destination->writeable()) {
         if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Destination unwritable";
         }
-        return;
+        return true;
     }
 
     // Fetch the value, may have been overriden by previous loopback routes
@@ -805,6 +829,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
 
         destination->apply(value, 0, source);
     }
+    return true;
 }
 
 Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) {
@@ -910,12 +935,12 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
     }
 }
 
-float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const {
-    Locker locker(_lock);
+float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) {
     return endpoint->value();
 }
 
 float UserInputMapper::getValue(const Input& input) const {
+    Locker locker(_lock);
     auto endpoint = endpointFor(input);
     if (!endpoint) {
         return 0;
@@ -923,7 +948,7 @@ float UserInputMapper::getValue(const Input& input) const {
     return endpoint->value();
 }
 
-Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) const {
+Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) {
     if (!endpoint->isPose()) {
         return Pose();
     }
@@ -931,6 +956,7 @@ Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) const {
 }
 
 Pose UserInputMapper::getPose(const Input& input) const {
+    Locker locker(_lock);
     auto endpoint = endpointFor(input);
     if (!endpoint) {
         return Pose();
@@ -1207,12 +1233,6 @@ bool hasDebuggableRoute(const T& routes) {
     return false;
 }
 
-void sortRoutes(Route::List& routes) {
-    std::stable_sort(routes.begin(), routes.end(), [](const Route::Pointer a, const Route::Pointer b) {
-        return a->source->priority() < b->source->priority();
-    });
-}
-
 
 void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
     Locker locker(_lock);
@@ -1225,14 +1245,12 @@ void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
         return (value->source->getInput().device != STANDARD_DEVICE);
     });
     _standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end());
-    sortRoutes(_standardRoutes);
 
     Route::List deviceRoutes = mapping->routes;
     deviceRoutes.remove_if([](const Route::Pointer& value) {
         return (value->source->getInput().device == STANDARD_DEVICE);
     });
     _deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
-    sortRoutes(_standardRoutes);
 
     if (!debuggableRoutes) {
         debuggableRoutes = hasDebuggableRoute(_deviceRoutes) || hasDebuggableRoute(_standardRoutes);
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 31924b4724..319037fcb1 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -136,14 +136,15 @@ namespace controller {
         int recordDeviceOfType(const QString& deviceName);
         QHash<const QString&, int> _deviceCounts;
 
-        float getValue(const EndpointPointer& endpoint) const;
-        Pose getPose(const EndpointPointer& endpoint) const;
+        static float getValue(const EndpointPointer& endpoint);
+        static Pose getPose(const EndpointPointer& endpoint);
 
         friend class RouteBuilderProxy;
         friend class MappingBuilderProxy;
 
         void runMappings();
-        void applyRoute(const RoutePointer& route);
+        static void applyRoutes(const RouteList& route);
+        static bool applyRoute(const RoutePointer& route, bool force = false);
         void enableMapping(const MappingPointer& mapping);
         void disableMapping(const MappingPointer& mapping);
         EndpointPointer endpointFor(const QJSValue& endpoint);

From 6001968d92732671eb80504bece7de2857d2f5f0 Mon Sep 17 00:00:00 2001
From: AlessandroSigna <alesigna92@gmail.com>
Date: Fri, 23 Oct 2015 13:52:22 -0700
Subject: [PATCH 132/301] Fix paddleBall.js

---
 examples/controllers/hydra/paddleBall.js | 32 ++++++++++++++++--------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/examples/controllers/hydra/paddleBall.js b/examples/controllers/hydra/paddleBall.js
index 91b2520e1d..87e81b6801 100644
--- a/examples/controllers/hydra/paddleBall.js
+++ b/examples/controllers/hydra/paddleBall.js
@@ -37,9 +37,17 @@ var hand;
 
 function setControllerID() {
     if (leftHanded)  {
-        hand = Controller.Standard.LeftHand;
+        hand = MyAvatar.getLeftHandPose();
     } else {
-        hand = Controller.Standard.RightHand; 
+        hand = MyAvatar.rightHandPosition; 
+    }
+}
+
+function getHandPose(){
+	if (leftHanded)  {
+         return MyAvatar.getLeftHandPose();
+    } else {
+        return MyAvatar.rightHandPosition; 
     }
 }
 
@@ -63,7 +71,7 @@ var ball, paddle, paddleModel, line;
 function createEntities() {
     ball = Entities.addEntity(
                 { type: "Sphere",
-                position: Controller.getPoseValue(hand).translation,
+                position: getHandPose().translation,
                 dimensions: { x: BALL_SIZE, y: BALL_SIZE, z: BALL_SIZE }, 
                   color: BALL_COLOR,
                   gravity: {  x: 0, y: GRAVITY, z: 0 },
@@ -73,27 +81,29 @@ function createEntities() {
 
     paddle = Entities.addEntity(
                 { type: "Box",
-                position: Controller.getPoseValue(hand).translation,  
+                position: getHandPose().translation,  
                 dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 0.80 }, 
                   color: PADDLE_COLOR,
                   gravity: {  x: 0, y: 0, z: 0 },
                 ignoreCollisions: false,
                 damping: 0.10,
                 visible: false,
-                rotation: Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation,
+                //rotation: Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation, 
+				rotation : getHandPose().rotation,
                 collisionsWillMove: false });
 
     modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx";
     paddleModel = Entities.addEntity(
                 { type: "Model",
-                position: Vec3.sum(Controller.getPoseValue(hand).translation, PADDLE_BOX_OFFSET),   
+                position: Vec3.sum(hand, PADDLE_BOX_OFFSET),   
                 dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 }, 
                   color: PADDLE_COLOR,
                   gravity: {  x: 0, y: 0, z: 0 },
                 ignoreCollisions: true,
                 modelURL: modelURL,
                 damping: 0.10,
-                rotation: Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation,
+                //rotation: Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation,
+				rotation : getHandPose().rotation,
                 collisionsWillMove: false });
 
     line = Overlays.addOverlay("line3d", {
@@ -118,7 +128,7 @@ function deleteEntities() {
 }
 
 function update(deltaTime) {
-    var palmPosition = Controller.getPoseValue(hand).translation;
+    var palmPosition = getHandPose().translation;
     var controllerActive = (Vec3.length(palmPosition) > 0);
 
     if (!gameOn && controllerActive) {
@@ -133,7 +143,7 @@ function update(deltaTime) {
     }
 
         var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
-        var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation), paddleOrientation);
+        var paddleWorldOrientation = Quat.multiply(getHandPose().rotation, paddleOrientation);
         var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(), 
                                     Vec3.multiplyQbyV(paddleWorldOrientation, leftHanded ? HOLD_POSITION_LEFT_OFFSET : HOLD_POSITION_RIGHT_OFFSET ));
 
@@ -146,10 +156,10 @@ function update(deltaTime) {
         Entities.editEntity(ball, { velocity: ballVelocity });
         Overlays.editOverlay(line, { start: props.position, end: holdPosition });
         Entities.editEntity(paddle, { position: holdPosition, 
-                                      velocity: Controller.getPoseValue(hand).velocity,
+                                      velocity: getHandPose().velocity,	//fix this maybe
                                       rotation: paddleWorldOrientation });
         Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)), 
-                                      velocity: Controller.getPoseValue(hand).velocity,
+                                      velocity: getHandPose().velocity, //fix this maybe
                                       rotation: paddleWorldOrientation });
 
 }

From 7e3192d0f6d4e15baafc74e1205bb06f2251d8b0 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 14:04:06 -0700
Subject: [PATCH 133/301] fix drumstick.js

fix drumstick.js
---
 examples/controllers/hydra/drumStick.js | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/examples/controllers/hydra/drumStick.js b/examples/controllers/hydra/drumStick.js
index e59528aa80..97a8bd856d 100644
--- a/examples/controllers/hydra/drumStick.js
+++ b/examples/controllers/hydra/drumStick.js
@@ -43,7 +43,8 @@ strokeSpeed[1] = 0.0;
 
 function checkSticks(deltaTime) {
     for (var palm = 0; palm < 2; palm++) {
-        var palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1);
+        var handPose = (palm == 0) ? MyAvatar.leftHandPose : MyAvatar.rightHandPose;
+        var palmVelocity = handPose.velocity;
         var speed = length(palmVelocity);
         
         const TRIGGER_SPEED = 0.30;            //    Lower this value to let you 'drum' more gently
@@ -64,7 +65,7 @@ function checkSticks(deltaTime) {
             if ((palmVelocity.y > 0.0) || (speed < STOP_SPEED)) {
                 state[palm] = 0;
         
-                var options = { position: Controller.getSpatialControlPosition(palm * 2 + 1) };
+                var options = { position: handPose.translation };
         
                 if (strokeSpeed[palm] > 1.0) { strokeSpeed[palm] = 1.0; }
                 options.volume = strokeSpeed[palm];

From f14a321d035ae778992d826f5b9b6c1d15b657f9 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 23 Oct 2015 15:03:04 -0700
Subject: [PATCH 134/301] Adding a amoving Average for the velocity of the
 hydra

---
 .../src/input-plugins/SixenseManager.cpp      | 21 +++++++++++--
 .../src/input-plugins/SixenseManager.h        | 31 +++++++++++++++++++
 2 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 29e60ca5ec..1f72d66019 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -178,6 +178,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
 
     if (sixenseGetNumActiveControllers() == 0) {
         _poseStateMap.clear();
+        _collectedSamples.clear();
         return;
     }
 
@@ -234,9 +235,12 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
                 
             } else {
                 _poseStateMap.clear();
+                _collectedSamples.clear();
             }
         } else {
-            _poseStateMap[left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND] = controller::Pose();
+            auto hand = left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND;
+            _poseStateMap[hand] = controller::Pose();
+            _collectedSamples[hand].clear();
         }
     }
 
@@ -387,6 +391,8 @@ void SixenseManager::handleButtonEvent(unsigned int buttons, bool left) {
 
 void SixenseManager::handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left) {
 #ifdef HAVE_SIXENSE
+    auto hand = left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND;
+
     // From ABOVE the sixense coordinate frame looks like this:
     //
     //       |
@@ -401,7 +407,7 @@ void SixenseManager::handlePoseEvent(float deltaTime, glm::vec3 position, glm::q
     //                      |
     //                      |
     //                      z
-    auto prevPose = _poseStateMap[left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND];
+    auto prevPose = _poseStateMap[hand];
 
     // Transform the measured position into body frame.
     position = _avatarRotation * (position + _avatarPosition);
@@ -448,7 +454,10 @@ void SixenseManager::handlePoseEvent(float deltaTime, glm::vec3 position, glm::q
     glm::vec3 velocity(0.0f);
     glm::quat angularVelocity;
 
+
+
     if (prevPose.isValid() && deltaTime > std::numeric_limits<float>::epsilon()) {
+
         velocity = (position - prevPose.getTranslation()) / deltaTime;
 
         auto deltaRot = rotation * glm::conjugate(prevPose.getRotation());
@@ -456,9 +465,15 @@ void SixenseManager::handlePoseEvent(float deltaTime, glm::vec3 position, glm::q
         auto angle = glm::angle(deltaRot);
         angularVelocity = glm::angleAxis(angle / deltaTime, axis);
 
+        // Average
+        auto& samples = _collectedSamples[hand];
+        samples.addSample(velocity);
+        velocity = samples.average;
+    } else if (!prevPose.isValid()) {
+        _collectedSamples[hand].clear();
     }
 
-    _poseStateMap[left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND] = controller::Pose(position, rotation, velocity, angularVelocity);
+    _poseStateMap[hand] = controller::Pose(position, rotation, velocity, angularVelocity);
 #endif // HAVE_SIXENSE
 }
 
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index 368321e669..c0d908ed45 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -94,6 +94,36 @@ private:
     glm::vec3 _reachRight;
     float _lastDistance;
     bool _useSixenseFilter = true;
+
+    template <class T, int MAX_NUM_SAMPLES> class MovingAverage {
+    public:
+        using Samples = std::list< T >;
+        Samples samples;
+        T average;
+
+        void clear() {
+            samples.clear();
+        }
+
+        bool isAverageValid() const { return !samples.empty(); }
+
+        void addSample(T sample) {
+            samples.push_front(sample);
+            int numSamples = samples.size();
+
+            if (numSamples < MAX_NUM_SAMPLES) {
+                average = (sample + average * float(numSamples - 1)) / float(numSamples);
+            } else {
+                T tail = samples.back();
+                samples.pop_back();
+                average = average + (sample - tail) / float(numSamples);
+            }
+        }
+    };
+
+    static const int MAX_NUM_AVERAGING_SAMPLES = 10; // At ~100 updates per seconds this means averaging over ~.1s
+    using MovingAverageMap = std::map< int, MovingAverage< glm::vec3, MAX_NUM_AVERAGING_SAMPLES> >;
+    MovingAverageMap _collectedSamples;
     
 #ifdef __APPLE__
     QLibrary* _sixenseLibrary;
@@ -109,3 +139,4 @@ private:
 };
 
 #endif // hifi_SixenseManager_h
+

From 37e1e43ce0b573ce77d08a38be06c363ab6d5253 Mon Sep 17 00:00:00 2001
From: AlessandroSigna <alesigna92@gmail.com>
Date: Fri, 23 Oct 2015 15:48:29 -0700
Subject: [PATCH 135/301] Fix paddleBall.js

---
 examples/controllers/hydra/paddleBall.js | 49 +++++++-----------------
 1 file changed, 14 insertions(+), 35 deletions(-)

diff --git a/examples/controllers/hydra/paddleBall.js b/examples/controllers/hydra/paddleBall.js
index 87e81b6801..d90a78c260 100644
--- a/examples/controllers/hydra/paddleBall.js
+++ b/examples/controllers/hydra/paddleBall.js
@@ -20,10 +20,11 @@ var BALL_SIZE = 0.08;
 var PADDLE_SIZE = 0.20;
 var PADDLE_THICKNESS = 0.06;
 var PADDLE_COLOR = { red: 184, green: 134, blue: 11 };
-var BALL_COLOR = { red: 255, green: 0, blue: 0 };
+var BALL_COLOR = { red: 0, green: 255, blue: 0 };
 var LINE_COLOR = { red: 255, green: 255, blue: 0 };
 var PADDLE_BOX_OFFSET = { x: 0.05, y: 0.0, z: 0.0 };
 
+//probably we need to fix these initial values (offsets and orientation)
 var HOLD_POSITION_LEFT_OFFSET = { x: -0.15, y: 0.05, z: -0.05 }; 
 var HOLD_POSITION_RIGHT_OFFSET = { x: -0.15, y: 0.05, z: 0.05 }; 
 var PADDLE_ORIENTATION = Quat.fromPitchYawRollDegrees(0,0,0);
@@ -32,26 +33,7 @@ var SPRING_FORCE = 15.0;
 var lastSoundTime = 0; 
 var gameOn = false; 
 var leftHanded = true; 
-var hand;
 
-
-function setControllerID() {
-    if (leftHanded)  {
-        hand = MyAvatar.getLeftHandPose();
-    } else {
-        hand = MyAvatar.rightHandPosition; 
-    }
-}
-
-function getHandPose(){
-	if (leftHanded)  {
-         return MyAvatar.getLeftHandPose();
-    } else {
-        return MyAvatar.rightHandPosition; 
-    }
-}
-
-setControllerID(); 
 Menu.addMenu("PaddleBall");
 Menu.addMenuItem({ menuName: "PaddleBall", menuItemName: "Left-Handed", isCheckable: true, isChecked: true });
 
@@ -71,7 +53,7 @@ var ball, paddle, paddleModel, line;
 function createEntities() {
     ball = Entities.addEntity(
                 { type: "Sphere",
-                position: getHandPose().translation,
+                position: leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation,
                 dimensions: { x: BALL_SIZE, y: BALL_SIZE, z: BALL_SIZE }, 
                   color: BALL_COLOR,
                   gravity: {  x: 0, y: GRAVITY, z: 0 },
@@ -81,30 +63,28 @@ function createEntities() {
 
     paddle = Entities.addEntity(
                 { type: "Box",
-                position: getHandPose().translation,  
+                position: leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation,
                 dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 0.80 }, 
                   color: PADDLE_COLOR,
                   gravity: {  x: 0, y: 0, z: 0 },
                 ignoreCollisions: false,
                 damping: 0.10,
                 visible: false,
-                //rotation: Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation, 
-				rotation : getHandPose().rotation,
-                collisionsWillMove: false });
+				rotation : leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation,
+				collisionsWillMove: false });
 
     modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx";
     paddleModel = Entities.addEntity(
                 { type: "Model",
-                position: Vec3.sum(hand, PADDLE_BOX_OFFSET),   
+                position: Vec3.sum( leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation, PADDLE_BOX_OFFSET),   
                 dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 }, 
                   color: PADDLE_COLOR,
                   gravity: {  x: 0, y: 0, z: 0 },
                 ignoreCollisions: true,
                 modelURL: modelURL,
                 damping: 0.10,
-                //rotation: Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(hand).rotation,
-				rotation : getHandPose().rotation,
-                collisionsWillMove: false });
+                rotation : leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation,
+				collisionsWillMove: false });
 
     line = Overlays.addOverlay("line3d", {
                 start: { x: 0, y: 0, z: 0 },
@@ -128,7 +108,7 @@ function deleteEntities() {
 }
 
 function update(deltaTime) {
-    var palmPosition = getHandPose().translation;
+    var palmPosition = leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation;
     var controllerActive = (Vec3.length(palmPosition) > 0);
 
     if (!gameOn && controllerActive) {
@@ -143,8 +123,8 @@ function update(deltaTime) {
     }
 
         var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
-        var paddleWorldOrientation = Quat.multiply(getHandPose().rotation, paddleOrientation);
-        var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(), 
+        var paddleWorldOrientation = Quat.multiply(leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation, paddleOrientation);
+        var holdPosition = Vec3.sum(leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation, 
                                     Vec3.multiplyQbyV(paddleWorldOrientation, leftHanded ? HOLD_POSITION_LEFT_OFFSET : HOLD_POSITION_RIGHT_OFFSET ));
 
         var props = Entities.getEntityProperties(ball);
@@ -156,10 +136,10 @@ function update(deltaTime) {
         Entities.editEntity(ball, { velocity: ballVelocity });
         Overlays.editOverlay(line, { start: props.position, end: holdPosition });
         Entities.editEntity(paddle, { position: holdPosition, 
-                                      velocity: getHandPose().velocity,	//fix this maybe
+                                      velocity: leftHanded ? MyAvatar.leftHandPose.velocity : MyAvatar.rightHandPose.velocity,
                                       rotation: paddleWorldOrientation });
         Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)), 
-                                      velocity: getHandPose().velocity, //fix this maybe
+                                      velocity: leftHanded ? MyAvatar.leftHandPose.velocity : MyAvatar.rightHandPose.velocity,
                                       rotation: paddleWorldOrientation });
 
 }
@@ -192,7 +172,6 @@ function menuItemEvent(menuItem) {
         leftHanded = Menu.isOptionChecked("Left-Handed");
     }
     if ((leftHanded != oldHanded) && gameOn) {
-        setControllerID();
         deleteEntities(); 
         createEntities();
     }

From d5a90e273e418d02cfa0f69c8ee3687753df6b53 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 15:56:55 -0700
Subject: [PATCH 136/301] fix AnyEndpoint support from JS

---
 .../src/controllers/UserInputMapper.cpp       | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index e924718fca..30fd650eba 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -217,10 +217,10 @@ public:
     }
 
     virtual float value() override {
-        float result = 0;
+        float result = 0.0f;
         for (auto& child : _children) {
             float childResult = child->value();
-            if (childResult != 0.0f) {
+            if (childResult != 0.0f && result == 0.0f) {
                 result = childResult;
             }
         }
@@ -856,6 +856,21 @@ Endpoint::Pointer UserInputMapper::endpointFor(const QScriptValue& endpoint) {
         return result;
     }
 
+    if (endpoint.isArray()) {
+        int length = endpoint.property("length").toInteger();
+        Endpoint::List children;
+        for (int i = 0; i < length; i++) {
+            QScriptValue arrayItem = endpoint.property(i);
+            Endpoint::Pointer destination = endpointFor(arrayItem);
+            if (!destination) {
+                return Endpoint::Pointer();
+            }
+            children.push_back(destination);
+        }
+        return std::make_shared<AnyEndpoint>(children);
+    }
+
+
     qWarning() << "Unsupported input type " << endpoint.toString();
     return Endpoint::Pointer();
 }

From 5c09391170564a0b954de0fea98d46cb8c33a543 Mon Sep 17 00:00:00 2001
From: EdgarPironti <pacepiro@hotmail.it>
Date: Fri, 23 Oct 2015 16:19:40 -0700
Subject: [PATCH 137/301] fix toyball.js

---
 examples/controllers/hydra/toyball.js | 64 +++++++++------------------
 1 file changed, 22 insertions(+), 42 deletions(-)

diff --git a/examples/controllers/hydra/toyball.js b/examples/controllers/hydra/toyball.js
index 0f5db9b2c0..b2616af3e2 100644
--- a/examples/controllers/hydra/toyball.js
+++ b/examples/controllers/hydra/toyball.js
@@ -20,13 +20,8 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
 // maybe we should make these constants...
 var LEFT_PALM = 0;
 var LEFT_TIP = 1;
-var LEFT_BUTTON_FWD = 5;
-var LEFT_BUTTON_3 = 3;
-
 var RIGHT_PALM = 2;
 var RIGHT_TIP = 3;
-var RIGHT_BUTTON_FWD = 11;
-var RIGHT_BUTTON_3 = 9;
 
 var BALL_RADIUS = 0.08;
 var GRAVITY_STRENGTH = 3.0;
@@ -69,9 +64,6 @@ function getBallHoldPosition(whichSide) {
 }
 
 function checkControllerSide(whichSide) {
-    var BUTTON_FWD;
-    var BUTTON_3;
-    var TRIGGER;
     var palmPosition;
     var palmRotation;
     var ballAlreadyInHand;
@@ -79,35 +71,35 @@ function checkControllerSide(whichSide) {
     var linearVelocity;
     var angularVelocity; 
     var AVERAGE_FACTOR = 0.33;
-    
+	var grabButtonPressed;
+	
     if (whichSide == LEFT_PALM) {
-        BUTTON_FWD = LEFT_BUTTON_FWD;
-        BUTTON_3 = LEFT_BUTTON_3;
-        TRIGGER = 0;
-        palmPosition = Controller.getSpatialControlPosition(LEFT_PALM);
-        palmRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(LEFT_PALM));
+		palmPosition = MyAvatar.leftHandPose.translation;
+        palmRotation = MyAvatar.leftHandPose.rotation;
         ballAlreadyInHand = leftBallAlreadyInHand;
         handMessage = "LEFT";
-        averageLinearVelocity[0] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, Controller.getSpatialControlVelocity(LEFT_TIP)), 
+       averageLinearVelocity[0] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, MyAvatar.leftHandTipPose.velocity), 
                                             Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[0]));
-        linearVelocity = averageLinearVelocity[0];
-        angularVelocity = Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getSpatialControlRawAngularVelocity(LEFT_TIP));
+
+	   linearVelocity = averageLinearVelocity[0];
+       angularVelocity = MyAvatar.leftHandTipPose.angularVelocity;
+	   grabButtonPressed = (Controller.getValue(Controller.Standard.LT) > 0.5);
+    
     } else {
-        BUTTON_FWD = RIGHT_BUTTON_FWD;
-        BUTTON_3 = RIGHT_BUTTON_3;
-        TRIGGER = 1;
-        palmPosition = Controller.getSpatialControlPosition(RIGHT_PALM);
-        palmRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(RIGHT_PALM));
-        ballAlreadyInHand = rightBallAlreadyInHand;
-        averageLinearVelocity[1] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, Controller.getSpatialControlVelocity(RIGHT_TIP)), 
+		palmPosition = MyAvatar.rightHandPose.translation;
+        palmRotation = MyAvatar.rightHandPose.rotation;
+		ballAlreadyInHand = rightBallAlreadyInHand;
+		 averageLinearVelocity[1] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, MyAvatar.rightHandTipPose.velocity), 
                                             Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[1]));
-        linearVelocity = averageLinearVelocity[1];
-        angularVelocity = Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getSpatialControlRawAngularVelocity(RIGHT_TIP));
+ 
+		linearVelocity = averageLinearVelocity[1];
+		angularVelocity = MyAvatar.rightHandTipPose.angularVelocity;
         handMessage = "RIGHT";
+		grabButtonPressed = (Controller.getValue(Controller.Standard.RT) > 0.5);
+    
     }
 
-    var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3) || (Controller.getTriggerValue(TRIGGER) > 0.5));
-
+    
     // If I don't currently have a ball in my hand, then try to catch closest one
     if (!ballAlreadyInHand && grabButtonPressed) {
         var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius);
@@ -231,22 +223,10 @@ function checkControllerSide(whichSide) {
         }
     }
 }
-
-
 function checkController(deltaTime) {
-    var numberOfButtons = Controller.getNumberOfButtons();
-    var numberOfTriggers = Controller.getNumberOfTriggers();
-    var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
-    var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
 
-    // this is expected for hydras
-    if (!(numberOfButtons==12 && numberOfTriggers == 2 && controllersPerTrigger == 2)) {
-        debugPrint("total buttons = " + numberOfButtons + ", Triggers = " + numberOfTriggers + ", controllers/trigger = " + controllersPerTrigger); 
-        return; // bail if no hydra
-    }
-
-    checkControllerSide(LEFT_PALM);
-    checkControllerSide(RIGHT_PALM);
+   checkControllerSide(LEFT_PALM);
+   checkControllerSide(RIGHT_PALM);
 }
 
 

From 6b795364c8ed52a2ee2a82d557906710066c86d7 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 16:30:40 -0700
Subject: [PATCH 138/301] make handGrab treat shoulder bumbers and triggers as
 merged control

---
 examples/controllers/handControllerGrab.js | 25 +++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 17d16d1718..80a3ea98a4 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -148,6 +148,7 @@ function MyController(hand, triggerAction) {
     this.state = STATE_OFF;
     this.pointer = null; // entity-id of line object
     this.triggerValue = 0; // rolling average of trigger value
+    this.rawTriggerValue = 0;
 
     var _this = this;
 
@@ -244,12 +245,18 @@ function MyController(hand, triggerAction) {
         this.pointer = null;
     };
 
-    this.updateSmoothedTrigger = function() {
-        var triggerValue = Controller.getValue(this.triggerAction);
+    this.eitherTrigger = function (value) {
+        _this.rawTriggerValue = value;
+    };
+
+    this.updateSmoothedTrigger = function () {
+        //var triggerValue = Controller.getValue(this.triggerAction); // this.rawTriggerValue; // 
+        var triggerValue = this.rawTriggerValue;
         // smooth out trigger value
         this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
             (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO));
-    }
+
+    };
 
     this.triggerSmoothedSqueezed = function() {
         return this.triggerValue > TRIGGER_ON_VALUE;
@@ -259,8 +266,9 @@ function MyController(hand, triggerAction) {
         return this.triggerValue < TRIGGER_OFF_VALUE;
     };
 
-    this.triggerSqueezed = function() {
-        var triggerValue = Controller.getValue(this.triggerAction);
+    this.triggerSqueezed = function() { 
+        var triggerValue = Controller.getValue(this.triggerAction); // this.rawTriggerValue; // 
+        print("triggerSqueezed() triggerValue:" + triggerValue);
         return triggerValue > TRIGGER_ON_VALUE;
     };
 
@@ -861,6 +869,12 @@ function MyController(hand, triggerAction) {
 var rightController = new MyController(RIGHT_HAND, Controller.Standard.RT);
 var leftController = new MyController(LEFT_HAND, Controller.Standard.LT);
 
+var mapping = Controller.newMapping("handGrab");
+mapping.from([Controller.Standard.RB, Controller.Standard.RT]).to(rightController.eitherTrigger);
+mapping.from([Controller.Standard.LB, Controller.Standard.LT]).to(leftController.eitherTrigger);
+Controller.enableMapping("handGrab");
+
+
 function update() {
     rightController.update();
     leftController.update();
@@ -869,6 +883,7 @@ function update() {
 function cleanup() {
     rightController.cleanup();
     leftController.cleanup();
+    Controller.disableMapping("handGrab");
 }
 
 Script.scriptEnding.connect(cleanup);

From 9285cf8e2cff33e2389a1b0cde10ed85b05cae49 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 17:12:26 -0700
Subject: [PATCH 139/301] fix hydraGrabHockey.js to use new API

---
 examples/example/games/hydraGrabHockey.js | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/examples/example/games/hydraGrabHockey.js b/examples/example/games/hydraGrabHockey.js
index b9f760fa08..26f9a443ab 100644
--- a/examples/example/games/hydraGrabHockey.js
+++ b/examples/example/games/hydraGrabHockey.js
@@ -59,9 +59,7 @@ function controller(side) {
   this.triggerHeld = false;
   this.triggerThreshold = 0.9;
   this.side = side;
-  this.palm = 2 * side;
-  this.tip = 2 * side + 1;
-  this.trigger = side;
+  this.trigger = side == LEFT ? Controller.Standard.LT : Controller.Standard.RT;
   this.originalGravity = {
     x: 0,
     y: 0,
@@ -150,8 +148,8 @@ function controller(side) {
 
 
   this.updateControllerState = function() {
-    this.palmPosition = Controller.getSpatialControlPosition(this.palm);
-    this.tipPosition = Controller.getSpatialControlPosition(this.tip);
+    this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation;
+    this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation;
     this.triggerValue = Controller.getTriggerValue(this.trigger);
   }
 

From c64290b5cd0d7400a9fd9e4024fccc6465d41e8d Mon Sep 17 00:00:00 2001
From: EdgarPironti <pacepiro@hotmail.it>
Date: Fri, 23 Oct 2015 17:13:29 -0700
Subject: [PATCH 140/301] Removed unused variables

---
 examples/controllers/hydra/toyball.js | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/examples/controllers/hydra/toyball.js b/examples/controllers/hydra/toyball.js
index b2616af3e2..c3374ffb5f 100644
--- a/examples/controllers/hydra/toyball.js
+++ b/examples/controllers/hydra/toyball.js
@@ -19,9 +19,7 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
 
 // maybe we should make these constants...
 var LEFT_PALM = 0;
-var LEFT_TIP = 1;
 var RIGHT_PALM = 2;
-var RIGHT_TIP = 3;
 
 var BALL_RADIUS = 0.08;
 var GRAVITY_STRENGTH = 3.0;
@@ -179,10 +177,8 @@ function checkControllerSide(whichSide) {
     if (ballAlreadyInHand) {
         if (whichSide == LEFT_PALM) {
             handEntity = leftHandEntity;
-            whichTip = LEFT_TIP;
         } else {
             handEntity = rightHandEntity;
-            whichTip = RIGHT_TIP;
         }
 
         //  If holding the ball keep it in the palm

From ed20e7d209dc12eb73f057ac4b3202e0525f8726 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 17:14:13 -0700
Subject: [PATCH 141/301] CR feedback

---
 examples/controllers/handControllerGrab.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 80a3ea98a4..2b370a3b89 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -869,10 +869,10 @@ function MyController(hand, triggerAction) {
 var rightController = new MyController(RIGHT_HAND, Controller.Standard.RT);
 var leftController = new MyController(LEFT_HAND, Controller.Standard.LT);
 
-var mapping = Controller.newMapping("handGrab");
+var mapping = Controller.newMapping("com.highfidelity.handControllerGrab");
 mapping.from([Controller.Standard.RB, Controller.Standard.RT]).to(rightController.eitherTrigger);
 mapping.from([Controller.Standard.LB, Controller.Standard.LT]).to(leftController.eitherTrigger);
-Controller.enableMapping("handGrab");
+Controller.enableMapping("com.highfidelity.handControllerGrab");
 
 
 function update() {

From 090dc5409b968356fcd69685ae84b04d3a78047a Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 17:14:59 -0700
Subject: [PATCH 142/301] CR feedback

---
 examples/controllers/handControllerGrab.js | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 2b370a3b89..9e21429cdc 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -250,7 +250,6 @@ function MyController(hand, triggerAction) {
     };
 
     this.updateSmoothedTrigger = function () {
-        //var triggerValue = Controller.getValue(this.triggerAction); // this.rawTriggerValue; // 
         var triggerValue = this.rawTriggerValue;
         // smooth out trigger value
         this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
@@ -267,8 +266,7 @@ function MyController(hand, triggerAction) {
     };
 
     this.triggerSqueezed = function() { 
-        var triggerValue = Controller.getValue(this.triggerAction); // this.rawTriggerValue; // 
-        print("triggerSqueezed() triggerValue:" + triggerValue);
+        var triggerValue = this.rawTriggerValue;
         return triggerValue > TRIGGER_ON_VALUE;
     };
 

From 9ba1b800d91655bda082a35035fcad1a138c4dd5 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 17:15:39 -0700
Subject: [PATCH 143/301] CR feedback

---
 examples/controllers/handControllerGrab.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 9e21429cdc..a61f52117b 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -881,7 +881,7 @@ function update() {
 function cleanup() {
     rightController.cleanup();
     leftController.cleanup();
-    Controller.disableMapping("handGrab");
+    Controller.disableMapping("com.highfidelity.handControllerGrab");
 }
 
 Script.scriptEnding.connect(cleanup);

From 0fdd32709f6eb7c52c3dc98568823516cb94671b Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 23 Oct 2015 13:28:36 -0700
Subject: [PATCH 144/301] Moving conditionals and endpoints out of
 UserInputMapper

Conflicts:
	libraries/controllers/src/controllers/UserInputMapper.cpp
---
 .../src/controllers/UserInputMapper.cpp       | 341 +-----------------
 .../controllers/{ => impl}/Conditional.cpp    |   0
 .../src/controllers/{ => impl}/Conditional.h  |   0
 .../src/controllers/{ => impl}/Endpoint.cpp   |   0
 .../src/controllers/{ => impl}/Endpoint.h     |   4 +-
 .../src/controllers/{ => impl}/Filter.cpp     |   0
 .../src/controllers/{ => impl}/Filter.h       |   0
 .../src/controllers/{ => impl}/Mapping.cpp    |   0
 .../src/controllers/{ => impl}/Mapping.h      |   0
 .../controllers/impl/MappingBuilderProxy.h    |   4 +-
 .../src/controllers/{ => impl}/Route.cpp      |   0
 .../src/controllers/{ => impl}/Route.h        |   0
 .../src/controllers/impl/RouteBuilderProxy.h  |   8 +-
 .../impl/conditionals/AndConditional.cpp      |  20 +
 .../impl/conditionals/AndConditional.h        |  32 ++
 .../impl/conditionals/EndpointConditional.cpp |   9 +
 .../impl/conditionals/EndpointConditional.h   |  27 ++
 .../impl/conditionals/NotConditional.cpp      |   9 +
 .../impl/conditionals/NotConditional.h        |  16 +
 .../impl/conditionals/ScriptConditional.cpp   |  27 ++
 .../impl/conditionals/ScriptConditional.h     |  34 ++
 .../impl/endpoints/ActionEndpoint.cpp         |  40 ++
 .../impl/endpoints/ActionEndpoint.h           |  41 +++
 .../impl/endpoints/AnyEndpoint.cpp            |  63 ++++
 .../controllers/impl/endpoints/AnyEndpoint.h  |  32 ++
 .../impl/endpoints/ArrayEndpoint.cpp          |   9 +
 .../impl/endpoints/ArrayEndpoint.h            |  43 +++
 .../impl/endpoints/CompositeEndpoint.cpp      |  32 ++
 .../impl/endpoints/CompositeEndpoint.h        |  26 ++
 .../impl/endpoints/InputEndpoint.cpp          |  41 +++
 .../impl/endpoints/InputEndpoint.h            |  39 ++
 .../controllers/impl/endpoints/JSEndpoint.cpp |   9 +
 .../controllers/impl/endpoints/JSEndpoint.h   |  41 +++
 .../impl/endpoints/ScriptEndpoint.cpp         |  43 +++
 .../impl/endpoints/ScriptEndpoint.h           |  39 ++
 .../impl/endpoints/StandardEndpoint.cpp       |   9 +
 .../impl/endpoints/StandardEndpoint.h         |  60 +++
 37 files changed, 766 insertions(+), 332 deletions(-)
 rename libraries/controllers/src/controllers/{ => impl}/Conditional.cpp (100%)
 rename libraries/controllers/src/controllers/{ => impl}/Conditional.h (100%)
 rename libraries/controllers/src/controllers/{ => impl}/Endpoint.cpp (100%)
 rename libraries/controllers/src/controllers/{ => impl}/Endpoint.h (98%)
 rename libraries/controllers/src/controllers/{ => impl}/Filter.cpp (100%)
 rename libraries/controllers/src/controllers/{ => impl}/Filter.h (100%)
 rename libraries/controllers/src/controllers/{ => impl}/Mapping.cpp (100%)
 rename libraries/controllers/src/controllers/{ => impl}/Mapping.h (100%)
 rename libraries/controllers/src/controllers/{ => impl}/Route.cpp (100%)
 rename libraries/controllers/src/controllers/{ => impl}/Route.h (100%)
 create mode 100644 libraries/controllers/src/controllers/impl/conditionals/AndConditional.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/conditionals/AndConditional.h
 create mode 100644 libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
 create mode 100644 libraries/controllers/src/controllers/impl/conditionals/NotConditional.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/conditionals/NotConditional.h
 create mode 100644 libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h

diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 30fd650eba..19a4b78207 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -24,9 +24,22 @@
 
 #include "Logging.h"
 
-#include "Endpoint.h"
-#include "Route.h"
-#include "Mapping.h"
+#include "impl/conditionals/AndConditional.h"
+#include "impl/conditionals/EndpointConditional.h"
+#include "impl/conditionals/ScriptConditional.h"
+
+#include "impl/endpoints/ActionEndpoint.h"
+#include "impl/endpoints/AnyEndpoint.h"
+#include "impl/endpoints/ArrayEndpoint.h"
+#include "impl/endpoints/CompositeEndpoint.h"
+#include "impl/endpoints/InputEndpoint.h"
+#include "impl/endpoints/JSEndpoint.h"
+#include "impl/endpoints/ScriptEndpoint.h"
+#include "impl/endpoints/StandardEndpoint.h"
+
+#include "impl/Route.h"
+#include "impl/Mapping.h"
+
 
 namespace controller {
     const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
@@ -42,300 +55,6 @@ controller::UserInputMapper::UserInputMapper() {
 
 namespace controller {
 
-class ScriptEndpoint : public Endpoint {
-    Q_OBJECT;
-public:
-    ScriptEndpoint(const QScriptValue& callable)
-        : Endpoint(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;
-};
-
-class StandardEndpoint : public VirtualEndpoint {
-public:
-    StandardEndpoint(const Input& input) : VirtualEndpoint(input) {}
-    virtual bool writeable() const override { return !_written; }
-    virtual bool readable() const override { return !_read; }
-    virtual void reset() override { 
-        apply(0.0f, 0.0f, Endpoint::Pointer());
-        apply(Pose(), Pose(), Endpoint::Pointer());
-        _written = _read = false;
-    }
-
-    virtual float value() override { 
-        _read = true;
-        return VirtualEndpoint::value();
-    }
-
-    virtual void apply(float newValue, float oldValue, const Pointer& source) override { 
-        // For standard endpoints, the first NON-ZERO write counts.  
-        if (newValue != 0.0) {
-            _written = true;
-        }
-        VirtualEndpoint::apply(newValue, oldValue, source);
-    }
-
-    virtual Pose pose() override { 
-        _read = true;
-        return VirtualEndpoint::pose();
-    }
-
-    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
-        if (newValue != Pose()) {
-            _written = true;
-        }
-        VirtualEndpoint::apply(newValue, oldValue, source);
-    }
-
-private:
-    bool _written { false };
-    bool _read { false };
-};
-
-
-class JSEndpoint : public Endpoint {
-public:
-    JSEndpoint(const QJSValue& callable)
-        : Endpoint(Input::INVALID_INPUT), _callable(callable) {
-    }
-
-    virtual float value() {
-        float result = (float)_callable.call().toNumber();;
-        return result;
-    }
-
-    virtual void apply(float newValue, float oldValue, const Pointer& source) {
-        _callable.call(QJSValueList({ QJSValue(newValue) }));
-    }
-
-private:
-    QJSValue _callable;
-};
-
-float ScriptEndpoint::value() {
-    updateValue();
-    return _lastValue;
-}
-
-void ScriptEndpoint::updateValue() {
-    if (QThread::currentThread() != thread()) {
-        QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
-        return;
-    }
-
-    _lastValue = (float)_callable.call().toNumber();
-}
-
-void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
-    internalApply(newValue, oldValue, source->getInput().getID());
-}
-
-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) }));
-}
-
-static const Input INVALID_STANDARD_INPUT = Input(UserInputMapper::STANDARD_DEVICE, Input::INVALID_CHANNEL, ChannelType::INVALID);
-
-class CompositeEndpoint : public Endpoint, Endpoint::Pair {
-public:
-    CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
-        : Endpoint(Input::INVALID_INPUT), Pair(first, second) { 
-        if (first->getInput().device == UserInputMapper::STANDARD_DEVICE &&
-            second->getInput().device == UserInputMapper::STANDARD_DEVICE) {
-            this->_input = INVALID_STANDARD_INPUT;
-        }
-    }
-
-    virtual float value() {
-        float result = first->value() * -1.0f + second->value();
-        return result;
-    }
-
-    virtual void apply(float newValue, float oldValue, const Pointer& source) {
-        // Composites are read only
-    }
-};
-
-class ArrayEndpoint : public Endpoint {
-    friend class UserInputMapper;
-public:
-    using Pointer = std::shared_ptr<ArrayEndpoint>;
-    ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
-
-    virtual float value() override {
-        return 0.0;
-    }
-
-    virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
-        for (auto& child : _children) {
-            if (child->writeable()) {
-                child->apply(newValue, oldValue, source);
-            }
-        }
-    }
-
-    virtual bool readable() const override { return false; }
-
-private:
-    Endpoint::List _children;
-};
-
-class AnyEndpoint : public Endpoint {
-    friend class UserInputMapper;
-public:
-    using Pointer = std::shared_ptr<AnyEndpoint>;
-    AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPUT), _children(children) {
-        bool standard = true;
-        // Ensure if we're building a composite of standard devices the composite itself
-        // is treated as a standard device for rule processing order
-        for (auto endpoint : children) {
-            if (endpoint->getInput().device != UserInputMapper::STANDARD_DEVICE) {
-                standard = false;
-                break;
-            }
-        }
-        if (standard) {
-            this->_input = INVALID_STANDARD_INPUT;
-        }
-    }
-
-    virtual float value() override {
-        float result = 0.0f;
-        for (auto& child : _children) {
-            float childResult = child->value();
-            if (childResult != 0.0f && result == 0.0f) {
-                result = childResult;
-            }
-        }
-        return result;
-    }
-
-    virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
-        qFatal("AnyEndpoint is read only");
-    }
-
-    // AnyEndpoint is used for reading, so return false if any child returns false (has been written to)
-    virtual bool writeable() const override { 
-        for (auto& child : _children) {
-            if (!child->writeable()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    virtual bool readable() const override { 
-        for (auto& child : _children) {
-            if (!child->readable()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-private:
-    Endpoint::List _children;
-};
-
-class InputEndpoint : public Endpoint {
-public:
-    InputEndpoint(const Input& id = Input::INVALID_INPUT)
-        : Endpoint(id) {
-    }
-
-    virtual float value() override {
-        _read = true;
-        if (isPose()) {
-            return pose().valid ? 1.0f : 0.0f;
-        }
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        auto deviceProxy = userInputMapper->getDeviceProxy(_input);
-        if (!deviceProxy) {
-            return 0.0f;
-        }
-        return deviceProxy->getValue(_input, 0);
-    }
-
-    // FIXME need support for writing back to vibration / force feedback effects
-    virtual void apply(float newValue, float oldValue, const Pointer& source) override {}
-
-    virtual Pose pose() override {
-        _read = true;
-        if (!isPose()) {
-            return Pose();
-        }
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
-        auto deviceProxy = userInputMapper->getDeviceProxy(_input);
-        if (!deviceProxy) {
-            return Pose();
-        }
-        return deviceProxy->getPose(_input, 0);
-    }
-
-    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
-
-    virtual bool writeable() const { return false; }
-    virtual bool readable() const { return !_read; }
-    virtual void reset() { _read = false; }
-
-private:
-    bool _read { false };
-};
-
-class ActionEndpoint : public Endpoint {
-public:
-    ActionEndpoint(const Input& id = Input::INVALID_INPUT)
-        : Endpoint(id) {
-    }
-
-    virtual float value() override { return _currentValue; }
-    virtual void apply(float newValue, float oldValue, const Pointer& source) override {
-        _currentValue += newValue;
-        if (_input != Input::INVALID_INPUT) {
-            auto userInputMapper = DependencyManager::get<UserInputMapper>();
-            userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
-        }
-    }
-
-    virtual Pose pose() override { return _currentPose; }
-    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
-        _currentPose = newValue;
-        if (!_currentPose.isValid()) {
-            return;
-        }
-        if (_input != Input::INVALID_INPUT) {
-            auto userInputMapper = DependencyManager::get<UserInputMapper>();
-            userInputMapper->setActionState(Action(_input.getChannel()), _currentPose);
-        }
-    }
-
-    virtual void reset() override {
-        _currentValue = 0.0f;
-        _currentPose = Pose();
-    }
-
-private:
-    float _currentValue{ 0.0f };
-    Pose _currentPose{};
-};
-
 UserInputMapper::~UserInputMapper() {
 }
 
@@ -1019,33 +738,6 @@ Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) {
     return result;
 }
 
-class AndConditional : public Conditional {
-public:
-    using Pointer = std::shared_ptr<AndConditional>;
-
-    AndConditional(Conditional::List children) : _children(children) { }
-
-    virtual bool satisfied() override {
-        for (auto& conditional : _children) {
-            if (!conditional->satisfied()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-private:
-    Conditional::List _children;
-};
-
-class EndpointConditional : public Conditional {
-public:
-    EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
-    virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
-private:
-    Endpoint::Pointer _endpoint;
-};
-
 Conditional::Pointer UserInputMapper::parseConditional(const QJsonValue& value) {
     if (value.isArray()) {
         // Support "when" : [ "GamePad.RB", "GamePad.LB" ]
@@ -1290,4 +982,3 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
 
 }
 
-#include "UserInputMapper.moc"
diff --git a/libraries/controllers/src/controllers/Conditional.cpp b/libraries/controllers/src/controllers/impl/Conditional.cpp
similarity index 100%
rename from libraries/controllers/src/controllers/Conditional.cpp
rename to libraries/controllers/src/controllers/impl/Conditional.cpp
diff --git a/libraries/controllers/src/controllers/Conditional.h b/libraries/controllers/src/controllers/impl/Conditional.h
similarity index 100%
rename from libraries/controllers/src/controllers/Conditional.h
rename to libraries/controllers/src/controllers/impl/Conditional.h
diff --git a/libraries/controllers/src/controllers/Endpoint.cpp b/libraries/controllers/src/controllers/impl/Endpoint.cpp
similarity index 100%
rename from libraries/controllers/src/controllers/Endpoint.cpp
rename to libraries/controllers/src/controllers/impl/Endpoint.cpp
diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/impl/Endpoint.h
similarity index 98%
rename from libraries/controllers/src/controllers/Endpoint.h
rename to libraries/controllers/src/controllers/impl/Endpoint.h
index 7a94b06e7e..f5fe058d82 100644
--- a/libraries/controllers/src/controllers/Endpoint.h
+++ b/libraries/controllers/src/controllers/impl/Endpoint.h
@@ -16,8 +16,8 @@
 
 #include <QtCore/QObject>
 
-#include "Input.h"
-#include "Pose.h"
+#include "../Input.h"
+#include "../Pose.h"
 
 class QScriptValue;
 
diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/impl/Filter.cpp
similarity index 100%
rename from libraries/controllers/src/controllers/Filter.cpp
rename to libraries/controllers/src/controllers/impl/Filter.cpp
diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/impl/Filter.h
similarity index 100%
rename from libraries/controllers/src/controllers/Filter.h
rename to libraries/controllers/src/controllers/impl/Filter.h
diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/impl/Mapping.cpp
similarity index 100%
rename from libraries/controllers/src/controllers/Mapping.cpp
rename to libraries/controllers/src/controllers/impl/Mapping.cpp
diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/impl/Mapping.h
similarity index 100%
rename from libraries/controllers/src/controllers/Mapping.h
rename to libraries/controllers/src/controllers/impl/Mapping.h
diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
index 93aa022647..ac9a5a300d 100644
--- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h
@@ -12,8 +12,8 @@
 #include <QtCore/QObject>
 #include <QtCore/QString>
 
-#include "../Mapping.h"
-#include "../Endpoint.h"
+#include "Mapping.h"
+#include "Endpoint.h"
 
 class QJSValue;
 class QScriptValue;
diff --git a/libraries/controllers/src/controllers/Route.cpp b/libraries/controllers/src/controllers/impl/Route.cpp
similarity index 100%
rename from libraries/controllers/src/controllers/Route.cpp
rename to libraries/controllers/src/controllers/impl/Route.cpp
diff --git a/libraries/controllers/src/controllers/Route.h b/libraries/controllers/src/controllers/impl/Route.h
similarity index 100%
rename from libraries/controllers/src/controllers/Route.h
rename to libraries/controllers/src/controllers/impl/Route.h
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 0484c5890d..2303f6184f 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -11,10 +11,12 @@
 
 #include <QtCore/QObject>
 
-#include "../Filter.h"
-#include "../Route.h"
-#include "../Mapping.h"
+#include "Filter.h"
+#include "Route.h"
+#include "Mapping.h"
+
 #include "../UserInputMapper.h"
+
 class QJSValue;
 class QScriptValue;
 class QJsonValue;
diff --git a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.cpp
new file mode 100644
index 0000000000..1633f9a439
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.cpp
@@ -0,0 +1,20 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "AndConditional.h"
+
+using namespace controller;
+
+bool AndConditional::satisfied() {
+   for (auto& conditional : _children) {
+       if (!conditional->satisfied()) {
+           return false;
+       }
+   }
+   return true;
+}
diff --git a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h
new file mode 100644
index 0000000000..5fc8b7df2a
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h
@@ -0,0 +1,32 @@
+//
+//  Created by Bradley Austin Davis 2015/10/20
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_AndConditional_h
+#define hifi_Controllers_AndConditional_h
+
+#include "../Conditional.h"
+
+namespace controller {
+
+class AndConditional : public Conditional {
+public:
+    using Pointer = std::shared_ptr<AndConditional>;
+
+    AndConditional(Conditional::List children) : _children(children) { }
+
+    virtual bool satisfied() override;
+
+private:
+    Conditional::List _children;
+};
+
+}
+
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp
new file mode 100644
index 0000000000..03e16b8cf9
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "EndpointConditional.h"
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
new file mode 100644
index 0000000000..1e4205afc7
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
@@ -0,0 +1,27 @@
+//
+//  Created by Bradley Austin Davis 2015/10/20
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_EndpointConditional_h
+#define hifi_Controllers_EndpointConditional_h
+
+#include "../Conditional.h"
+#include "../Endpoint.h"
+
+namespace controller {
+
+class EndpointConditional : public Conditional {
+public:
+    EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
+    virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
+private:
+    Endpoint::Pointer _endpoint;
+};
+
+}
+#endif
diff --git a/libraries/controllers/src/controllers/impl/conditionals/NotConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.cpp
new file mode 100644
index 0000000000..0c8d602b9e
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "NotConditional.h"
diff --git a/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h
new file mode 100644
index 0000000000..3acda07106
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h
@@ -0,0 +1,16 @@
+//
+//  Created by Bradley Austin Davis 2015/10/20
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_NotConditional_h
+#define hifi_Controllers_NotConditional_h
+
+#include "../Conditional.h"
+
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp
new file mode 100644
index 0000000000..277b63ed11
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp
@@ -0,0 +1,27 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "ScriptConditional.h"
+
+#include <QtCore/QThread>
+
+using namespace controller;
+
+bool ScriptConditional::satisfied() {
+    updateValue();
+    return _lastValue;
+}
+
+void ScriptConditional::updateValue() {
+    if (QThread::currentThread() != thread()) {
+        QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
+        return;
+    }
+
+    _lastValue = _callable.call().toBool();
+}
diff --git a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h
new file mode 100644
index 0000000000..800692d02c
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h
@@ -0,0 +1,34 @@
+//
+//  Created by Bradley Austin Davis 2015/10/20
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_ScriptConditional_h
+#define hifi_Controllers_ScriptConditional_h
+
+#include <QtCore/QObject>
+
+#include <QtScript/QScriptValue>
+
+#include "../Conditional.h"
+
+namespace controller {
+
+class ScriptConditional : public QObject, public Conditional {
+    Q_OBJECT;
+public:
+    ScriptConditional(const QScriptValue& callable) : _callable(callable) { }
+    virtual bool satisfied() override;
+protected:
+    Q_INVOKABLE void updateValue();
+private:
+    QScriptValue _callable;
+    bool _lastValue { false };
+};
+
+}
+#endif
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp
new file mode 100644
index 0000000000..d07ef38185
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp
@@ -0,0 +1,40 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "ActionEndpoint.h"
+
+#include <DependencyManager.h>
+
+#include "../../UserInputMapper.h"
+
+using namespace controller;
+
+void ActionEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
+    _currentValue += newValue;
+    if (_input != Input::INVALID_INPUT) {
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
+    }
+}
+
+void ActionEndpoint::apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) {
+    _currentPose = newValue;
+    if (!_currentPose.isValid()) {
+        return;
+    }
+    if (_input != Input::INVALID_INPUT) {
+        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+        userInputMapper->setActionState(Action(_input.getChannel()), _currentPose);
+    }
+}
+
+void ActionEndpoint::reset() {
+    _currentValue = 0.0f;
+    _currentPose = Pose();
+}
+
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h
new file mode 100644
index 0000000000..eaae1e3798
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h
@@ -0,0 +1,41 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_ActionEndpoint_h
+#define hifi_Controllers_ActionEndpoint_h
+
+#include "../Endpoint.h"
+
+#include "../../Actions.h"
+#include <DependencyManager.h>
+
+#include "../../UserInputMapper.h"
+
+namespace controller {
+
+class ActionEndpoint : public Endpoint {
+public:
+    ActionEndpoint(const Input& id = Input::INVALID_INPUT) : Endpoint(id) { }
+
+    virtual float value() override { return _currentValue; }
+    virtual void apply(float newValue, float oldValue, const Pointer& source) override;
+
+    virtual Pose pose() override { return _currentPose; }
+    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override;
+
+    virtual void reset() override;
+
+private:
+    float _currentValue{ 0.0f };
+    Pose _currentPose{};
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
new file mode 100644
index 0000000000..b3310e4424
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
@@ -0,0 +1,63 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "AnyEndpoint.h"
+
+#include "../../UserInputMapper.h"
+
+using namespace controller;
+
+AnyEndpoint::AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPUT), _children(children) {
+    bool standard = true;
+    // Ensure if we're building a composite of standard devices the composite itself
+    // is treated as a standard device for rule processing order
+    for (auto endpoint : children) {
+        if (endpoint->getInput().device != UserInputMapper::STANDARD_DEVICE) {
+            standard = false;
+            break;
+        }
+    }
+    if (standard) {
+        this->_input.device = UserInputMapper::STANDARD_DEVICE;
+    }
+}
+
+float AnyEndpoint::value() {
+    float result = 0;
+    for (auto& child : _children) {
+        float childResult = child->value();
+        if (childResult != 0.0f) {
+            result = childResult;
+        }
+    }
+    return result;
+}
+
+void AnyEndpoint::apply(float newValue, float oldValue, const Endpoint::Pointer& source) {
+    qFatal("AnyEndpoint is read only");
+}
+
+// AnyEndpoint is used for reading, so return false if any child returns false (has been written to)
+bool AnyEndpoint::writeable() const {
+    for (auto& child : _children) {
+        if (!child->writeable()) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool AnyEndpoint::readable() const {
+    for (auto& child : _children) {
+        if (!child->readable()) {
+            return false;
+        }
+    }
+    return true;
+}
+
diff --git a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
new file mode 100644
index 0000000000..25db6a5a2a
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
@@ -0,0 +1,32 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_AnyEndpoint_h
+#define hifi_Controllers_AnyEndpoint_h
+
+#include "../Endpoint.h"
+
+namespace controller {
+
+class AnyEndpoint : public Endpoint {
+    friend class UserInputMapper;
+public:
+    AnyEndpoint(Endpoint::List children);
+    virtual float value() override;
+    virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override;
+    virtual bool writeable() const override;
+    virtual bool readable() const override;
+
+private:
+    Endpoint::List _children;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp
new file mode 100644
index 0000000000..c083a7147d
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "ArrayEndpoint.h"
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
new file mode 100644
index 0000000000..676f43868a
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
@@ -0,0 +1,43 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_ArrayEndpoint_h
+#define hifi_Controllers_ArrayEndpoint_h
+
+#include "../Endpoint.h"
+
+namespace controller {
+
+class ArrayEndpoint : public Endpoint {
+    friend class UserInputMapper;
+public:
+    using Pointer = std::shared_ptr<ArrayEndpoint>;
+    ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
+
+    virtual float value() override {
+        return 0.0;
+    }
+
+    virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
+        for (auto& child : _children) {
+            if (child->writeable()) {
+                child->apply(newValue, oldValue, source);
+            }
+        }
+    }
+
+    virtual bool readable() const override { return false; }
+
+private:
+    Endpoint::List _children;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
new file mode 100644
index 0000000000..9d89a7d2b3
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
@@ -0,0 +1,32 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "CompositeEndpoint.h"
+
+#include "../../UserInputMapper.h"
+
+namespace controller {
+
+CompositeEndpoint::CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
+    : Endpoint(Input::INVALID_INPUT), Pair(first, second) {
+    if (first->getInput().device == UserInputMapper::STANDARD_DEVICE &&
+        second->getInput().device == UserInputMapper::STANDARD_DEVICE) {
+        this->_input.device = UserInputMapper::STANDARD_DEVICE;
+    }
+}
+
+float CompositeEndpoint::value() {
+    float result = first->value() * -1.0f + second->value();
+    return result;
+}
+
+void CompositeEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
+    // Composites are read only
+}
+
+}
diff --git a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
new file mode 100644
index 0000000000..b525a2e4ab
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
@@ -0,0 +1,26 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_CompositeEndpoint_h
+#define hifi_Controllers_CompositeEndpoint_h
+
+#include "../Endpoint.h"
+
+namespace controller {
+    class CompositeEndpoint : public Endpoint, Endpoint::Pair {
+    public:
+        CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second);
+
+        virtual float value() override;
+        virtual void apply(float newValue, float oldValue, const Pointer& source) override;
+    };
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp
new file mode 100644
index 0000000000..32cd5b65e0
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp
@@ -0,0 +1,41 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "InputEndpoint.h"
+
+#include <DependencyManager.h>
+
+#include "../../UserInputMapper.h"
+
+using namespace controller;
+float InputEndpoint::value(){
+    _read = true;
+    if (isPose()) {
+        return pose().valid ? 1.0f : 0.0f;
+    }
+    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    auto deviceProxy = userInputMapper->getDeviceProxy(_input);
+    if (!deviceProxy) {
+        return 0.0f;
+    }
+    return deviceProxy->getValue(_input, 0);
+}
+
+Pose InputEndpoint::pose() {
+    _read = true;
+    if (!isPose()) {
+        return Pose();
+    }
+    auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    auto deviceProxy = userInputMapper->getDeviceProxy(_input);
+    if (!deviceProxy) {
+        return Pose();
+    }
+    return deviceProxy->getPose(_input, 0);
+}
+
diff --git a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h
new file mode 100644
index 0000000000..195cd33683
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h
@@ -0,0 +1,39 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_InputEndpoint_h
+#define hifi_Controllers_InputEndpoint_h
+
+#include "../Endpoint.h"
+
+namespace controller {
+
+class InputEndpoint : public Endpoint {
+public:
+    InputEndpoint(const Input& id = Input::INVALID_INPUT)
+        : Endpoint(id) {
+    }
+
+    virtual float value() override;
+    // FIXME need support for writing back to vibration / force feedback effects
+    virtual void apply(float newValue, float oldValue, const Pointer& source) override {}
+    virtual Pose pose() override;
+    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
+
+    virtual bool writeable() const { return false; }
+    virtual bool readable() const { return !_read; }
+    virtual void reset() { _read = false; }
+
+private:
+    bool _read { false };
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp
new file mode 100644
index 0000000000..4560741d12
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "JSEndpoint.h"
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
new file mode 100644
index 0000000000..38ac92bfb6
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
@@ -0,0 +1,41 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_JSEndpoint_h
+#define hifi_Controllers_JSEndpoint_h
+
+#include "../Endpoint.h"
+
+#include <QtQml/QJSValue>
+#include <QtQml/QJSValueList>
+
+namespace controller {
+
+class JSEndpoint : public Endpoint {
+public:
+    JSEndpoint(const QJSValue& callable)
+        : Endpoint(Input::INVALID_INPUT), _callable(callable) {
+    }
+
+    virtual float value() {
+        float result = (float)_callable.call().toNumber();
+        return result;
+    }
+
+    virtual void apply(float newValue, float oldValue, const Pointer& source) {
+        _callable.call(QJSValueList({ QJSValue(newValue) }));
+    }
+
+private:
+    QJSValue _callable;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
new file mode 100644
index 0000000000..3dedcef4e4
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
@@ -0,0 +1,43 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "ScriptEndpoint.h"
+
+#include <QtCore/QThread>
+
+using namespace controller;
+
+float ScriptEndpoint::value() {
+    updateValue();
+    return _lastValue;
+}
+
+void ScriptEndpoint::updateValue() {
+    if (QThread::currentThread() != thread()) {
+        QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
+        return;
+    }
+
+    _lastValue = (float)_callable.call().toNumber();
+}
+
+void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
+    internalApply(newValue, oldValue, source->getInput().getID());
+}
+
+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) }));
+}
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
new file mode 100644
index 0000000000..e3c7abe812
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
@@ -0,0 +1,39 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_ScriptEndpoint_h
+#define hifi_Controllers_ScriptEndpoint_h
+
+#include <QtScript/QScriptValue>
+
+#include "../Endpoint.h"
+
+namespace controller {
+
+class ScriptEndpoint : public Endpoint {
+    Q_OBJECT;
+public:
+    ScriptEndpoint(const QScriptValue& callable)
+        : Endpoint(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;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp
new file mode 100644
index 0000000000..09920d249c
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "StandardEndpoint.h"
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h
new file mode 100644
index 0000000000..44803a22fd
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h
@@ -0,0 +1,60 @@
+//
+//  Created by Bradley Austin Davis 2015/10/23
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_StandardEndpoint_h
+#define hifi_Controllers_StandardEndpoint_h
+
+#include "../Endpoint.h"
+
+namespace controller {
+
+class StandardEndpoint : public VirtualEndpoint {
+public:
+    StandardEndpoint(const Input& input) : VirtualEndpoint(input) {}
+    virtual bool writeable() const override { return !_written; }
+    virtual bool readable() const override { return !_read; }
+    virtual void reset() override {
+        apply(0.0f, 0.0f, Endpoint::Pointer());
+        apply(Pose(), Pose(), Endpoint::Pointer());
+        _written = _read = false;
+    }
+
+    virtual float value() override {
+        _read = true;
+        return VirtualEndpoint::value();
+    }
+
+    virtual void apply(float newValue, float oldValue, const Pointer& source) override {
+        // For standard endpoints, the first NON-ZERO write counts.
+        if (newValue != 0.0) {
+            _written = true;
+        }
+        VirtualEndpoint::apply(newValue, oldValue, source);
+    }
+
+    virtual Pose pose() override {
+        _read = true;
+        return VirtualEndpoint::pose();
+    }
+
+    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
+        if (newValue != Pose()) {
+            _written = true;
+        }
+        VirtualEndpoint::apply(newValue, oldValue, source);
+    }
+
+private:
+    bool _written { false };
+    bool _read { false };
+};
+
+}
+
+#endif

From d5425ac625b27bafdb01e6a9853756e80cd95856 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 23 Oct 2015 13:28:36 -0700
Subject: [PATCH 145/301] Moving conditionals and endpoints out of
 UserInputMapper

Conflicts:
	libraries/controllers/src/controllers/UserInputMapper.cpp
---
 .../src/controllers/impl/conditionals/AndConditional.cpp         | 1 +
 .../src/controllers/impl/conditionals/AndConditional.h           | 1 -
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.cpp
index 1633f9a439..772d4f1314 100644
--- a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.cpp
+++ b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.cpp
@@ -18,3 +18,4 @@ bool AndConditional::satisfied() {
    }
    return true;
 }
+
diff --git a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h
index 5fc8b7df2a..c60e4b15df 100644
--- a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h
+++ b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h
@@ -28,5 +28,4 @@ private:
 
 }
 
-
 #endif

From 4e6f64833fa2cb6fcffdb2705e77d82007231274 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 23 Oct 2015 11:25:06 -0700
Subject: [PATCH 146/301] Conditional support from JS

---
 examples/tests/controllerInterfaceTest.js     |  2 +
 .../src/controllers/UserInputMapper.cpp       | 43 ++++++++++++++++++-
 .../src/controllers/UserInputMapper.h         |  4 ++
 .../src/controllers/impl/Conditional.h        |  1 +
 .../controllers/impl/RouteBuilderProxy.cpp    | 12 +++++-
 .../src/controllers/impl/RouteBuilderProxy.h  |  3 ++
 6 files changed, 62 insertions(+), 3 deletions(-)

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<AndConditional>(children);
+    }
+
+    if (condition.isNumber()) {
+        return conditionalFor(Input(condition.toInt32()));
+    }
+
+    if (condition.isFunction()) {
+        return std::make_shared<ScriptConditional>(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<EndpointConditional>(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<Conditional>;
         using List = std::list<Pointer>;
         using Factory = hifi::SimpleFactory<Conditional, QString>;
+        using Lambda = std::function<bool()>;
 
         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;

From 0959c981324e315d1e46d0a6967ae38176626e62 Mon Sep 17 00:00:00 2001
From: EdgarPironti <pacepiro@hotmail.it>
Date: Fri, 23 Oct 2015 17:26:44 -0700
Subject: [PATCH 147/301] Fixed tab

---
 examples/controllers/hydra/toyball.js | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/examples/controllers/hydra/toyball.js b/examples/controllers/hydra/toyball.js
index c3374ffb5f..10f8a82ec9 100644
--- a/examples/controllers/hydra/toyball.js
+++ b/examples/controllers/hydra/toyball.js
@@ -69,31 +69,31 @@ function checkControllerSide(whichSide) {
     var linearVelocity;
     var angularVelocity; 
     var AVERAGE_FACTOR = 0.33;
-	var grabButtonPressed;
+    var grabButtonPressed;
 	
     if (whichSide == LEFT_PALM) {
-		palmPosition = MyAvatar.leftHandPose.translation;
+        palmPosition = MyAvatar.leftHandPose.translation;
         palmRotation = MyAvatar.leftHandPose.rotation;
         ballAlreadyInHand = leftBallAlreadyInHand;
         handMessage = "LEFT";
-       averageLinearVelocity[0] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, MyAvatar.leftHandTipPose.velocity), 
+        averageLinearVelocity[0] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, MyAvatar.leftHandTipPose.velocity), 
                                             Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[0]));
 
-	   linearVelocity = averageLinearVelocity[0];
-       angularVelocity = MyAvatar.leftHandTipPose.angularVelocity;
-	   grabButtonPressed = (Controller.getValue(Controller.Standard.LT) > 0.5);
+        linearVelocity = averageLinearVelocity[0];
+        angularVelocity = MyAvatar.leftHandTipPose.angularVelocity;
+        grabButtonPressed = (Controller.getValue(Controller.Standard.LT) > 0.5);
     
     } else {
-		palmPosition = MyAvatar.rightHandPose.translation;
+        palmPosition = MyAvatar.rightHandPose.translation;
         palmRotation = MyAvatar.rightHandPose.rotation;
-		ballAlreadyInHand = rightBallAlreadyInHand;
-		 averageLinearVelocity[1] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, MyAvatar.rightHandTipPose.velocity), 
+        ballAlreadyInHand = rightBallAlreadyInHand;
+        averageLinearVelocity[1] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, MyAvatar.rightHandTipPose.velocity), 
                                             Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[1]));
  
-		linearVelocity = averageLinearVelocity[1];
-		angularVelocity = MyAvatar.rightHandTipPose.angularVelocity;
+        linearVelocity = averageLinearVelocity[1];
+        angularVelocity = MyAvatar.rightHandTipPose.angularVelocity;
         handMessage = "RIGHT";
-		grabButtonPressed = (Controller.getValue(Controller.Standard.RT) > 0.5);
+        grabButtonPressed = (Controller.getValue(Controller.Standard.RT) > 0.5);
     
     }
 

From 9aaef9aabd0034670c15539b45bdfaab0277b93f Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 17:32:06 -0700
Subject: [PATCH 148/301] fix hydraPaint.js to use new API

---
 examples/example/painting/hydraPaint.js | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/examples/example/painting/hydraPaint.js b/examples/example/painting/hydraPaint.js
index 29a3323e72..36137945cc 100644
--- a/examples/example/painting/hydraPaint.js
+++ b/examples/example/painting/hydraPaint.js
@@ -71,10 +71,8 @@ function controller(side, cycleColorButton) {
     this.triggerHeld = false;
     this.triggerThreshold = 0.9;
     this.side = side;
-    this.palm = 2 * side;
-    this.tip = 2 * side + 1;
-    this.trigger = side;
-    this.cycleColorButton = cycleColorButton;
+    this.trigger = side == LEFT ? Controller.Stantard.LT : Controller.Standard.RT;
+    this.cycleColorButton = side == LEFT ? Controller.Stantard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb;
 
     this.points = [];
     this.normals = [];
@@ -173,11 +171,10 @@ function controller(side, cycleColorButton) {
 
 
     this.updateControllerState = function() {
-        this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton);
-        this.palmPosition = Controller.getSpatialControlPosition(this.palm);
-        this.tipPosition = Controller.getSpatialControlPosition(this.tip);
-        this.palmNormal = Controller.getSpatialControlNormal(this.palm);
-        this.triggerValue = Controller.getTriggerValue(this.trigger);
+        this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton);
+        this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation;
+        this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation;
+        this.triggerValue = Controller.getValue(this.trigger);
 
         
         if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) {
@@ -215,8 +212,8 @@ function vectorIsZero(v) {
 }
 
 
-var rightController = new controller(RIGHT, RIGHT_BUTTON_4);
-var leftController = new controller(LEFT, LEFT_BUTTON_4);
+var rightController = new controller(RIGHT);
+var leftController = new controller(LEFT);
 Script.update.connect(update);
 Script.scriptEnding.connect(scriptEnding);
 

From be843a0035d820fbe7527ca7119acc60ba5682ac Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 23 Oct 2015 17:32:54 -0700
Subject: [PATCH 149/301] adding a rnning average on the velocity values
 returned by the hydra and adding a simple js to test

---
 examples/controllers/handPosesDebug.js        | 102 ++++++++++++++++++
 .../src/input-plugins/SixenseManager.h        |   2 +-
 2 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 examples/controllers/handPosesDebug.js

diff --git a/examples/controllers/handPosesDebug.js b/examples/controllers/handPosesDebug.js
new file mode 100644
index 0000000000..c4e7352445
--- /dev/null
+++ b/examples/controllers/handPosesDebug.js
@@ -0,0 +1,102 @@
+//
+//  handPosesDebug.js
+//  examples
+//
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+
+
+function makeSphere(color) {
+	var SPHERE_SIZE = 0.05;
+	var sphere = Overlays.addOverlay("sphere", {
+	    position: { x: 0, y: 0, z: 0 },
+	    size: SPHERE_SIZE,
+	    color: color,
+	    alpha: 1.0,
+	    solid: true,
+	    visible: true,
+	});
+
+	return sphere;
+}
+
+
+var NUM_HANDS = 2;
+var NUM_SPHERES_PER_HAND = 2;
+var LEFT_HAND = 0;
+var RIGHT_HAND = 1;
+
+var COLORS = [ { red: 255, green: 0, blue: 0 }, { red: 0, green: 0, blue: 255 } ];
+
+function index(handNum, indexNum) {
+	return handNum * NUM_HANDS + indexNum;
+}
+
+var app = {};
+
+
+function setup() {
+	app.spheres = new Array();
+
+	for (var h = 0; h < NUM_HANDS; h++) {
+		for (var s = 0; s < NUM_SPHERES_PER_HAND; s++) {
+			var i = index(h, s);
+			app.spheres[i] = makeSphere(COLORS[h]);
+			print("Added Sphere num " + i + " = " + JSON.stringify(app.spheres[i]));
+		}
+	}
+}
+
+function updateHand(handNum) {
+
+	var pose;
+	var handName = "right";
+	if (handNum == LEFT_HAND) {
+		pose = MyAvatar.getLeftHandPose();
+		handName = "left";
+	} else {
+		pose = MyAvatar.getRightHandPose();
+		handName = "right";
+	}
+
+	if (pose.valid) {
+		//print(handName + " hand moving" +  JSON.stringify(pose));
+		Overlays.editOverlay(app.spheres[index(handNum, 0)], {
+	        position: pose.translation,
+	        visible: true,
+	    });
+	   	var vpos = Vec3.sum(pose.velocity, pose.translation);
+	    Overlays.editOverlay(app.spheres[index(handNum, 1)], {
+	        position: vpos,
+	        visible: true,
+	    });
+	} else {
+		Overlays.editOverlay(app.spheres[index(handNum, 0)], {
+	        visible: false
+	    });
+
+	    Overlays.editOverlay(app.spheres[index(handNum, 1)], {
+	        visible: false
+	    });
+	}
+}
+
+function update() {
+	updateHand(LEFT_HAND);
+	updateHand(RIGHT_HAND);
+}
+
+function scriptEnding() {
+	print("Removing spheres = " + JSON.stringify(app.spheres));
+	for (var i = 0; i < app.spheres.length; i++) {
+		Overlays.deleteOverlay(app.spheres[i]);
+	}
+}
+
+setup();
+Script.update.connect(update);
+Script.scriptEnding.connect(scriptEnding);
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index c0d908ed45..3bc82b365b 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -121,7 +121,7 @@ private:
         }
     };
 
-    static const int MAX_NUM_AVERAGING_SAMPLES = 10; // At ~100 updates per seconds this means averaging over ~.1s
+    static const int MAX_NUM_AVERAGING_SAMPLES = 1000; // At ~100 updates per seconds this means averaging over ~.1s
     using MovingAverageMap = std::map< int, MovingAverage< glm::vec3, MAX_NUM_AVERAGING_SAMPLES> >;
     MovingAverageMap _collectedSamples;
     

From 060f87d14a58e16cd0039863edc90e57837b8bfb Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 17:33:45 -0700
Subject: [PATCH 150/301] CR feedback

---
 examples/controllers/handControllerGrab.js | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index a61f52117b..29d6595c3a 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -867,10 +867,12 @@ function MyController(hand, triggerAction) {
 var rightController = new MyController(RIGHT_HAND, Controller.Standard.RT);
 var leftController = new MyController(LEFT_HAND, Controller.Standard.LT);
 
-var mapping = Controller.newMapping("com.highfidelity.handControllerGrab");
+var MAPPING_NAME = "com.highfidelity.handControllerGrab";
+
+var mapping = Controller.newMapping(MAPPING_NAME);
 mapping.from([Controller.Standard.RB, Controller.Standard.RT]).to(rightController.eitherTrigger);
 mapping.from([Controller.Standard.LB, Controller.Standard.LT]).to(leftController.eitherTrigger);
-Controller.enableMapping("com.highfidelity.handControllerGrab");
+Controller.enableMapping(MAPPING_NAME);
 
 
 function update() {
@@ -881,7 +883,7 @@ function update() {
 function cleanup() {
     rightController.cleanup();
     leftController.cleanup();
-    Controller.disableMapping("com.highfidelity.handControllerGrab");
+    Controller.disableMapping(MAPPING_NAME);
 }
 
 Script.scriptEnding.connect(cleanup);

From 4a19a1468262608d8a871c2f08574eaca0b3a2ec Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 23 Oct 2015 17:53:34 -0700
Subject: [PATCH 151/301] fix walkApi.js to detect hydra in official way

---
 examples/libraries/walkApi.js | 20 ++------------------
 1 file changed, 2 insertions(+), 18 deletions(-)

diff --git a/examples/libraries/walkApi.js b/examples/libraries/walkApi.js
index 2a4471bfbf..8935380150 100644
--- a/examples/libraries/walkApi.js
+++ b/examples/libraries/walkApi.js
@@ -18,24 +18,8 @@ Script.include("./libraries/walkConstants.js");
 
 Avatar = function() {
     // if Hydras are connected, the only way to enable use is to never set any arm joint rotation
-    this.hydraCheck = function() {
-        // function courtesy of Thijs Wenker (frisbee.js)
-        var numberOfButtons = Controller.getNumberOfButtons();
-        var numberOfTriggers = Controller.getNumberOfTriggers();
-        var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
-        const HYDRA_BUTTONS = 12;
-        const HYDRA_TRIGGERS = 2;
-        const HYDRA_CONTROLLERS_PER_TRIGGER = 2;
-        var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
-        if (numberOfButtons == HYDRA_BUTTONS &&
-            numberOfTriggers == HYDRA_TRIGGERS &&
-            controllersPerTrigger == HYDRA_CONTROLLERS_PER_TRIGGER) {
-            print('walk.js info: Razer Hydra detected. Setting arms free (not controlled by script)');
-            return true;
-        } else {
-            print('walk.js info: Razer Hydra not detected. Arms will be controlled by script.');
-            return false;
-        }
+    this.hydraCheck = function () {
+        return Controller.Hardware.Hydra !== undefined;
     }
     // settings
     this.headFree = true;

From 0d15182adbb40bc067d60b517cdc925c6d44c19f Mon Sep 17 00:00:00 2001
From: EdgarPironti <pacepiro@hotmail.it>
Date: Fri, 23 Oct 2015 18:09:43 -0700
Subject: [PATCH 152/301] Fixed sword.js

---
 examples/example/games/sword.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/examples/example/games/sword.js b/examples/example/games/sword.js
index 608fc30361..abd94b5319 100644
--- a/examples/example/games/sword.js
+++ b/examples/example/games/sword.js
@@ -238,7 +238,7 @@ var inHand = false;
 
 function isControllerActive() {
     // I don't think the hydra API provides any reliable way to know whether a particular controller is active. Ask for both.
-    controllerActive = (Vec3.length(Controller.getSpatialControlPosition(3)) > 0) || Vec3.length(Controller.getSpatialControlPosition(4)) > 0;
+    controllerActive = (Vec3.length(MyAvatar.leftHandPose.translation) > 0) || Vec3.length(MyAvatar.rightHandPose.translation) > 0;
     return controllerActive;
 }
 
@@ -312,10 +312,10 @@ function grabSword(hand) {
     }
     var handRotation;
     if (hand === "right") {
-        handRotation = MyAvatar.getRightPalmRotation();
+        handRotation = MyAvatar.rightHandPose.rotation;
 
     } else if (hand === "left") {
-        handRotation = MyAvatar.getLeftPalmRotation();
+        handRotation = MyAvatar.leftHandPose.rotation;
     }
     var swordRotation = Entities.getEntityProperties(swordID).rotation;
     var offsetRotation = Quat.multiply(Quat.inverse(handRotation), swordRotation);

From d400c694f6d821f912002173b0c4097c54d32eaa Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 23 Oct 2015 18:09:54 -0700
Subject: [PATCH 153/301] Cleaning up for release

---
 examples/controllers/handPosesDebug.js             | 11 +++++------
 .../src/input-plugins/SixenseManager.cpp           | 14 ++++++++++----
 .../src/input-plugins/SixenseManager.h             |  5 +++--
 3 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/examples/controllers/handPosesDebug.js b/examples/controllers/handPosesDebug.js
index c4e7352445..6c933b2565 100644
--- a/examples/controllers/handPosesDebug.js
+++ b/examples/controllers/handPosesDebug.js
@@ -51,8 +51,7 @@ function setup() {
 	}
 }
 
-function updateHand(handNum) {
-
+function updateHand(handNum, deltaTime) {
 	var pose;
 	var handName = "right";
 	if (handNum == LEFT_HAND) {
@@ -69,7 +68,7 @@ function updateHand(handNum) {
 	        position: pose.translation,
 	        visible: true,
 	    });
-	   	var vpos = Vec3.sum(pose.velocity, pose.translation);
+	   	var vpos = Vec3.sum(Vec3.multiply(10 * deltaTime, pose.velocity), pose.translation);
 	    Overlays.editOverlay(app.spheres[index(handNum, 1)], {
 	        position: vpos,
 	        visible: true,
@@ -85,9 +84,9 @@ function updateHand(handNum) {
 	}
 }
 
-function update() {
-	updateHand(LEFT_HAND);
-	updateHand(RIGHT_HAND);
+function update(deltaTime) {
+	updateHand(LEFT_HAND, deltaTime);
+	updateHand(RIGHT_HAND, deltaTime);
 }
 
 function scriptEnding() {
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 1f72d66019..7ce30ec26f 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -240,7 +240,8 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
         } else {
             auto hand = left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND;
             _poseStateMap[hand] = controller::Pose();
-            _collectedSamples[hand].clear();
+            _collectedSamples[hand].first.clear();
+            _collectedSamples[hand].second.clear();
         }
     }
 
@@ -467,10 +468,15 @@ void SixenseManager::handlePoseEvent(float deltaTime, glm::vec3 position, glm::q
 
         // Average
         auto& samples = _collectedSamples[hand];
-        samples.addSample(velocity);
-        velocity = samples.average;
+        samples.first.addSample(velocity);
+        velocity = samples.first.average;
+     
+        // FIXME: // Not using quaternion average yet for angular velocity because it s probably wrong but keep the MovingAverage in place
+        //samples.second.addSample(glm::vec4(angularVelocity.x, angularVelocity.y, angularVelocity.z, angularVelocity.w));
+        //angularVelocity = glm::quat(samples.second.average.w, samples.second.average.x, samples.second.average.y, samples.second.average.z);
     } else if (!prevPose.isValid()) {
-        _collectedSamples[hand].clear();
+        _collectedSamples[hand].first.clear();
+        _collectedSamples[hand].second.clear();
     }
 
     _poseStateMap[hand] = controller::Pose(position, rotation, velocity, angularVelocity);
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index 3bc82b365b..b9ca9d8479 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -121,8 +121,9 @@ private:
         }
     };
 
-    static const int MAX_NUM_AVERAGING_SAMPLES = 1000; // At ~100 updates per seconds this means averaging over ~.1s
-    using MovingAverageMap = std::map< int, MovingAverage< glm::vec3, MAX_NUM_AVERAGING_SAMPLES> >;
+    static const int MAX_NUM_AVERAGING_SAMPLES = 50; // At ~100 updates per seconds this means averaging over ~.5s
+    using Samples = std::pair<  MovingAverage< glm::vec3, MAX_NUM_AVERAGING_SAMPLES>, MovingAverage< glm::vec4, MAX_NUM_AVERAGING_SAMPLES> >;
+    using MovingAverageMap = std::map< int, Samples >;
     MovingAverageMap _collectedSamples;
     
 #ifdef __APPLE__

From 7f3f202567b4ca36037673779c6db9bd3de8647e Mon Sep 17 00:00:00 2001
From: AlessandroSigna <alesigna92@gmail.com>
Date: Fri, 23 Oct 2015 18:23:15 -0700
Subject: [PATCH 154/301] fix stick.js

---
 examples/stick.js | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/examples/stick.js b/examples/stick.js
index f581591957..6683d8dcb6 100644
--- a/examples/stick.js
+++ b/examples/stick.js
@@ -10,7 +10,7 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-var hand = "left";
+var hand = "right";
 var nullActionID = "00000000-0000-0000-0000-000000000000";
 var controllerID;
 var controllerActive;
@@ -32,7 +32,7 @@ function makeNewStick() {
             modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx",
             compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj",
             dimensions: {x: .11, y: .11, z: 1.0},
-            position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close
+            position: MyAvatar.rightHandPosition, // initial position doesn't matter, as long as it's close
             rotation: MyAvatar.orientation,
             damping: .1,
             collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav",
@@ -84,23 +84,15 @@ function mouseMoveEvent(event) {
 }
 
 
-function initControls(){
-    if (hand == "right") {
-        controllerID = 3; // right handed
-    } else {
-        controllerID = 4; // left handed
-    }
-}
-
-
 function update(deltaTime){
-    var palmPosition = Controller.getSpatialControlPosition(controllerID);
+    var handPose = (hand == "right") ? MyAvatar.rightHandPose : MyAvatar.leftHandPose;
+    var palmPosition = handPose.translation;
     controllerActive = (Vec3.length(palmPosition) > 0);
     if(!controllerActive){
         return;
     }
 
-    stickOrientation = Controller.getSpatialControlRawRotation(controllerID);
+    stickOrientation = handPose.rotation;
     var adjustment = Quat.fromPitchYawRollDegrees(180, 0, 0);
     stickOrientation = Quat.multiply(stickOrientation, adjustment);
 

From 394511ac1bb4efca011134c351af104cf4fa44ce Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 24 Oct 2015 09:50:09 -0700
Subject: [PATCH 155/301] fix frisbee.js to work with new API

---
 examples/controllers/hydra/frisbee.js | 34 +++++++++++++++------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/examples/controllers/hydra/frisbee.js b/examples/controllers/hydra/frisbee.js
index 78d8e77a90..46550d8e76 100644
--- a/examples/controllers/hydra/frisbee.js
+++ b/examples/controllers/hydra/frisbee.js
@@ -130,29 +130,38 @@ function Hand(name, palm, tip, forwardButton, button3, trigger) {
     this.trigger = trigger;
     this.holdingFrisbee = false;
     this.entity = false;
-    this.palmPosition = function() { return Controller.getSpatialControlPosition(this.palm); }
+    this.palmPosition = function () {
+        return this.palm == LEFT_PALM ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation;
+    };
+
     this.grabButtonPressed = function() { 
                                     return (
-                                            Controller.isButtonPressed(this.forwardButton)  ||
-                                            Controller.isButtonPressed(this.button3)        ||
-                                            Controller.getTriggerValue(this.trigger) > 0.5
+                                            Controller.getValue(this.forwardButton)  ||
+                                            Controller.getValue(this.button3) ||
+                                            Controller.getValue(this.trigger) > 0.5
                                             )
                                         };
-    this.holdPosition = function() { return this.palm == LEFT_PALM ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(); };
+    this.holdPosition = function () {
+        return this.palm == LEFT_PALM ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation;
+    };
+
     this.holdRotation = function() {
-        var q = Controller.getSpatialControlRawRotation(this.palm);
+        var q = (this.palm == LEFT_PALM) ? Controller.getPoseValue(Controller.Standard.leftHand).rotation
+                                         : Controller.getPoseValue(Controller.Standard.rightHand).rotation;
         q = Quat.multiply(MyAvatar.orientation, q);
         return {x: q.x, y: q.y, z: q.z, w: q.w};
     };
-    this.tipVelocity = function() { return Controller.getSpatialControlVelocity(this.tip); };
+    this.tipVelocity = function () {
+        return this.tip == LEFT_TIP ? MyAvatar.leftHandTipPose.velocity : MyAvatar.rightHandTipPose.velocity;
+    };
 }
 
 function MouseControl(button) {
     this.button = button;
 }
 
-var leftHand = new Hand("LEFT", LEFT_PALM, LEFT_TIP, LEFT_BUTTON_FWD, LEFT_BUTTON_3, 0);
-var rightHand = new Hand("RIGHT", RIGHT_PALM, RIGHT_TIP, RIGHT_BUTTON_FWD, RIGHT_BUTTON_3, 1);
+var leftHand = new Hand("LEFT", LEFT_PALM, LEFT_TIP, Controller.Standard.LB, Controller.Standard.LeftPrimaryThumb, Controller.Standard.LT);
+var rightHand = new Hand("RIGHT", RIGHT_PALM, RIGHT_TIP, Controller.Standard.RB, Controller.Standard.RightPrimaryThumb, Controller.Standard.RT);
 
 var leftMouseControl = new MouseControl("LEFT");
 var middleMouseControl = new MouseControl("MIDDLE");
@@ -302,12 +311,7 @@ function initToolBar() {
 }
 
 function hydraCheck() {
-    var numberOfButtons = Controller.getNumberOfButtons();
-    var numberOfTriggers = Controller.getNumberOfTriggers();
-    var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
-    var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
-    hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2);
-    return true;//hydrasConnected;
+    return Controller.Hardware.Hydra !== undefined;
 }
 
 function checkController(deltaTime) {

From e11b0add9a63d5497dbb30c184a18489cacb331d Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Sat, 24 Oct 2015 15:29:49 -0700
Subject: [PATCH 156/301] Update safety trampoline with correct arguments.

---
 libraries/animation/src/Rig.cpp              | 9 +++++++++
 libraries/script-engine/src/ScriptEngine.cpp | 3 ++-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 7ab39c2f34..0576a8e420 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -637,6 +637,15 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
                                   Q_ARG(QScriptValue, _stateHandlers),
                                   Q_ARG(AnimVariantMap, _animVars),
                                   Q_ARG(AnimVariantResultHandler, handleResult));
+        // It turns out that, for thread-safety reasons, ScriptEngine::callAnimationStateHandler will invoke itself if called from other
+        // than the script thread. Thus the above _could_ be replaced with an ordinary call, which will then trigger the same
+        // invokeMethod as is done explicitly above. However, the script-engine library depends on this animation library, not vice versa.
+        // We could create an AnimVariantCallingMixin class in shared, with an abstract virtual slot
+        // AnimVariantCallingMixin::callAnimationStateHandler (and move AnimVariantMap/AnimVaraintResultHandler to shared), but the
+        // call site here would look like this instead of the above:
+        //   dynamic_cast<AnimVariantCallingMixin*>(_stateHandlers.engine())->callAnimationStateHandler(_stateHandlers, _animVars, handleResult);
+        // This works (I tried it), but the result would be that we would still have same runtime type checks as the invokeMethod above
+        // (occuring within the ScriptEngine::callAnimationStateHandler invokeMethod trampoline), _plus_ another runtime check for the dynamic_cast.
     }
     QMutexLocker locker(&_stateMutex); // as we examine/copy most recently computed state, if any. (Typically an earlier invocation.)
     _animVars.copyVariantsFrom(_stateHandlersResults);
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index acfa0c027b..86eb9570d8 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -748,7 +748,8 @@ void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantM
 #endif
         QMetaObject::invokeMethod(this, "callAnimationStateHandler",
                                   Q_ARG(QScriptValue, callback),
-                                  Q_ARG(AnimVariantMap, parameters));
+                                  Q_ARG(AnimVariantMap, parameters),
+                                  Q_ARG(AnimVariantResultHandler, resultHandler));
         return;
     }
     QScriptValue javascriptParametgers = parameters.animVariantMapToScriptValue(this);

From 5bc736952a6b3fb71f4558b2cbeafb44df12f292 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sat, 24 Oct 2015 16:26:29 -0700
Subject: [PATCH 157/301] Function based endpoints should inhibit spamming with
 repeats of the same value

---
 .../src/controllers/impl/endpoints/ScriptEndpoint.cpp     | 8 ++++++--
 .../src/controllers/impl/endpoints/ScriptEndpoint.h       | 3 ++-
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
index 3dedcef4e4..069bcb3c00 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
@@ -14,7 +14,7 @@ using namespace controller;
 
 float ScriptEndpoint::value() {
     updateValue();
-    return _lastValue;
+    return _lastValueRead;
 }
 
 void ScriptEndpoint::updateValue() {
@@ -23,14 +23,18 @@ void ScriptEndpoint::updateValue() {
         return;
     }
 
-    _lastValue = (float)_callable.call().toNumber();
+    _lastValueRead = (float)_callable.call().toNumber();
 }
 
 void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
+    if (newValue == _lastValueWritten) {
+        return;
+    }
     internalApply(newValue, oldValue, source->getInput().getID());
 }
 
 void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID) {
+    _lastValueWritten = newValue;
     if (QThread::currentThread() != thread()) {
         QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
             Q_ARG(float, newValue),
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
index e3c7abe812..a56ac472be 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
@@ -31,7 +31,8 @@ protected:
     Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID);
 private:
     QScriptValue _callable;
-    float _lastValue = 0.0f;
+    float _lastValueRead { 0.0f };
+    float _lastValueWritten { 0.0f };
 };
 
 }

From 3e50174114b36f8e7bd77aaf664f1091fed78b26 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sat, 24 Oct 2015 16:26:50 -0700
Subject: [PATCH 158/301] Updating gun.js to new controller API

---
 examples/controllers/hydra/gun.js | 623 ++++++++++++++++--------------
 1 file changed, 331 insertions(+), 292 deletions(-)

diff --git a/examples/controllers/hydra/gun.js b/examples/controllers/hydra/gun.js
index a90960a330..03caf50ad7 100644
--- a/examples/controllers/hydra/gun.js
+++ b/examples/controllers/hydra/gun.js
@@ -15,24 +15,61 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
+Script.include([ "../../libraries/utils.js" ]);
+Script.include([ "../../libraries/constants.js" ]);
+Script.include([ "../../libraries/toolBars.js" ]);
+
 HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
 
-var RED = { red: 255, green: 0, blue: 0 };
 var LASER_WIDTH = 2;
+var POSE_CONTROLS = [ Controller.Standard.LeftHand, Controller.Standard.RightHand ];
+var TRIGGER_CONTROLS = [ Controller.Standard.LT, Controller.Standard.RT ];
+var MIN_THROWER_DELAY = 1000;
+var MAX_THROWER_DELAY = 1000;
+var RELOAD_INTERVAL = 5;
+var GUN_MODEL = HIFI_PUBLIC_BUCKET + "cozza13/gun/m1911-handgun+1.fbx?v=4";
+var BULLET_VELOCITY = 10.0;
+var GUN_OFFSETS = [ {
+    x: -0.04,
+    y: 0.26,
+    z: 0.04
+}, {
+    x: 0.04,
+    y: 0.26,
+    z: 0.04
+} ];
 
+var GUN_ORIENTATIONS = [ Quat.fromPitchYawRollDegrees(0, 90, 90), Quat.fromPitchYawRollDegrees(0, -90, 270) ];
+
+var BARREL_OFFSETS = [ {
+    x: -0.12,
+    y: 0.12,
+    z: 0.04
+}, {
+    x: 0.12,
+    y: 0.12,
+    z: 0.04
+} ];
+
+var mapping = Controller.newMapping();
+var validPoses = [ false, false ];
+var barrelVectors = [ 0, 0 ];
+var barrelTips = [ 0, 0 ];
 var pointer = [];
+
 pointer.push(Overlays.addOverlay("line3d", {
-    start: { x: 0, y: 0, z: 0 },
-    end: { x: 0, y: 0, z: 0 },
-    color: RED,
+    start: ZERO_VECTOR,
+    end: ZERO_VECTOR,
+    color: COLORS.RED,
     alpha: 1,
     visible: true,
     lineWidth: LASER_WIDTH
 }));
+
 pointer.push(Overlays.addOverlay("line3d", {
-    start: { x: 0, y: 0, z: 0 },
-    end: { x: 0, y: 0, z: 0 },
-    color: RED,
+    start: ZERO_VECTOR,
+    end: ZERO_VECTOR,
+    color: COLORS.RED,
     alpha: 1,
     visible: true,
     lineWidth: LASER_WIDTH
@@ -42,56 +79,27 @@ function getRandomFloat(min, max) {
     return Math.random() * (max - min) + min;
 }
 
-var lastX = 0;
-var lastY = 0;
-var yawFromMouse = 0;
-var pitchFromMouse = 0;
-var isMouseDown = false; 
-
-var MIN_THROWER_DELAY = 1000;
-var MAX_THROWER_DELAY = 1000;
-var LEFT_BUTTON_3 = 3;
-var RELOAD_INTERVAL = 5;
-
-var KICKBACK_ANGLE = 15;
-var elbowKickAngle = 0.0;
-var rotationBeforeKickback; 
-
 var showScore = false;
-
-
-// Load some sound to use for loading and firing 
+// Load some sound to use for loading and firing
 var fireSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw");
 var loadSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw");
 var impactSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletImpact2.raw");
 var targetHitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw");
 var targetLaunchSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw");
 
-var gunModel = "https://s3.amazonaws.com/hifi-public/cozza13/gun/m1911-handgun+1.fbx?v=4";
-
 var audioOptions = {
-  volume: 0.9
+    volume: 0.9
 }
 
 var shotsFired = 0;
-var shotTime = new Date(); 
-
-var activeControllers = 0; 
-
-// initialize our controller triggers
-var triggerPulled = new Array();
-var numberOfTriggers = Controller.getNumberOfTriggers();
-for (t = 0; t < numberOfTriggers; t++) {
-    triggerPulled[t] = false;
-}
-
-var isLaunchButtonPressed = false; 
-var score = 0; 
+var shotTime = new Date();
+var isLaunchButtonPressed = false;
+var score = 0;
 
 var bulletID = false;
 var targetID = false;
 
-//  Create overlay buttons and reticle 
+// Create overlay buttons and reticle
 
 var BUTTON_SIZE = 32;
 var PADDING = 3;
@@ -99,78 +107,91 @@ var NUM_BUTTONS = 3;
 
 var screenSize = Controller.getViewportDimensions();
 var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2;
-Script.include(["../../libraries/toolBars.js"]);
-var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function (screenSize) {
+
+var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function(screenSize) {
     return {
         x: startX,
         y: (screenSize.y - (BUTTON_SIZE + PADDING)),
     };
 });
-var reticle = Overlays.addOverlay("image", {
-                    x: screenSize.x / 2 - (BUTTON_SIZE / 2),
-                    y: screenSize.y / 2 - (BUTTON_SIZE / 2),
-                    width: BUTTON_SIZE,
-                    height: BUTTON_SIZE,
-                    imageURL: HIFI_PUBLIC_BUCKET + "images/gun/crosshairs.svg",
-                    alpha: 1
-                });
 
 var offButton = toolBar.addOverlay("image", {
-                    width: BUTTON_SIZE,
-                    height: BUTTON_SIZE,
-                    imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",
-                    alpha: 1
-                });
+    width: BUTTON_SIZE,
+    height: BUTTON_SIZE,
+    imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",
+    alpha: 1
+});
 
 startX += BUTTON_SIZE + PADDING;
 var platformButton = toolBar.addOverlay("image", {
-                    x: startX,
-                    y: screenSize.y - (BUTTON_SIZE + PADDING),
-                    width: BUTTON_SIZE,
-                    height: BUTTON_SIZE,
-                    imageURL: HIFI_PUBLIC_BUCKET + "images/gun/platform-targets.svg",
-                    alpha: 1
-                });
+    x: startX,
+    y: screenSize.y - (BUTTON_SIZE + PADDING),
+    width: BUTTON_SIZE,
+    height: BUTTON_SIZE,
+    imageURL: HIFI_PUBLIC_BUCKET + "images/gun/platform-targets.svg",
+    alpha: 1
+});
 
 startX += BUTTON_SIZE + PADDING;
 var gridButton = toolBar.addOverlay("image", {
-                    x: startX,
-                    y: screenSize.y - (BUTTON_SIZE + PADDING),
-                    width: BUTTON_SIZE,
-                    height: BUTTON_SIZE,
-                    imageURL: HIFI_PUBLIC_BUCKET + "images/gun/floating-targets.svg",
-                    alpha: 1
-                });
+    x: startX,
+    y: screenSize.y - (BUTTON_SIZE + PADDING),
+    width: BUTTON_SIZE,
+    height: BUTTON_SIZE,
+    imageURL: HIFI_PUBLIC_BUCKET + "images/gun/floating-targets.svg",
+    alpha: 1
+});
 
 if (showScore) {
     var text = Overlays.addOverlay("text", {
-                    x: screenSize.x / 2 - 100,
-                    y: screenSize.y / 2 - 50,
-                    width: 150,
-                    height: 50,
-                    color: { red: 0, green: 0, blue: 0},
-                    textColor: { red: 255, green: 0, blue: 0},
-                    topMargin: 4,
-                    leftMargin: 4,
-                    text: "Score: " + score
-                });
+        x: screenSize.x / 2 - 100,
+        y: screenSize.y / 2 - 50,
+        width: 150,
+        height: 50,
+        color: {
+            red: 0,
+            green: 0,
+            blue: 0
+        },
+        textColor: {
+            red: 255,
+            green: 0,
+            blue: 0
+        },
+        topMargin: 4,
+        leftMargin: 4,
+        text: "Score: " + score
+    });
 }
 
-var BULLET_VELOCITY = 10.0;
-
 function entityCollisionWithEntity(entity1, entity2, collision) {
     if (entity2 === targetID) {
         score++;
         if (showScore) {
-            Overlays.editOverlay(text, { text: "Score: " + score } );
+            Overlays.editOverlay(text, {
+                text: "Score: " + score
+            });
         }
 
-        //  We will delete the bullet and target in 1/2 sec, but for now we can see them bounce!
+        // We will delete the bullet and target in 1/2 sec, but for now we can
+        // see them bounce!
         Script.setTimeout(deleteBulletAndTarget, 500);
 
         // Turn the target and the bullet white
-        Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }});
-        Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }});
+        Entities.editEntity(entity1, {
+            color: {
+                red: 255,
+                green: 255,
+                blue: 255
+            }
+        });
+        Entities.editEntity(entity2, {
+            color: {
+                red: 255,
+                green: 255,
+                blue: 255
+            }
+        });
 
         // play the sound near the camera so the shooter can hear it
         audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
@@ -188,41 +209,45 @@ function shootBullet(position, velocity, grenade) {
 
     var bVelocity = grenade ? Vec3.multiply(GRENADE_VELOCITY, Vec3.normalize(velocity)) : velocity;
     var bSize = grenade ? GRENADE_SIZE : BULLET_SIZE;
-    var bGravity = grenade ? GRENADE_GRAVITY : BULLET_GRAVITY; 
+    var bGravity = grenade ? GRENADE_GRAVITY : BULLET_GRAVITY;
+
+    bulletID = Entities.addEntity({
+        type: "Sphere",
+        position: position,
+        dimensions: {
+            x: bSize,
+            y: bSize,
+            z: bSize
+        },
+        color: {
+            red: 0,
+            green: 0,
+            blue: 0
+        },
+        velocity: bVelocity,
+        lifetime: BULLET_LIFETIME,
+        gravity: {
+            x: 0,
+            y: bGravity,
+            z: 0
+        },
+        damping: 0.01,
+        density: 8000,
+        ignoreCollisions: false,
+        collisionsWillMove: true
+    });
 
-    bulletID = Entities.addEntity(
-        { type: "Sphere",
-          position: position, 
-          dimensions: { x: bSize, y: bSize, z: bSize }, 
-          color: {  red: 0, green: 0, blue: 0 },  
-          velocity: bVelocity, 
-          lifetime: BULLET_LIFETIME,
-          gravity: {  x: 0, y: bGravity, z: 0 },
-          damping: 0.01,
-          density: 8000,
-          ignoreCollisions: false,
-          collisionsWillMove: true
-      });
     Script.addEventHandler(bulletID, "collisionWithEntity", entityCollisionWithEntity);
 
-    // Play firing sounds 
-    audioOptions.position = position;   
+    // Play firing sounds
+    audioOptions.position = position;
     Audio.playSound(fireSound, audioOptions);
     shotsFired++;
     if ((shotsFired % RELOAD_INTERVAL) == 0) {
         Audio.playSound(loadSound, audioOptions);
     }
-
-    // Kickback the arm 
-    if (elbowKickAngle > 0.0) {
-        MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback);
-    }
-    rotationBeforeKickback = MyAvatar.getJointRotation("LeftForeArm"); 
-    var armRotation = MyAvatar.getJointRotation("LeftForeArm"); 
-    armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, KICKBACK_ANGLE));
-    MyAvatar.setJointData("LeftForeArm", armRotation);
-    elbowKickAngle = KICKBACK_ANGLE;
 }
+
 function shootTarget() {
     var TARGET_SIZE = 0.50;
     var TARGET_GRAVITY = 0.0;
@@ -232,95 +257,152 @@ function shootTarget() {
     var DISTANCE_TO_LAUNCH_FROM = 5.0;
     var ANGLE_RANGE_FOR_LAUNCH = 20.0;
     var camera = Camera.getPosition();
-    
-    var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), { x:0, y:1, z:0 });
+
+    var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), {
+        x: 0,
+        y: 1,
+        z: 0
+    });
     targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection);
     var forwardVector = Quat.getFront(targetDirection);
- 
+
     var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM));
 
     var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY);
     velocity.y += TARGET_UP_VELOCITY;
 
-    targetID = Entities.addEntity(
-        { type: "Box",
-          position: newPosition, 
-          dimensions: { x: TARGET_SIZE * (0.5 + Math.random()), y: TARGET_SIZE * (0.5 + Math.random()), z: TARGET_SIZE * (0.5 + Math.random()) / 4.0 }, 
-          color: {  red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },  
-          velocity: velocity, 
-          gravity: {  x: 0, y: TARGET_GRAVITY, z: 0 }, 
-          lifetime: TARGET_LIFETIME,
-          rotation:  Camera.getOrientation(),
-          damping: 0.1,
-          density: 100.0, 
-          collisionsWillMove: true });
+    targetID = Entities.addEntity({
+        type: "Box",
+        position: newPosition,
+        dimensions: {
+            x: TARGET_SIZE * (0.5 + Math.random()),
+            y: TARGET_SIZE * (0.5 + Math.random()),
+            z: TARGET_SIZE * (0.5 + Math.random()) / 4.0
+        },
+        color: {
+            red: Math.random() * 255,
+            green: Math.random() * 255,
+            blue: Math.random() * 255
+        },
+        velocity: velocity,
+        gravity: {
+            x: 0,
+            y: TARGET_GRAVITY,
+            z: 0
+        },
+        lifetime: TARGET_LIFETIME,
+        rotation: Camera.getOrientation(),
+        damping: 0.1,
+        density: 100.0,
+        collisionsWillMove: true
+    });
 
-    // Record start time 
+    // Record start time
     shotTime = new Date();
 
     // Play target shoot sound
-    audioOptions.position = newPosition;   
+    audioOptions.position = newPosition;
     Audio.playSound(targetLaunchSound, audioOptions);
 }
 
 function makeGrid(type, scale, size) {
-    var separation = scale * 2; 
+    var separation = scale * 2;
     var pos = Vec3.sum(Camera.getPosition(), Vec3.multiply(10.0 * scale * separation, Quat.getFront(Camera.getOrientation())));
     var x, y, z;
-    var GRID_LIFE = 60.0; 
-    var dimensions; 
+    var GRID_LIFE = 60.0;
+    var dimensions;
 
     for (x = 0; x < size; x++) {
         for (y = 0; y < size; y++) {
             for (z = 0; z < size; z++) {
-                
-                dimensions = { x: separation/2.0 * (0.5 + Math.random()), y: separation/2.0 * (0.5 + Math.random()), z: separation/2.0 * (0.5 + Math.random()) / 4.0 };
 
-                Entities.addEntity(
-                    { type: type,
-                      position: { x: pos.x + x * separation, y: pos.y + y * separation, z: pos.z + z * separation },
-                      dimensions: dimensions, 
-                      color: {  red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },  
-                      velocity: {  x: 0, y: 0, z: 0 }, 
-                      gravity: {  x: 0, y: 0, z: 0 }, 
-                      lifetime: GRID_LIFE,
-                      rotation:  Camera.getOrientation(),
-                      damping: 0.1,
-                      density: 100.0, 
-                      collisionsWillMove: true });
+                dimensions = {
+                    x: separation / 2.0 * (0.5 + Math.random()),
+                    y: separation / 2.0 * (0.5 + Math.random()),
+                    z: separation / 2.0 * (0.5 + Math.random()) / 4.0
+                };
+
+                Entities.addEntity({
+                    type: type,
+                    position: {
+                        x: pos.x + x * separation,
+                        y: pos.y + y * separation,
+                        z: pos.z + z * separation
+                    },
+                    dimensions: dimensions,
+                    color: {
+                        red: Math.random() * 255,
+                        green: Math.random() * 255,
+                        blue: Math.random() * 255
+                    },
+                    velocity: {
+                        x: 0,
+                        y: 0,
+                        z: 0
+                    },
+                    gravity: {
+                        x: 0,
+                        y: 0,
+                        z: 0
+                    },
+                    lifetime: GRID_LIFE,
+                    rotation: Camera.getOrientation(),
+                    damping: 0.1,
+                    density: 100.0,
+                    collisionsWillMove: true
+                });
             }
         }
     }
 }
 
 function makePlatform(gravity, scale, size) {
-    var separation = scale * 2; 
+    var separation = scale * 2;
     var pos = Vec3.sum(Camera.getPosition(), Vec3.multiply(10.0 * scale * separation, Quat.getFront(Camera.getOrientation())));
     pos.y -= separation * size;
     var x, y, z;
-    var TARGET_LIFE = 60.0; 
+    var TARGET_LIFE = 60.0;
     var INITIAL_GAP = 0.5;
-    var dimensions; 
+    var dimensions;
 
     for (x = 0; x < size; x++) {
         for (y = 0; y < size; y++) {
             for (z = 0; z < size; z++) {
 
-                dimensions = { x: separation/2.0, y: separation, z: separation/2.0 };
+                dimensions = {
+                    x: separation / 2.0,
+                    y: separation,
+                    z: separation / 2.0
+                };
 
-                Entities.addEntity(
-                    { type: "Box",
-                      position: { x: pos.x - (separation * size  / 2.0) + x * separation, 
-                                  y: pos.y + y * (separation + INITIAL_GAP), 
-                                  z: pos.z - (separation * size / 2.0) + z * separation },
-                      dimensions: dimensions, 
-                      color: {  red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },  
-                      velocity: {  x: 0, y: 0.05, z: 0 }, 
-                      gravity: {  x: 0, y: gravity, z: 0 }, 
-                      lifetime: TARGET_LIFE,
-                      damping: 0.1,
-                      density: 100.0, 
-                      collisionsWillMove: true });
+                Entities.addEntity({
+                    type: "Box",
+                    position: {
+                        x: pos.x - (separation * size / 2.0) + x * separation,
+                        y: pos.y + y * (separation + INITIAL_GAP),
+                        z: pos.z - (separation * size / 2.0) + z * separation
+                    },
+                    dimensions: dimensions,
+                    color: {
+                        red: Math.random() * 255,
+                        green: Math.random() * 255,
+                        blue: Math.random() * 255
+                    },
+                    velocity: {
+                        x: 0,
+                        y: 0.05,
+                        z: 0
+                    },
+                    gravity: {
+                        x: 0,
+                        y: gravity,
+                        z: 0
+                    },
+                    lifetime: TARGET_LIFE,
+                    damping: 0.1,
+                    density: 100.0,
+                    collisionsWillMove: true
+                });
             }
         }
     }
@@ -328,9 +410,21 @@ function makePlatform(gravity, scale, size) {
     // Make a floor for this stuff to fall onto
     Entities.addEntity({
         type: "Box",
-        position: { x: pos.x, y: pos.y - separation / 2.0, z: pos.z }, 
-        dimensions: { x: 2.0 * separation * size, y: separation / 2.0, z: 2.0 * separation * size },
-        color: { red: 100, green: 100, blue: 100 },
+        position: {
+            x: pos.x,
+            y: pos.y - separation / 2.0,
+            z: pos.z
+        },
+        dimensions: {
+            x: 2.0 * separation * size,
+            y: separation / 2.0,
+            z: 2.0 * separation * size
+        },
+        color: {
+            red: 100,
+            green: 100,
+            blue: 100
+        },
         lifetime: TARGET_LIFE
     });
 
@@ -340,7 +434,7 @@ function keyPressEvent(event) {
     // if our tools are off, then don't do anything
     if (event.text == "t") {
         var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
-        Script.setTimeout(shootTarget, time); 
+        Script.setTimeout(shootTarget, time);
     } else if ((event.text == ".") || (event.text == "SPACE")) {
         shootFromMouse(false);
     } else if (event.text == ",") {
@@ -348,7 +442,7 @@ function keyPressEvent(event) {
     } else if (event.text == "r") {
         playLoadSound();
     } else if (event.text == "s") {
-        //  Hit this key to dump a posture from hydra to log
+        // Hit this key to dump a posture from hydra to log
         Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm"));
         Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm"));
         Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand"));
@@ -356,137 +450,70 @@ function keyPressEvent(event) {
 }
 
 function playLoadSound() {
-    audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); 
+    audioOptions.position = MyAvatar.leftHandPose.translation;
     Audio.playSound(loadSound, audioOptions);
-    // Raise arm to firing posture 
-    takeFiringPose();
-}
-
-function clearPose() {
-    MyAvatar.clearJointData("LeftForeArm");
-    MyAvatar.clearJointData("LeftArm");
-    MyAvatar.clearJointData("LeftHand");
 }
 
 function deleteBulletAndTarget() {
     Entities.deleteEntity(bulletID);
     Entities.deleteEntity(targetID);
-    bulletID = false; 
-    targetID = false; 
+    bulletID = false;
+    targetID = false;
 }
 
-function takeFiringPose() {
-    clearPose();
-    if (Controller.getNumberOfSpatialControls() == 0) {
-        MyAvatar.setJointData("LeftForeArm", {x: -0.251919, y: -0.0415449, z: 0.499487, w: 0.827843});
-        MyAvatar.setJointData("LeftArm", { x: 0.470196, y: -0.132559, z: 0.494033, w: 0.719219});
-        MyAvatar.setJointData("LeftHand", { x: -0.0104815, y: -0.110551, z: -0.352111, w: 0.929333});
-    }
-}
-
-MyAvatar.attach(gunModel, "RightHand", {x:0.04, y: 0.22, z: 0.02}, Quat.fromPitchYawRollDegrees(-172, -85, 79), 0.40);
-MyAvatar.attach(gunModel, "LeftHand", {x:-0.04, y: 0.22, z: 0.02}, Quat.fromPitchYawRollDegrees(-172, 85, -79), 0.40);
-
-//  Give a bit of time to load before playing sound
-Script.setTimeout(playLoadSound, 2000); 
-
 function update(deltaTime) {
-    if (activeControllers == 0) {
-        if (Controller.getNumberOfSpatialControls() > 0) { 
-            activeControllers = Controller.getNumberOfSpatialControls();
-            clearPose();
-        }
-    }
+    // FIXME we should also expose MyAvatar.handPoses[2], MyAvatar.tipPoses[2]
+    var tipPoses = [ MyAvatar.leftHandTipPose, MyAvatar.rightHandTipPose ];
 
-    var KICKBACK_DECAY_RATE = 0.125;
-    if (elbowKickAngle > 0.0)  {       
-        if (elbowKickAngle > 0.5) {
-            var newAngle = elbowKickAngle * KICKBACK_DECAY_RATE;
-            elbowKickAngle -= newAngle; 
-            var armRotation = MyAvatar.getJointRotation("LeftForeArm");
-            armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, -newAngle));
-            MyAvatar.setJointData("LeftForeArm", armRotation);
-        } else {
-            MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback);
-            if (Controller.getNumberOfSpatialControls() > 0) {
-                clearPose();
-            }
-            elbowKickAngle = 0.0;
-        }
-    }
-
-
-    // check for trigger press
-
-    var numberOfTriggers = 2; 
-    var controllersPerTrigger = 2;
-
-    if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
-        for (var t = 0; t < 2; t++) {
-            var shootABullet = false;
-            var triggerValue = Controller.getTriggerValue(t);
-            if (triggerPulled[t]) {
-                // must release to at least 0.1
-                if (triggerValue < 0.1) {
-                    triggerPulled[t] = false; // unpulled
-                }
-            } else {
-                // must pull to at least 
-                if (triggerValue > 0.5) {
-                    triggerPulled[t] = true; // pulled
-                    shootABullet = true;
-                }
-            }
-            var palmController = t * controllersPerTrigger; 
-            var palmPosition = Controller.getSpatialControlPosition(palmController);
-            var fingerTipController = palmController + 1; 
-            var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
-            var laserTip = Vec3.sum(Vec3.multiply(100.0, Vec3.subtract(fingerTipPosition, palmPosition)), palmPosition);
-
-            //  Update Lasers 
-            Overlays.editOverlay(pointer[t], {
-                start: palmPosition,
-                end: laserTip,
-                alpha: 1
+    for (var side = 0; side < 2; side++) {
+        // First check if the controller is valid
+        var controllerPose = Controller.getPoseValue(POSE_CONTROLS[side]);
+        validPoses[side] = controllerPose.valid;
+        if (!controllerPose.valid) {
+            Overlays.editOverlay(pointer[side], {
+                visible: false
             });
-
-            if (shootABullet) {
-                 
-                var palmToFingerTipVector = 
-                        {   x: (fingerTipPosition.x - palmPosition.x),
-                            y: (fingerTipPosition.y - palmPosition.y),
-                            z: (fingerTipPosition.z - palmPosition.z)  };
-                                    
-                // just off the front of the finger tip
-                var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2, 
-                                 y: fingerTipPosition.y + palmToFingerTipVector.y/2, 
-                                 z: fingerTipPosition.z  + palmToFingerTipVector.z/2};   
-                   
-                var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(palmToFingerTipVector)); 
-
-                shootBullet(position, velocity, false);
-            }
+            continue;
         }
+
+        // Need to adjust the laser
+        var tipPose = tipPoses[side];
+        var handRotation = MyAvatar.getJointCombinedRotation(side == 0 ? "LeftHand" : "RightHand");
+        // handRotation = Quat.multiply(Quat.inverse(MyAvatar.orientation),
+        // handRotation);
+        var barrelOffset = Vec3.multiplyQbyV(handRotation, BARREL_OFFSETS[side]);
+        barrelTips[side] = Vec3.sum(tipPose.translation, barrelOffset);
+        barrelVectors[side] = Vec3.multiplyQbyV(handRotation, {
+            x: 0,
+            y: 1,
+            z: 0
+        });
+
+        var laserTip = Vec3.sum(Vec3.multiply(100.0, barrelVectors[side]), barrelTips[side]);
+        // Update Lasers
+        Overlays.editOverlay(pointer[side], {
+            start: barrelTips[side],
+            end: laserTip,
+            alpha: 1,
+            visible: true
+        });
     }
 }
 
-function shootFromMouse(grenade) {
-    var DISTANCE_FROM_CAMERA = 1.0;
-    var camera = Camera.getPosition();
-    var forwardVector = Quat.getFront(Camera.getOrientation());
-    var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
-    var velocity = Vec3.multiply(forwardVector, BULLET_VELOCITY);
-    shootBullet(newPosition, velocity, grenade);
-}
-
-function mouseReleaseEvent(event) { 
-    //  position 
-    isMouseDown = false;
+function triggerChanged(side, value) {
+    var pressed = (value != 0);
+    if (pressed) {
+        var position = barrelTips[side];
+        var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(barrelVectors[side]));
+        shootBullet(position, velocity, false);
+    }
 }
 
 function mousePressEvent(event) {
-    var clickedText = false;
-    var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
+    var clickedOverlay = Overlays.getOverlayAtPoint({
+        x: event.x,
+        y: event.y
+    });
     if (clickedOverlay == offButton) {
         Script.stop();
     } else if (clickedOverlay == platformButton) {
@@ -494,25 +521,37 @@ function mousePressEvent(event) {
         makePlatform(-9.8, 1.0, platformSize);
     } else if (clickedOverlay == gridButton) {
         makeGrid("Box", 1.0, 3);
-    } 
+    }
 }
 
 function scriptEnding() {
-    Overlays.deleteOverlay(reticle);
+    mapping.disable();
     toolBar.cleanup();
-    Overlays.deleteOverlay(pointer[0]);
-    Overlays.deleteOverlay(pointer[1]);
+    for (var i = 0; i < pointer.length; ++i) {
+        Overlays.deleteOverlay(pointer[i]);
+    }
     Overlays.deleteOverlay(text);
-    MyAvatar.detachOne(gunModel);
-    MyAvatar.detachOne(gunModel);
+    MyAvatar.detachOne(GUN_MODEL);
+    MyAvatar.detachOne(GUN_MODEL);
     clearPose();
 }
 
+MyAvatar.attach(GUN_MODEL, "LeftHand", GUN_OFFSETS[0], GUN_ORIENTATIONS[1], 0.40);
+MyAvatar.attach(GUN_MODEL, "RightHand", GUN_OFFSETS[1], GUN_ORIENTATIONS[1], 0.40);
+
+// Give a bit of time to load before playing sound
+Script.setTimeout(playLoadSound, 2000);
+
+mapping.from(Controller.Standard.LT).constrainToPositiveInteger().to(function(value) {
+    triggerChanged(0, value);
+});
+
+mapping.from(Controller.Standard.RT).constrainToPositiveInteger().to(function(value) {
+    triggerChanged(1, value);
+});
+mapping.enable();
+
 Script.scriptEnding.connect(scriptEnding);
 Script.update.connect(update);
-Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
 Controller.mousePressEvent.connect(mousePressEvent);
 Controller.keyPressEvent.connect(keyPressEvent);
-
-
-

From a7547ef11e5ab1e70f56511215ddc7b13a6a1e97 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 25 Oct 2015 16:44:43 -0700
Subject: [PATCH 159/301] Adding hysteresis filter, moving filters to
 individual files

---
 .../src/controllers/impl/Filter.cpp           | 226 ++++++++++++------
 .../controllers/src/controllers/impl/Filter.h | 198 +--------------
 .../controllers/impl/RouteBuilderProxy.cpp    |  52 ++--
 .../src/controllers/impl/RouteBuilderProxy.h  |   4 +-
 .../controllers/impl/filters/ClampFilter.cpp  |  38 +++
 .../controllers/impl/filters/ClampFilter.h    |  32 +++
 .../impl/filters/ConstrainToIntegerFilter.cpp |   9 +
 .../impl/filters/ConstrainToIntegerFilter.h   |  30 +++
 .../ConstrainToPositiveIntegerFilter.cpp      |   9 +
 .../ConstrainToPositiveIntegerFilter.h        |  30 +++
 .../impl/filters/DeadZoneFilter.cpp           |  26 ++
 .../controllers/impl/filters/DeadZoneFilter.h |  31 +++
 .../impl/filters/HysteresisFilter.cpp         |  57 +++++
 .../impl/filters/HysteresisFilter.h           |  31 +++
 .../controllers/impl/filters/InvertFilter.cpp |   9 +
 .../controllers/impl/filters/InvertFilter.h   |  29 +++
 .../controllers/impl/filters/PulseFilter.cpp  |  37 +++
 .../controllers/impl/filters/PulseFilter.h    |  36 +++
 .../controllers/impl/filters/ScaleFilter.cpp  |  19 ++
 .../controllers/impl/filters/ScaleFilter.h    |  34 +++
 20 files changed, 638 insertions(+), 299 deletions(-)
 create mode 100644 libraries/controllers/src/controllers/impl/filters/ClampFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/ClampFilter.h
 create mode 100644 libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h
 create mode 100644 libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h
 create mode 100644 libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h
 create mode 100644 libraries/controllers/src/controllers/impl/filters/HysteresisFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h
 create mode 100644 libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/InvertFilter.h
 create mode 100644 libraries/controllers/src/controllers/impl/filters/PulseFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/PulseFilter.h
 create mode 100644 libraries/controllers/src/controllers/impl/filters/ScaleFilter.cpp
 create mode 100644 libraries/controllers/src/controllers/impl/filters/ScaleFilter.h

diff --git a/libraries/controllers/src/controllers/impl/Filter.cpp b/libraries/controllers/src/controllers/impl/Filter.cpp
index bc31e9ea44..09188318eb 100644
--- a/libraries/controllers/src/controllers/impl/Filter.cpp
+++ b/libraries/controllers/src/controllers/impl/Filter.cpp
@@ -14,101 +14,183 @@
 #include <QtCore/QJsonObject>
 #include <QtCore/QJsonArray>
 
-#include "SharedUtil.h"
+#include <SharedUtil.h>
+
+#include "filters/ClampFilter.h"
+#include "filters/ConstrainToIntegerFilter.h"
+#include "filters/ConstrainToPositiveIntegerFilter.h"
+#include "filters/DeadZoneFilter.h"
+#include "filters/HysteresisFilter.h"
+#include "filters/InvertFilter.h"
+#include "filters/PulseFilter.h"
+#include "filters/ScaleFilter.h"
 
 using namespace controller;
 
 Filter::Factory Filter::_factory;
 
-REGISTER_FILTER_CLASS_INSTANCE(InvertFilter, "invert")
+REGISTER_FILTER_CLASS_INSTANCE(ClampFilter, "clamp")
 REGISTER_FILTER_CLASS_INSTANCE(ConstrainToIntegerFilter, "constrainToInteger")
 REGISTER_FILTER_CLASS_INSTANCE(ConstrainToPositiveIntegerFilter, "constrainToPositiveInteger")
-REGISTER_FILTER_CLASS_INSTANCE(ScaleFilter, "scale")
-REGISTER_FILTER_CLASS_INSTANCE(ClampFilter, "clamp")
 REGISTER_FILTER_CLASS_INSTANCE(DeadZoneFilter, "deadZone")
+REGISTER_FILTER_CLASS_INSTANCE(HysteresisFilter, "hysteresis")
+REGISTER_FILTER_CLASS_INSTANCE(InvertFilter, "invert")
+REGISTER_FILTER_CLASS_INSTANCE(ScaleFilter, "scale")
 REGISTER_FILTER_CLASS_INSTANCE(PulseFilter, "pulse")
 
-
 const QString JSON_FILTER_TYPE = QStringLiteral("type");
 const QString JSON_FILTER_PARAMS = QStringLiteral("params");
 
 
-Filter::Pointer Filter::parse(const QJsonObject& json) {
-    // The filter is an object, now let s check for type and potential arguments
+Filter::Pointer Filter::parse(const QJsonValue& json) {
     Filter::Pointer filter;
-    auto filterType = json[JSON_FILTER_TYPE];
-    if (filterType.isString()) {
+    if (json.isString()) {
+        filter = Filter::getFactory().create(json.toString());
+    } else if (json.isObject()) {
+        QJsonObject jsonObj = json.toObject();
+        // The filter is an object, now let s check for type and potential arguments
+        auto filterType = jsonObj[JSON_FILTER_TYPE];
         filter = Filter::getFactory().create(filterType.toString());
         if (filter) {
-            // Filter is defined, need to read the parameters and validate
-            auto parameters = json[JSON_FILTER_PARAMS];
-            if (parameters.isArray()) {
-                if (filter->parseParameters(parameters.toArray())) {
-                }
+            QJsonValue params = jsonObj;
+            if (jsonObj.contains(JSON_FILTER_PARAMS)) {
+                params = jsonObj[JSON_FILTER_PARAMS];
+            }
+            if (!filter->parseParameters(params)) {
+                qWarning() << "Unable to parse filter parameters " << params;
+                return Filter::Pointer();
             }
-
-            return filter;
         }
     }
-    return Filter::Pointer();
+    return filter;
 }
 
-
-bool ScaleFilter::parseParameters(const QJsonArray& parameters) {
-    if (parameters.size() > 1) {
-        _scale = parameters[0].toDouble();
-    }
-    return true;
-}
-
-
-bool ClampFilter::parseParameters(const QJsonArray& parameters) {
-    if (parameters.size() > 1) {
-        _min = parameters[0].toDouble();
-    }
-    if (parameters.size() > 2) {
-        _max = parameters[1].toDouble();
-    }
-    return true;
-}
-
-
-float DeadZoneFilter::apply(float value) const {
-    float scale = 1.0f / (1.0f - _min);
-    if (std::abs(value) < _min) {
-        return 0.0f;
-    }
-    return (value - _min) * scale;
-}
-
-bool DeadZoneFilter::parseParameters(const QJsonArray& parameters) {
-    if (parameters.size() > 1) {
-        _min = parameters[0].toDouble();
-    }
-    return true;
-}
-
-
-float PulseFilter::apply(float value) const {
-    float result = 0.0f;
-
-    if (0.0f != value) {
-        float now = secTimestampNow();
-        float delta = now - _lastEmitTime;
-        if (delta >= _interval) {
-            _lastEmitTime = now;
-            result = value;
+bool Filter::parseSingleFloatParameter(const QJsonValue& parameters, const QString& name, float& output) {
+    if (parameters.isDouble()) {
+        output = parameters.toDouble();
+        return true;
+    } else if (parameters.isArray()) {
+        auto arrayParameters = parameters.toArray();
+        if (arrayParameters.size() > 1) {
+            output = arrayParameters[0].toDouble();
+            return true;
         }
-    }
-
-    return result;
-}
-
-bool PulseFilter::parseParameters(const QJsonArray& parameters) {
-    if (parameters.size() > 1) {
-        _interval = parameters[0].toDouble();
-    }
-    return true;
+    } else if (parameters.isObject()) {
+        static const QString JSON_MIN = QStringLiteral("interval");
+        auto objectParameters = parameters.toObject();
+        if (objectParameters.contains(name)) {
+            output = objectParameters[name].toDouble();
+            return true;
+        }
+    } 
+    return false;
 }
 
 
+
+#if 0
+
+namespace controller {
+
+    class LambdaFilter : public Filter {
+    public:
+        //    LambdaFilter() {}12
+        LambdaFilter(Lambda f) : _function(f) {};
+
+        virtual float apply(float value) const {
+            return _function(value);
+        }
+
+        virtual bool parseParameters(const QJsonArray& parameters) { return true; }
+
+        //        REGISTER_FILTER_CLASS(LambdaFilter);
+    private:
+        Lambda _function;
+    };
+
+    class ScriptFilter : public Filter {
+    public:
+
+    };
+
+
+
+    //class EasingFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override;
+
+    //private:
+    //    QEasingCurve _curve;
+    //};
+
+    //// GLSL style filters
+    //class StepFilter : public Filter {
+    //public:
+    //    StepFilter(float edge) : _edge(edge) {};
+    //    virtual float apply(float value) const override;
+
+    //private:
+    //    const float _edge;
+    //};
+
+    //class PowFilter : public Filter {
+    //public:
+    //    PowFilter(float exponent) : _exponent(exponent) {};
+    //    virtual float apply(float value) const override;
+
+    //private:
+    //    const float _exponent;
+    //};
+
+    //class AbsFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override;
+    //};
+
+    //class SignFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override;
+    //};
+
+    //class FloorFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override {
+    //        return floor(newValue);
+    //    }
+    //};
+
+    //class CeilFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override {
+    //        return ceil(newValue);
+    //    }
+    //};
+
+    //class FractFilter : public Filter {
+    //public:
+    //    virtual float apply(float value) const override {
+    //        return fract(newValue);
+    //    }
+    //};
+
+    //class MinFilter : public Filter {
+    //public:
+    //    MinFilter(float mine) : _min(min) {};
+
+    //    virtual float apply(float value) const override {
+    //        return glm::min(_min, newValue);
+    //    }
+
+    //private:
+    //    const float _min;
+    //};
+
+    //class MaxFilter : public Filter {
+    //public:
+    //    MaxFilter(float max) : _max(max) {};
+    //    virtual float apply(float newValue, float oldValue) override;
+    //private:
+    //    const float _max;
+    //};
+}
+#endif
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/impl/Filter.h b/libraries/controllers/src/controllers/impl/Filter.h
index 1fa9833044..77585c8ebb 100644
--- a/libraries/controllers/src/controllers/impl/Filter.h
+++ b/libraries/controllers/src/controllers/impl/Filter.h
@@ -21,8 +21,7 @@
 
 #include <QtCore/QEasingCurve>
 
-class QJsonObject;
-class QJsonArray;
+class QJsonValue;
 
 namespace controller {
 
@@ -36,11 +35,13 @@ namespace controller {
 
         virtual float apply(float value) const = 0;
         // Factory features
-        virtual bool parseParameters(const QJsonArray& parameters) { return true; }
+        virtual bool parseParameters(const QJsonValue& parameters) { return true; }
 
-        static Pointer parse(const QJsonObject& json);
+        static Pointer parse(const QJsonValue& json);
         static void registerBuilder(const QString& name, Factory::Builder builder);
         static Factory& getFactory() { return _factory; }
+
+        static bool parseSingleFloatParameter(const QJsonValue& parameters, const QString& name, float& output);
     protected:
         static Factory _factory;
     };
@@ -54,194 +55,5 @@ namespace controller {
 #define REGISTER_FILTER_CLASS_INSTANCE(classEntry, className) \
     classEntry::Registrar classEntry::_registrar(className, Filter::getFactory());
 
-namespace controller {
-
-    class LambdaFilter : public Filter {
-    public:
-    //    LambdaFilter() {}
-        LambdaFilter(Lambda f) : _function(f) {};
-
-        virtual float apply(float value) const {
-            return _function(value);
-        }
-
-        virtual bool parseParameters(const QJsonArray& parameters) { return true; }
-
-//        REGISTER_FILTER_CLASS(LambdaFilter);
-    private:
-        Lambda _function;
-    };
-
-    class ScriptFilter : public Filter {
-    public:
-
-    };
-   
-    class ScaleFilter : public Filter {
-        REGISTER_FILTER_CLASS(ScaleFilter);
-    public:
-        ScaleFilter() {}
-        ScaleFilter(float scale): _scale(scale) {}
-
-        virtual float apply(float value) const override {
-            return value * _scale;
-        }
-        virtual bool parseParameters(const QJsonArray& parameters);
-
-    private:
-        float _scale = 1.0f;
-    };
-
-    class InvertFilter : public ScaleFilter {
-        REGISTER_FILTER_CLASS(InvertFilter);
-    public:
-        InvertFilter() : ScaleFilter(-1.0f) {}
-        
-        virtual bool parseParameters(const QJsonArray& parameters) { return true; }
-
-    private:
-    };
-
-    class ClampFilter : public Filter {
-        REGISTER_FILTER_CLASS(ClampFilter);
-    public:
-        ClampFilter(float min = 0.0, float max = 1.0) : _min(min), _max(max) {};
-
-        virtual float apply(float value) const override {
-            return glm::clamp(value, _min, _max);
-        }
-        virtual bool parseParameters(const QJsonArray& parameters) override;
-    protected:
-        float _min = 0.0f;
-        float _max = 1.0f;
-    };
-
-    class DeadZoneFilter : public Filter {
-        REGISTER_FILTER_CLASS(DeadZoneFilter);
-    public:
-        DeadZoneFilter(float min = 0.0) : _min(min) {};
-
-        virtual float apply(float value) const override;
-        virtual bool parseParameters(const QJsonArray& parameters) override;
-    protected:
-        float _min = 0.0f;
-    };
-
-    class PulseFilter : public Filter {
-        REGISTER_FILTER_CLASS(PulseFilter);
-    public:
-        PulseFilter() {}
-        PulseFilter(float interval) : _interval(interval) {}
-
-
-        virtual float apply(float value) const override;
-
-        virtual bool parseParameters(const QJsonArray& parameters);
-
-    private:
-        mutable float _lastEmitTime{ -::std::numeric_limits<float>::max() };
-        float _interval = 1.0f;
-    };
-
-    class ConstrainToIntegerFilter : public Filter {
-        REGISTER_FILTER_CLASS(ConstrainToIntegerFilter);
-    public:
-        ConstrainToIntegerFilter() {};
-
-        virtual float apply(float value) const override {
-            return glm::sign(value);
-        }
-    protected:
-    };
-
-    class ConstrainToPositiveIntegerFilter : public Filter {
-        REGISTER_FILTER_CLASS(ConstrainToPositiveIntegerFilter);
-    public:
-        ConstrainToPositiveIntegerFilter() {};
-
-        virtual float apply(float value) const override {
-            return (value <= 0.0f) ? 0.0f : 1.0f;
-        }
-    protected:
-    };
-
-    //class EasingFilter : public Filter {
-    //public:
-    //    virtual float apply(float value) const override;
-
-    //private:
-    //    QEasingCurve _curve;
-    //};
-
-    //// GLSL style filters
-    //class StepFilter : public Filter {
-    //public:
-    //    StepFilter(float edge) : _edge(edge) {};
-    //    virtual float apply(float value) const override;
-
-    //private:
-    //    const float _edge;
-    //};
-
-    //class PowFilter : public Filter {
-    //public:
-    //    PowFilter(float exponent) : _exponent(exponent) {};
-    //    virtual float apply(float value) const override;
-
-    //private:
-    //    const float _exponent;
-    //};
-
-    //class AbsFilter : public Filter {
-    //public:
-    //    virtual float apply(float value) const override;
-    //};
-
-    //class SignFilter : public Filter {
-    //public:
-    //    virtual float apply(float value) const override;
-    //};
-
-    //class FloorFilter : public Filter {
-    //public:
-    //    virtual float apply(float value) const override {
-    //        return floor(newValue);
-    //    }
-    //};
-
-    //class CeilFilter : public Filter {
-    //public:
-    //    virtual float apply(float value) const override {
-    //        return ceil(newValue);
-    //    }
-    //};
-
-    //class FractFilter : public Filter {
-    //public:
-    //    virtual float apply(float value) const override {
-    //        return fract(newValue);
-    //    }
-    //};
-
-    //class MinFilter : public Filter {
-    //public:
-    //    MinFilter(float mine) : _min(min) {};
-
-    //    virtual float apply(float value) const override {
-    //        return glm::min(_min, newValue);
-    //    }
-
-    //private:
-    //    const float _min;
-    //};
-
-    //class MaxFilter : public Filter {
-    //public:
-    //    MaxFilter(float max) : _max(max) {};
-    //    virtual float apply(float newValue, float oldValue) override;
-    //private:
-    //    const float _max;
-    //};
-}
 
 #endif
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index d56d699c28..49e615439d 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -18,6 +18,15 @@
 #include "../ScriptingInterface.h"
 #include "../Logging.h"
 
+#include "filters/ClampFilter.h"
+#include "filters/ConstrainToIntegerFilter.h"
+#include "filters/ConstrainToPositiveIntegerFilter.h"
+#include "filters/DeadZoneFilter.h"
+#include "filters/HysteresisFilter.h"
+#include "filters/InvertFilter.h"
+#include "filters/PulseFilter.h"
+#include "filters/ScaleFilter.h"
+
 using namespace controller;
 
 void RouteBuilderProxy::toQml(const QJSValue& destination) {
@@ -43,18 +52,6 @@ QObject* RouteBuilderProxy::debug(bool enable) {
     return this;
 }
 
-QObject* RouteBuilderProxy::filterQml(const QJSValue& expression) {
-    if (expression.isCallable()) {
-        addFilter([=](float value) {
-            QJSValue originalExpression = expression;
-            QJSValueList params({ QJSValue(value) });
-            auto result = originalExpression.call(params);
-            return (float)(result.toNumber());
-        });
-    }
-    return this;
-}
-
 QObject* RouteBuilderProxy::when(const QScriptValue& expression) {
     _route->conditional = _parent.conditionalFor(expression);
     return this;
@@ -65,53 +62,46 @@ QObject* RouteBuilderProxy::whenQml(const QJSValue& expression) {
     return this;
 }
 
-
-QObject* RouteBuilderProxy::filter(const QScriptValue& expression) {
-    return this;
-}
-
-
 QObject* RouteBuilderProxy::clamp(float min, float max) {
-    addFilter(Filter::Pointer(new ClampFilter(min, max)));
+    addFilter(std::make_shared<ClampFilter>(min, max));
     return this;
 }
 
 QObject* RouteBuilderProxy::scale(float multiplier) {
-    addFilter(Filter::Pointer(new ScaleFilter(multiplier)));
+    addFilter(std::make_shared<ScaleFilter>(multiplier));
     return this;
 }
 
 QObject* RouteBuilderProxy::invert() {
-    addFilter(Filter::Pointer(new InvertFilter()));
+    addFilter(std::make_shared<InvertFilter>());
+    return this;
+}
+
+QObject* RouteBuilderProxy::hysteresis(float min, float max) {
+    addFilter(std::make_shared<HysteresisFilter>(min, max));
     return this;
 }
 
 QObject* RouteBuilderProxy::deadZone(float min) {
-    addFilter(Filter::Pointer(new DeadZoneFilter(min)));
+    addFilter(std::make_shared<DeadZoneFilter>(min));
     return this;
 }
 
 QObject* RouteBuilderProxy::constrainToInteger() {
-    addFilter(Filter::Pointer(new ConstrainToIntegerFilter()));
+    addFilter(std::make_shared<ConstrainToIntegerFilter>());
     return this;
 }
 
 QObject* RouteBuilderProxy::constrainToPositiveInteger() {
-    addFilter(Filter::Pointer(new ConstrainToPositiveIntegerFilter()));
+    addFilter(std::make_shared<ConstrainToPositiveIntegerFilter>());
     return this;
 }
 
-
 QObject* RouteBuilderProxy::pulse(float interval) {
-    addFilter(Filter::Pointer(new PulseFilter(interval)));
+    addFilter(std::make_shared<PulseFilter>(interval));
     return this;
 }
 
-void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
-    Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda);
-    addFilter(filterPointer);
-}
-
 void RouteBuilderProxy::addFilter(Filter::Pointer filter) {
     _route->filters.push_back(filter);
 }
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index 4bcfba5acd..d55aa80f6b 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -34,14 +34,13 @@ class RouteBuilderProxy : public QObject {
             : _parent(parent), _mapping(mapping), _route(route) { }
 
         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* hysteresis(float min, float max);
         Q_INVOKABLE QObject* pulse(float interval);
         Q_INVOKABLE QObject* scale(float multiplier);
         Q_INVOKABLE QObject* invert();
@@ -52,7 +51,6 @@ 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;
         Mapping::Pointer _mapping;
diff --git a/libraries/controllers/src/controllers/impl/filters/ClampFilter.cpp b/libraries/controllers/src/controllers/impl/filters/ClampFilter.cpp
new file mode 100644
index 0000000000..ec22981ef3
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/ClampFilter.cpp
@@ -0,0 +1,38 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "ClampFilter.h"
+
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
+using namespace controller;
+
+bool ClampFilter::parseParameters(const QJsonValue& parameters) {
+    if (parameters.isArray()) {
+        auto arrayParameters = parameters.toArray();
+        if (arrayParameters.size() > 1) {
+            _min = arrayParameters[0].toDouble();
+        }
+        if (arrayParameters.size() > 2) {
+            _max = arrayParameters[1].toDouble();
+        }
+    } else if (parameters.isObject()) {
+        static const QString JSON_MAX = QStringLiteral("max");
+        static const QString JSON_MIN = QStringLiteral("min");
+
+        auto objectParameters = parameters.toObject();
+        if (objectParameters.contains(JSON_MIN)) {
+            _min = objectParameters[JSON_MIN].toDouble();
+        }
+        if (objectParameters.contains(JSON_MAX)) {
+            _max = objectParameters[JSON_MAX].toDouble();
+        }
+    }
+    return true;
+}
diff --git a/libraries/controllers/src/controllers/impl/filters/ClampFilter.h b/libraries/controllers/src/controllers/impl/filters/ClampFilter.h
new file mode 100644
index 0000000000..fd82821b3e
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/ClampFilter.h
@@ -0,0 +1,32 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_Clamp_h
+#define hifi_Controllers_Filters_Clamp_h
+
+#include "../Filter.h"
+
+namespace controller {
+
+class ClampFilter : public Filter {
+    REGISTER_FILTER_CLASS(ClampFilter);
+public:
+    ClampFilter(float min = 0.0, float max = 1.0) : _min(min), _max(max) {};
+    virtual float apply(float value) const override {
+        return glm::clamp(value, _min, _max);
+    }
+    virtual bool parseParameters(const QJsonValue& parameters) override;
+protected:
+    float _min = 0.0f;
+    float _max = 1.0f;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp
new file mode 100644
index 0000000000..78ffb47693
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "ConstrainToIntegerFilter.h"
diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h
new file mode 100644
index 0000000000..580dc2a856
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h
@@ -0,0 +1,30 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_ConstrainToIntegerFilter_h
+#define hifi_Controllers_Filters_ConstrainToIntegerFilter_h
+
+#include "../Filter.h"
+
+namespace controller {
+
+class ConstrainToIntegerFilter : public Filter {
+    REGISTER_FILTER_CLASS(ConstrainToIntegerFilter);
+public:
+    ConstrainToIntegerFilter() {};
+
+    virtual float apply(float value) const override {
+        return glm::sign(value);
+    }
+protected:
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp
new file mode 100644
index 0000000000..d78942b18f
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "ConstrainToPositiveIntegerFilter.h"
diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h
new file mode 100644
index 0000000000..27395cde24
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h
@@ -0,0 +1,30 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_ConstrainToPositiveInteger_h
+#define hifi_Controllers_Filters_ConstrainToPositiveInteger_h
+
+#include "../Filter.h"
+
+namespace controller {
+
+class ConstrainToPositiveIntegerFilter : public Filter {
+    REGISTER_FILTER_CLASS(ConstrainToPositiveIntegerFilter);
+public:
+    ConstrainToPositiveIntegerFilter() {};
+
+    virtual float apply(float value) const override {
+        return (value <= 0.0f) ? 0.0f : 1.0f;
+    }
+protected:
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.cpp b/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.cpp
new file mode 100644
index 0000000000..809308eeab
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.cpp
@@ -0,0 +1,26 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "DeadZoneFilter.h"
+
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
+using namespace controller;
+float DeadZoneFilter::apply(float value) const {
+    float scale = 1.0f / (1.0f - _min);
+    if (std::abs(value) < _min) {
+        return 0.0f;
+    }
+    return (value - _min) * scale;
+}
+
+bool DeadZoneFilter::parseParameters(const QJsonValue& parameters) {
+    static const QString JSON_MIN = QStringLiteral("min");
+    return parseSingleFloatParameter(parameters, JSON_MIN, _min);
+}
diff --git a/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h b/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h
new file mode 100644
index 0000000000..70ac657415
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h
@@ -0,0 +1,31 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_DeadZoneFilter_h
+#define hifi_Controllers_Filters_DeadZoneFilter_h
+
+#include "../Filter.h"
+
+namespace controller {
+
+class DeadZoneFilter : public Filter {
+    REGISTER_FILTER_CLASS(DeadZoneFilter);
+public:
+    DeadZoneFilter(float min = 0.0) : _min(min) {};
+
+    virtual float apply(float value) const override;
+    virtual bool parseParameters(const QJsonValue& parameters) override;
+protected:
+    float _min = 0.0f;
+};
+
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.cpp b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.cpp
new file mode 100644
index 0000000000..c1edfe35da
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.cpp
@@ -0,0 +1,57 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "HysteresisFilter.h"
+
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
+using namespace controller;
+
+float HysteresisFilter::apply(float value) const {
+    if (_signaled) {
+        if (value <= _min) {
+            _signaled = false;
+        }
+    } else {
+        if (value >= _max) {
+            _signaled = true;
+        }
+    }
+    return _signaled ? 1.0f : 0.0f;
+}
+
+bool HysteresisFilter::parseParameters(const QJsonValue& parameters) {
+    if (parameters.isArray()) {
+        auto arrayParameters = parameters.toArray();
+        if (arrayParameters.size() > 1) {
+            _min = arrayParameters[0].toDouble();
+        }
+        if (arrayParameters.size() > 2) {
+            _max = arrayParameters[1].toDouble();
+        }
+    } else if (parameters.isObject()) {
+        static const QString JSON_MAX = QStringLiteral("max");
+        static const QString JSON_MIN = QStringLiteral("min");
+
+        auto objectParameters = parameters.toObject();
+        if (objectParameters.contains(JSON_MIN)) {
+            _min = objectParameters[JSON_MIN].toDouble();
+        }
+        if (objectParameters.contains(JSON_MAX)) {
+            _max = objectParameters[JSON_MAX].toDouble();
+        }
+    } else {
+        return false;
+    }
+
+    if (_min > _max) {
+        std::swap(_min, _max);
+    }
+    return true;
+}
diff --git a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h
new file mode 100644
index 0000000000..cf33f1bbff
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h
@@ -0,0 +1,31 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_Hysteresis_h
+#define hifi_Controllers_Filters_Hysteresis_h
+
+#include "../Filter.h"
+
+namespace controller {
+
+class HysteresisFilter : public Filter {
+    REGISTER_FILTER_CLASS(HysteresisFilter);
+public:
+    HysteresisFilter(float min = 0.25, float max = 0.75) : _min(min), _max(max) {};
+    virtual float apply(float value) const override;
+    virtual bool parseParameters(const QJsonValue& parameters) override;
+protected:
+    float _min;
+    float _max;
+    mutable bool _signaled { false };
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp b/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp
new file mode 100644
index 0000000000..db582b84cc
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "InvertFilter.h"
diff --git a/libraries/controllers/src/controllers/impl/filters/InvertFilter.h b/libraries/controllers/src/controllers/impl/filters/InvertFilter.h
new file mode 100644
index 0000000000..889cd0140c
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/InvertFilter.h
@@ -0,0 +1,29 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_InvertFilter_h
+#define hifi_Controllers_Filters_InvertFilter_h
+
+#include "ScaleFilter.h"
+
+namespace controller {
+
+class InvertFilter : public ScaleFilter {
+    REGISTER_FILTER_CLASS(InvertFilter);
+public:
+    InvertFilter() : ScaleFilter(-1.0f) {}
+
+    virtual bool parseParameters(const QJsonArray& parameters) { return true; }
+
+private:
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/filters/PulseFilter.cpp b/libraries/controllers/src/controllers/impl/filters/PulseFilter.cpp
new file mode 100644
index 0000000000..f4e1f04791
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/PulseFilter.cpp
@@ -0,0 +1,37 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "PulseFilter.h"
+
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
+using namespace controller;
+
+
+
+float PulseFilter::apply(float value) const {
+    float result = 0.0f;
+
+    if (0.0f != value) {
+        float now = secTimestampNow();
+        float delta = now - _lastEmitTime;
+        if (delta >= _interval) {
+            _lastEmitTime = now;
+            result = value;
+        }
+    }
+
+    return result;
+}
+
+bool PulseFilter::parseParameters(const QJsonValue& parameters) {
+    static const QString JSON_MIN = QStringLiteral("interval");
+    return parseSingleFloatParameter(parameters, JSON_MIN, _interval);
+}
+
diff --git a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h
new file mode 100644
index 0000000000..2512b479cf
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h
@@ -0,0 +1,36 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_Pulse_h
+#define hifi_Controllers_Filters_Pulse_h
+
+#include "../Filter.h"
+
+namespace controller {
+
+
+class PulseFilter : public Filter {
+    REGISTER_FILTER_CLASS(PulseFilter);
+public:
+    PulseFilter() {}
+    PulseFilter(float interval) : _interval(interval) {}
+
+
+    virtual float apply(float value) const override;
+
+    virtual bool parseParameters(const QJsonValue& parameters);
+
+private:
+    mutable float _lastEmitTime { -::std::numeric_limits<float>::max() };
+    float _interval = 1.0f;
+};
+
+}
+
+#endif
diff --git a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.cpp b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.cpp
new file mode 100644
index 0000000000..4a310e3a04
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.cpp
@@ -0,0 +1,19 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "ScaleFilter.h"
+
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
+using namespace controller;
+
+bool ScaleFilter::parseParameters(const QJsonValue& parameters) {
+    static const QString JSON_SCALE = QStringLiteral("scale");
+    return parseSingleFloatParameter(parameters, JSON_SCALE, _scale);
+}
diff --git a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h
new file mode 100644
index 0000000000..39c5edd4e5
--- /dev/null
+++ b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h
@@ -0,0 +1,34 @@
+//
+//  Created by Bradley Austin Davis 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_Controllers_Filters_Scale_h
+#define hifi_Controllers_Filters_Scale_h
+
+#include "../Filter.h"
+
+namespace controller {
+
+class ScaleFilter : public Filter {
+    REGISTER_FILTER_CLASS(ScaleFilter);
+public:
+    ScaleFilter() {}
+    ScaleFilter(float scale) : _scale(scale) {}
+
+    virtual float apply(float value) const override {
+        return value * _scale;
+    }
+    virtual bool parseParameters(const QJsonValue& parameters);
+
+private:
+    float _scale = 1.0f;
+};
+
+}
+
+#endif

From 75b2ee94b243f34f7c7fab4c8bfe6f6dce627816 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 25 Oct 2015 16:44:55 -0700
Subject: [PATCH 160/301] PR feedback

---
 examples/controllers/hydra/gun.js             | 27 +++++++------------
 .../impl/filters/HysteresisFilter.cpp         |  7 +++++
 .../impl/filters/HysteresisFilter.h           |  2 +-
 3 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/examples/controllers/hydra/gun.js b/examples/controllers/hydra/gun.js
index 03caf50ad7..576c4335f6 100644
--- a/examples/controllers/hydra/gun.js
+++ b/examples/controllers/hydra/gun.js
@@ -15,9 +15,12 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-Script.include([ "../../libraries/utils.js" ]);
-Script.include([ "../../libraries/constants.js" ]);
-Script.include([ "../../libraries/toolBars.js" ]);
+// FIXME kickback functionality was removed because the joint setting interface in 
+// MyAvatar has apparently changed, breaking it.  
+
+Script.include("../../libraries/utils.js");
+Script.include("../../libraries/constants.js");
+Script.include("../../libraries/toolBars.js");
 
 HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
 
@@ -100,14 +103,11 @@ var bulletID = false;
 var targetID = false;
 
 // Create overlay buttons and reticle
-
 var BUTTON_SIZE = 32;
 var PADDING = 3;
 var NUM_BUTTONS = 3;
-
 var screenSize = Controller.getViewportDimensions();
 var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2;
-
 var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function(screenSize) {
     return {
         x: startX,
@@ -441,11 +441,6 @@ function keyPressEvent(event) {
         shootFromMouse(true);
     } else if (event.text == "r") {
         playLoadSound();
-    } else if (event.text == "s") {
-        // Hit this key to dump a posture from hydra to log
-        Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm"));
-        Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm"));
-        Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand"));
     }
 }
 
@@ -478,9 +473,7 @@ function update(deltaTime) {
 
         // Need to adjust the laser
         var tipPose = tipPoses[side];
-        var handRotation = MyAvatar.getJointCombinedRotation(side == 0 ? "LeftHand" : "RightHand");
-        // handRotation = Quat.multiply(Quat.inverse(MyAvatar.orientation),
-        // handRotation);
+        var handRotation = tipPoses[side].rotation;
         var barrelOffset = Vec3.multiplyQbyV(handRotation, BARREL_OFFSETS[side]);
         barrelTips[side] = Vec3.sum(tipPose.translation, barrelOffset);
         barrelVectors[side] = Vec3.multiplyQbyV(handRotation, {
@@ -536,17 +529,17 @@ function scriptEnding() {
     clearPose();
 }
 
-MyAvatar.attach(GUN_MODEL, "LeftHand", GUN_OFFSETS[0], GUN_ORIENTATIONS[1], 0.40);
+MyAvatar.attach(GUN_MODEL, "LeftHand", GUN_OFFSETS[0], GUN_ORIENTATIONS[0], 0.40);
 MyAvatar.attach(GUN_MODEL, "RightHand", GUN_OFFSETS[1], GUN_ORIENTATIONS[1], 0.40);
 
 // Give a bit of time to load before playing sound
 Script.setTimeout(playLoadSound, 2000);
 
-mapping.from(Controller.Standard.LT).constrainToPositiveInteger().to(function(value) {
+mapping.from(Controller.Standard.LT).hysteresis(0.1, 0.5).to(function(value) {
     triggerChanged(0, value);
 });
 
-mapping.from(Controller.Standard.RT).constrainToPositiveInteger().to(function(value) {
+mapping.from(Controller.Standard.RT).hysteresis(0.1, 0.5).to(function(value) {
     triggerChanged(1, value);
 });
 mapping.enable();
diff --git a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.cpp b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.cpp
index c1edfe35da..a7f22e1de4 100644
--- a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.cpp
+++ b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.cpp
@@ -13,6 +13,13 @@
 
 using namespace controller;
 
+HysteresisFilter::HysteresisFilter(float min, float max) : _min(min), _max(max) {
+    if (_min > _max) {
+        std::swap(_min, _max);
+    }
+};
+
+
 float HysteresisFilter::apply(float value) const {
     if (_signaled) {
         if (value <= _min) {
diff --git a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h
index cf33f1bbff..4f7e07928d 100644
--- a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h
@@ -17,7 +17,7 @@ namespace controller {
 class HysteresisFilter : public Filter {
     REGISTER_FILTER_CLASS(HysteresisFilter);
 public:
-    HysteresisFilter(float min = 0.25, float max = 0.75) : _min(min), _max(max) {};
+    HysteresisFilter(float min = 0.25, float max = 0.75);
     virtual float apply(float value) const override;
     virtual bool parseParameters(const QJsonValue& parameters) override;
 protected:

From 900b07fdeef094f5e6ddf14939fc1a76934ae628 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Mon, 26 Oct 2015 10:00:07 -0700
Subject: [PATCH 161/301] dead code

---
 interface/src/avatar/MyAvatar.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 435e6af5ef..1ffb27930e 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -118,8 +118,6 @@ public:
     Q_INVOKABLE QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { return _rig->addAnimationStateHandler(handler, propertiesList); }
     // Removes a handler previously added by addAnimationStateHandler.
     Q_INVOKABLE void removeAnimationStateHandler(QScriptValue handler) { _rig->removeAnimationStateHandler(handler); }
-    // Processes a handler result. Not really for user code, but used by callAnimationStateHandler.
-    Q_INVOKABLE void animationStateHandlerResult(QScriptValue handler, QScriptValue result) { _rig->animationStateHandlerResult(handler, result); }
 
     // get/set avatar data
     void saveData();

From 4b4907c9ef8bb4398d1db9cb7c8285c823c758e5 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Mon, 26 Oct 2015 10:04:55 -0700
Subject: [PATCH 162/301] Allow multiple scripts to register, and allow them to
 specify the specific anim vars they are interested in.

---
 libraries/animation/src/AnimVariant.h        |  4 +-
 libraries/animation/src/AnimVariantMap.cpp   | 31 +++++++---
 libraries/animation/src/Rig.cpp              | 60 +++++++++++++-------
 libraries/animation/src/Rig.h                | 12 +++-
 libraries/script-engine/src/ScriptEngine.cpp | 11 ++--
 libraries/script-engine/src/ScriptEngine.h   |  2 +-
 6 files changed, 79 insertions(+), 41 deletions(-)

diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h
index 7a80321f7b..bd96dda77d 100644
--- a/libraries/animation/src/AnimVariant.h
+++ b/libraries/animation/src/AnimVariant.h
@@ -163,7 +163,7 @@ public:
     bool hasKey(const QString& key) const { return _map.find(key) != _map.end(); }
 
     // Answer a Plain Old Javascript Object (for the given engine) all of our values set as properties.
-    QScriptValue animVariantMapToScriptValue(QScriptEngine* engine) const;
+    QScriptValue animVariantMapToScriptValue(QScriptEngine* engine, const QStringList& names, bool useNames) const;
     // Side-effect us with the value of object's own properties. (No inherited properties.)
     void animVariantMapFromScriptValue(const QScriptValue& object);
     void copyVariantsFrom(const AnimVariantMap& other);
@@ -206,7 +206,7 @@ protected:
     std::set<QString> _triggers;
 };
 
-typedef std::function<void(QScriptValue, QScriptValue)> AnimVariantResultHandler;
+typedef std::function<void(QScriptValue)> AnimVariantResultHandler;
 Q_DECLARE_METATYPE(AnimVariantResultHandler);
 Q_DECLARE_METATYPE(AnimVariantMap)
 
diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
index 59f10a96e0..0c808bd404 100644
--- a/libraries/animation/src/AnimVariantMap.cpp
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -15,36 +15,49 @@
 #include <RegisteredMetaTypes.h>
 #include "AnimVariant.h"
 
-QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine) const {
+QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine, const QStringList& names, bool useNames) const {
     if (QThread::currentThread() != engine->thread()) {
         qCWarning(animation) << "Cannot create Javacript object from non-script thread" << QThread::currentThread();
         return QScriptValue();
     }
     QScriptValue target = engine->newObject();
-    for (auto& pair : _map) {
-        switch (pair.second.getType()) {
+    auto setOne = [&] (QString name, AnimVariant value) {
+        switch (value.getType()) {
             case AnimVariant::Type::Bool:
-                target.setProperty(pair.first, pair.second.getBool());
+                target.setProperty(name, value.getBool());
                 break;
             case AnimVariant::Type::Int:
-                target.setProperty(pair.first, pair.second.getInt());
+                target.setProperty(name, value.getInt());
                 break;
             case AnimVariant::Type::Float:
-                target.setProperty(pair.first, pair.second.getFloat());
+                target.setProperty(name, value.getFloat());
                 break;
             case AnimVariant::Type::String:
-                target.setProperty(pair.first, pair.second.getString());
+                target.setProperty(name, value.getString());
                 break;
             case AnimVariant::Type::Vec3:
-                target.setProperty(pair.first, vec3toScriptValue(engine, pair.second.getVec3()));
+                target.setProperty(name, vec3toScriptValue(engine, value.getVec3()));
                 break;
             case AnimVariant::Type::Quat:
-                target.setProperty(pair.first, quatToScriptValue(engine, pair.second.getQuat()));
+                target.setProperty(name, quatToScriptValue(engine, value.getQuat()));
                 break;
             default:
                 // Note that we don't do mat4 in Javascript currently, and there's not yet a reason to start now.
                 assert("AnimVariant::Type" == "valid");
         }
+    };
+    if (useNames) { // copy only the requested names
+        for (const QString& name : names) {
+            auto search = _map.find(name);
+            if (search != _map.end()) { // scripts are allowed to request names that do not exist
+                setOne(name, search->second);
+            }
+        }
+
+    } else {  // copy all of them
+        for (auto& pair : _map) {
+            setOne(pair.first, pair.second);
+        }
     }
     return target;
 }
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 0576a8e420..7810bb8693 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -606,36 +606,51 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
 }
 
 // Allow script to add/remove handlers and report results, from within their thread.
-// TODO: iterate multiple handlers, but with one shared arg.
-// TODO: fill the properties based on the union of requested properties. (Keep all properties objs and compute new union when add/remove handler.)
 QScriptValue Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { // called in script thread
-    _stateHandlers = handler;
-    return handler; // suitable for giving to removeAnimationStateHandler
-}
-void Rig::removeAnimationStateHandler(QScriptValue handler) { // called in script thread
-    _stateHandlers = QScriptValue();
-    QMutexLocker locker(&_stateMutex); // guarding access to results
-    _stateHandlersResults.clearMap(); // TODO: When we have multiple handlers, we'll need to clear only his handler's results.
-}
-void Rig::animationStateHandlerResult(QScriptValue handler, QScriptValue result) { // called synchronously from script
-    // handler is currently ignored but might be used in storing individual results
     QMutexLocker locker(&_stateMutex);
-    if (!_stateHandlers.isValid()) {
+    int identifier = ++_nextStateHandlerId; // 0 is unused
+    StateHandler& data = _stateHandlers[identifier];
+    data.function = handler;
+    data.useNames = propertiesList.isArray();
+    if (data.useNames) {
+        data.propertyNames = propertiesList.toVariant().toStringList();
+    }
+    return QScriptValue(identifier); // suitable for giving to removeAnimationStateHandler
+}
+void Rig::removeAnimationStateHandler(QScriptValue identifier) { // called in script thread
+    QMutexLocker locker(&_stateMutex);
+    _stateHandlers.remove(identifier.isNumber() ? identifier.toInt32() : 0); // silently continues if handler not present
+}
+void Rig::animationStateHandlerResult(int identifier, QScriptValue result) { // called synchronously from script
+    QMutexLocker locker(&_stateMutex);
+    auto found = _stateHandlers.find(identifier);
+    if (found == _stateHandlers.end()) {
         return; // Don't use late-breaking results that got reported after the handler was removed.
     }
-    _stateHandlersResults.animVariantMapFromScriptValue(result); // Into our own copy.
+    found.value().results.animVariantMapFromScriptValue(result); // Into our own copy.
 }
 
 void Rig::updateAnimationStateHandlers() { // called on avatar update thread (which may be main thread)
-    if (_stateHandlers.isValid()) {
-        auto handleResult = [this](QScriptValue handler, QScriptValue result) {
-            animationStateHandlerResult(handler, result);
+    QMutexLocker locker(&_stateMutex);
+    // It might pay to produce just one AnimVariantMap copy here, with a union of all the requested propertyNames,
+    // rather than having each callAnimationStateHandler invocation make its own copy.
+    // However, that copying is done on the script's own time rather than ours, so even if it's less cpu, it would be more
+    // work on the avatar update thread (which is possibly the main thread).
+    for (auto data = _stateHandlers.begin(); data != _stateHandlers.end(); data++) {
+        // call out:
+        int identifier = data.key();
+        StateHandler& value = data.value();
+        QScriptValue& function = value.function;
+        auto handleResult = [this, identifier](QScriptValue result) {
+            animationStateHandlerResult(identifier, result);
         };
         // invokeMethod makes a copy of the args, and copies of AnimVariantMap do copy the underlying map, so this will correctly capture
         // the state of _animVars and allow continued changes to _animVars in this thread without conflict.
-        QMetaObject::invokeMethod(_stateHandlers.engine(), "callAnimationStateHandler",  Qt::QueuedConnection,
-                                  Q_ARG(QScriptValue, _stateHandlers),
+        QMetaObject::invokeMethod(function.engine(), "callAnimationStateHandler",  Qt::QueuedConnection,
+                                  Q_ARG(QScriptValue, function),
                                   Q_ARG(AnimVariantMap, _animVars),
+                                  Q_ARG(QStringList, value.propertyNames),
+                                  Q_ARG(bool, value.useNames),
                                   Q_ARG(AnimVariantResultHandler, handleResult));
         // It turns out that, for thread-safety reasons, ScriptEngine::callAnimationStateHandler will invoke itself if called from other
         // than the script thread. Thus the above _could_ be replaced with an ordinary call, which will then trigger the same
@@ -643,12 +658,13 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
         // We could create an AnimVariantCallingMixin class in shared, with an abstract virtual slot
         // AnimVariantCallingMixin::callAnimationStateHandler (and move AnimVariantMap/AnimVaraintResultHandler to shared), but the
         // call site here would look like this instead of the above:
-        //   dynamic_cast<AnimVariantCallingMixin*>(_stateHandlers.engine())->callAnimationStateHandler(_stateHandlers, _animVars, handleResult);
+        //   dynamic_cast<AnimVariantCallingMixin*>(function.engine())->callAnimationStateHandler(function, ..., handleResult);
         // This works (I tried it), but the result would be that we would still have same runtime type checks as the invokeMethod above
         // (occuring within the ScriptEngine::callAnimationStateHandler invokeMethod trampoline), _plus_ another runtime check for the dynamic_cast.
+
+        // gather results in (likely from an earlier update):
+        _animVars.copyVariantsFrom(value.results); // If multiple handlers write the same anim var, the last registgered wins. (_map preserves order).
     }
-    QMutexLocker locker(&_stateMutex); // as we examine/copy most recently computed state, if any. (Typically an earlier invocation.)
-    _animVars.copyVariantsFrom(_stateHandlersResults);
 }
 
 void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index 83f1a02b8a..5551b21e40 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -53,6 +53,12 @@ typedef std::shared_ptr<Rig> RigPointer;
 
 class Rig : public QObject, public std::enable_shared_from_this<Rig> {
 public:
+    struct StateHandler {
+        AnimVariantMap results;
+        QStringList propertyNames;
+        QScriptValue function;
+        bool useNames;
+    };
 
     struct HeadParameters {
         float leanSideways = 0.0f; // degrees
@@ -203,7 +209,7 @@ public:
     bool disableHands {false}; // should go away with rig animation (and Rig::inverseKinematics)
     QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList);
     void removeAnimationStateHandler(QScriptValue handler);
-    void animationStateHandlerResult(QScriptValue handler, QScriptValue result);
+    void animationStateHandlerResult(int identifier, QScriptValue result);
 
     bool getModelOffset(glm::vec3& modelOffsetOut) const;
 
@@ -249,8 +255,8 @@ public:
     float _rightHandOverlayAlpha = 0.0f;
 
 private:
-    QScriptValue _stateHandlers;
-    AnimVariantMap _stateHandlersResults;
+    QMap<int, StateHandler> _stateHandlers;
+    int _nextStateHandlerId {0};
     QMutex _stateMutex;
 };
 
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 86eb9570d8..91df9fa793 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -262,7 +262,8 @@ void ScriptEngine::errorInLoadingScript(const QUrl& url) {
 // callAnimationStateHandler requires that the type be registered.
 // These two are meaningful, if we ever do want to use them...
 static QScriptValue animVarMapToScriptValue(QScriptEngine* engine, const AnimVariantMap& parameters) {
-    return parameters.animVariantMapToScriptValue(engine);
+    QStringList unused;
+    return parameters.animVariantMapToScriptValue(engine, unused, false);
 }
 static void animVarMapFromScriptValue(const QScriptValue& value, AnimVariantMap& parameters) {
     parameters.animVariantMapFromScriptValue(value);
@@ -741,7 +742,7 @@ void ScriptEngine::stop() {
 }
 
 // Other threads can invoke this through invokeMethod, which causes the callback to be asynchronously executed in this script's thread.
-void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, AnimVariantResultHandler resultHandler) {
+void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler) {
     if (QThread::currentThread() != thread()) {
 #ifdef THREAD_DEBUGGING
         qDebug() << "*** WARNING *** ScriptEngine::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]  name:" << name;
@@ -749,14 +750,16 @@ void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantM
         QMetaObject::invokeMethod(this, "callAnimationStateHandler",
                                   Q_ARG(QScriptValue, callback),
                                   Q_ARG(AnimVariantMap, parameters),
+                                  Q_ARG(QStringList, names),
+                                  Q_ARG(bool, useNames),
                                   Q_ARG(AnimVariantResultHandler, resultHandler));
         return;
     }
-    QScriptValue javascriptParametgers = parameters.animVariantMapToScriptValue(this);
+    QScriptValue javascriptParametgers = parameters.animVariantMapToScriptValue(this, names, useNames);
     QScriptValueList callingArguments;
     callingArguments << javascriptParametgers;
     QScriptValue result = callback.call(QScriptValue(), callingArguments);
-    resultHandler(callback, result);
+    resultHandler(result);
 }
 
 void ScriptEngine::timerFired() {
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index b6f736c846..30468880a2 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -144,7 +144,7 @@ public:
     ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; }
 
 public slots:
-    void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, AnimVariantResultHandler resultHandler);
+    void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler);
 
 signals:
     void scriptLoaded(const QString& scriptFilename);

From f38303a9a5890c6fa75a73d776089dabd4b2d27e Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 26 Oct 2015 10:36:31 -0700
Subject: [PATCH 163/301] Adding vive default mapping

---
 interface/resources/controllers/vive.json     | 22 +++++++++++++++++++
 .../input-plugins/ViveControllerManager.cpp   |  4 ++--
 2 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 interface/resources/controllers/vive.json

diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json
new file mode 100644
index 0000000000..f51f908813
--- /dev/null
+++ b/interface/resources/controllers/vive.json
@@ -0,0 +1,22 @@
+{
+    "name": "XBox to Standard",
+    "channels": [
+        { "from": "Vive.LY", "to": "Standard.LY" }, 
+        { "from": "Vive.LX", "to": "Standard.LX" },
+        { "from": "Vive.LT", "to": "Standard.LT" }, 
+        { "from": "Vive.LB", "to": "Standard.LB" }, 
+        { "from": "Vive.LS", "to": "Standard.LS" },
+
+        { "from": "Vive.RY", "to": "Standard.RY" }, 
+        { "from": "Vive.RX", "to": "Standard.RX" },
+        { "from": "Vive.RT", "to": "Standard.RT" }, 
+        { "from": "Vive.RB", "to": "Standard.RB" }, 
+        { "from": "Vive.RS", "to": "Standard.RS" },
+
+        { "from": "Vive.Back", "to": "Standard.Back" }, 
+        { "from": "Vive.Start", "to": "Standard.Start" }, 
+        
+        { "from": "Vive.A", "to": "Standard.A" }, 
+        { "from": "Vive.B", "to": "Standard.B" }
+    ]
+}
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index 21b7b81173..8dd3d21a07 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -45,7 +45,7 @@ const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
 const QString RENDER_CONTROLLERS = "Render Hand Controllers";
 
 ViveControllerManager::ViveControllerManager() :
-        InputDevice("SteamVR Controller"),
+        InputDevice("Vive"),
     _trackedControllers(0),
     _modelLoaded(false),
     _leftHandRenderID(0),
@@ -313,7 +313,7 @@ void ViveControllerManager::handleButtonEvent(uint32_t button, bool pressed, boo
 
     if (button == vr::k_EButton_ApplicationMenu) {
         // FIXME?
-        _buttonPressedMap.insert(left ? controller::A : controller::A);
+        _buttonPressedMap.insert(left ? controller::B : controller::A);
     } else if (button == vr::k_EButton_Grip) {
         // Tony says these are harder to reach, so make them the meta buttons
         _buttonPressedMap.insert(left ? controller::BACK : controller::START);

From 6b9b4d4e6e38d6c8428261c1699f3074ecedc570 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 26 Oct 2015 10:44:39 -0700
Subject: [PATCH 164/301] Add libraries/line.js

---
 examples/libraries/line.js | 149 +++++++++++++++++++++++++++++++++++++
 1 file changed, 149 insertions(+)
 create mode 100644 examples/libraries/line.js

diff --git a/examples/libraries/line.js b/examples/libraries/line.js
new file mode 100644
index 0000000000..62811e50bc
--- /dev/null
+++ b/examples/libraries/line.js
@@ -0,0 +1,149 @@
+function error(message) {
+    print("[ERROR] " + message);
+}
+
+// PolyLine
+var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 };
+var MAX_LINE_LENGTH = 40; // This must be 2 or greater;
+var PolyLine = function(position, color, defaultStrokeWidth) {
+    this.position = position;
+    this.color = color;
+    this.defaultStrokeWidth = 0.10;
+    this.points = [
+        { x: 0, y: 0, z: 0 }
+    ];
+    this.strokeWidths = [
+        this.defaultStrokeWidth
+    ];
+    this.normals = [
+        { x: 1, y: 0, z: 0 }
+    ]
+    this.entityID = Entities.addEntity({
+        type: "PolyLine",
+        position: position,
+        linePoints: this.points,
+        normals: this.normals,
+        strokeWidths: this.strokeWidths,
+        dimensions: LINE_DIMENSIONS,
+        color: color,
+        lifetime: 20,
+    });
+};
+
+PolyLine.prototype.enqueuePoint = function(position) {
+    if (this.isFull()) {
+        error("Hit max PolyLine size");
+        return;
+    }
+
+    position = Vec3.subtract(position, this.position);
+    this.points.push(position);
+    this.normals.push({ x: 1, y: 0, z: 0 });
+    this.strokeWidths.push(this.defaultStrokeWidth * Math.min(1.0, this.points.length / 10));
+    Entities.editEntity(this.entityID, {
+        linePoints: this.points,
+        normals: this.normals,
+        strokeWidths: this.strokeWidths,
+    });
+};
+
+PolyLine.prototype.dequeuePoint = function() {
+    if (this.points.length == 0) {
+        error("Hit min PolyLine size");
+        return;
+    }
+
+    this.points = this.points.slice(1);
+    this.normals = this.normals.slice(1);
+    this.strokeWidths = this.strokeWidths.slice(1);
+
+    Entities.editEntity(this.entityID, {
+        linePoints: this.points,
+        normals: this.normals,
+        strokeWidths: this.strokeWidths,
+    });
+};
+
+PolyLine.prototype.getFirstPoint = function() {
+    return Vec3.sum(this.position, this.points[0]);
+};
+
+PolyLine.prototype.getLastPoint = function() {
+    return Vec3.sum(this.position, this.points[this.points.length - 1]);
+};
+
+PolyLine.prototype.getSize = function() {
+    return this.points.length;
+}
+
+PolyLine.prototype.isFull = function() {
+    return this.points.length >= MAX_LINE_LENGTH;
+};
+
+PolyLine.prototype.destroy = function() {
+    Entities.deleteEntity(this.entityID);
+    this.points = [];
+};
+
+
+
+// InfiniteLine
+InfiniteLine = function(position, color) {
+    this.position = position;
+    this.color = color;
+    this.lines = [new PolyLine(position, color)];
+    this.size = 0;
+};
+
+InfiniteLine.prototype.enqueuePoint = function(position) {
+    var currentLine;
+
+    if (this.lines.length == 0) {
+        currentLine = new PolyLine(position, this.color);
+        this.lines.push(currentLine);
+    } else {
+        currentLine = this.lines[this.lines.length - 1];
+    }
+
+    if (currentLine.isFull()) {
+        var newLine = new PolyLine(currentLine.getLastPoint(), this.color);
+        this.lines.push(newLine);
+        currentLine = newLine;
+    }
+
+    currentLine.enqueuePoint(position);
+
+    ++this.size;
+};
+
+InfiniteLine.prototype.dequeuePoint = function() {
+    if (this.lines.length == 0) {
+        error("Trying to dequeue from InfiniteLine when no points are left");
+        return;
+    }
+
+    var lastLine = this.lines[0];
+    lastLine.dequeuePoint();
+
+    if (lastLine.getSize() <= 1) {
+        this.lines = this.lines.slice(1);
+    }
+
+    --this.size;
+};
+
+InfiniteLine.prototype.getFirstPoint = function() {
+    return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null;
+};
+
+InfiniteLine.prototype.getLastPoint = function() {
+    return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null;
+};
+
+InfiniteLine.prototype.destroy = function() {
+    for (var i = 0; i < this.lines.length; ++i) {
+        this.lines[i].destroy();
+    }
+
+    this.size = 0;
+};

From d6230fbed329f5db5780adca536012939d035a4c Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 26 Oct 2015 10:46:36 -0700
Subject: [PATCH 165/301] Remove trailing commas in line.js

---
 examples/libraries/line.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/examples/libraries/line.js b/examples/libraries/line.js
index 62811e50bc..0834c6176e 100644
--- a/examples/libraries/line.js
+++ b/examples/libraries/line.js
@@ -26,7 +26,7 @@ var PolyLine = function(position, color, defaultStrokeWidth) {
         strokeWidths: this.strokeWidths,
         dimensions: LINE_DIMENSIONS,
         color: color,
-        lifetime: 20,
+        lifetime: 20
     });
 };
 
@@ -43,7 +43,7 @@ PolyLine.prototype.enqueuePoint = function(position) {
     Entities.editEntity(this.entityID, {
         linePoints: this.points,
         normals: this.normals,
-        strokeWidths: this.strokeWidths,
+        strokeWidths: this.strokeWidths
     });
 };
 
@@ -60,7 +60,7 @@ PolyLine.prototype.dequeuePoint = function() {
     Entities.editEntity(this.entityID, {
         linePoints: this.points,
         normals: this.normals,
-        strokeWidths: this.strokeWidths,
+        strokeWidths: this.strokeWidths
     });
 };
 

From 691e5f3be0880f54872e4143f0e2dc05891cb5d7 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 26 Oct 2015 11:07:54 -0700
Subject: [PATCH 166/301] Remove new/old value division from endpoint::apply

---
 .../src/controllers/UserInputMapper.cpp          |  4 ++--
 .../controllers/src/controllers/impl/Endpoint.h  | 12 ++++++------
 .../impl/endpoints/ActionEndpoint.cpp            |  6 +++---
 .../controllers/impl/endpoints/ActionEndpoint.h  |  4 ++--
 .../controllers/impl/endpoints/AnyEndpoint.cpp   |  2 +-
 .../src/controllers/impl/endpoints/AnyEndpoint.h |  2 +-
 .../controllers/impl/endpoints/ArrayEndpoint.h   |  4 ++--
 .../impl/endpoints/CompositeEndpoint.cpp         |  2 +-
 .../impl/endpoints/CompositeEndpoint.h           |  2 +-
 .../controllers/impl/endpoints/InputEndpoint.h   |  4 ++--
 .../src/controllers/impl/endpoints/JSEndpoint.h  |  2 +-
 .../impl/endpoints/ScriptEndpoint.cpp            | 15 +++++++--------
 .../controllers/impl/endpoints/ScriptEndpoint.h  |  4 ++--
 .../impl/endpoints/StandardEndpoint.h            | 16 ++++++++--------
 14 files changed, 39 insertions(+), 40 deletions(-)

diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 2579c7dbec..4a055e3c3f 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -529,7 +529,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
             }
         }
         // no filters yet for pose
-        destination->apply(value, Pose(), source);
+        destination->apply(value, source);
     } else {
         // Fetch the value, may have been overriden by previous loopback routes
         float value = getValue(source);
@@ -546,7 +546,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
             qCDebug(controllers) << "Filtered value was " << value;
         }
 
-        destination->apply(value, 0, source);
+        destination->apply(value, source);
     }
     return true;
 }
diff --git a/libraries/controllers/src/controllers/impl/Endpoint.h b/libraries/controllers/src/controllers/impl/Endpoint.h
index f5fe058d82..5dd3f6adb4 100644
--- a/libraries/controllers/src/controllers/impl/Endpoint.h
+++ b/libraries/controllers/src/controllers/impl/Endpoint.h
@@ -37,9 +37,9 @@ namespace controller {
 
         Endpoint(const Input& input) : _input(input) {}
         virtual float value() = 0;
-        virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
+        virtual void apply(float value, const Pointer& source) = 0;
         virtual Pose pose() { return Pose(); }
-        virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) {}
+        virtual void apply(const Pose& value, const Pointer& source) {}
         virtual const bool isPose() { return _input.isPose(); }
 
         virtual bool writeable() const { return true; }
@@ -58,7 +58,7 @@ namespace controller {
             : Endpoint(Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
 
         virtual float value() override { return _readLambda(); }
-        virtual void apply(float newValue, float oldValue, const Pointer& source) override { _writeLambda(newValue); }
+        virtual void apply(float value, const Pointer& source) override { _writeLambda(value); }
 
     private:
         ReadLambda _readLambda;
@@ -73,11 +73,11 @@ namespace controller {
         }
 
         virtual float value() override { return _currentValue; }
-        virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; }
+        virtual void apply(float value, const Pointer& source) override { _currentValue = value; }
 
         virtual Pose pose() override { return _currentPose; }
-        virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
-            _currentPose = newValue;
+        virtual void apply(const Pose& value, const Pointer& source) override {
+            _currentPose = value;
         }
     protected:
         float _currentValue { 0.0f };
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp
index d07ef38185..b671d8e93c 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.cpp
@@ -14,7 +14,7 @@
 
 using namespace controller;
 
-void ActionEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
+void ActionEndpoint::apply(float newValue, const Pointer& source) {
     _currentValue += newValue;
     if (_input != Input::INVALID_INPUT) {
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
@@ -22,8 +22,8 @@ void ActionEndpoint::apply(float newValue, float oldValue, const Pointer& source
     }
 }
 
-void ActionEndpoint::apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) {
-    _currentPose = newValue;
+void ActionEndpoint::apply(const Pose& value, const Pointer& source) {
+    _currentPose = value;
     if (!_currentPose.isValid()) {
         return;
     }
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h
index eaae1e3798..574fdcedb5 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h
@@ -24,10 +24,10 @@ public:
     ActionEndpoint(const Input& id = Input::INVALID_INPUT) : Endpoint(id) { }
 
     virtual float value() override { return _currentValue; }
-    virtual void apply(float newValue, float oldValue, const Pointer& source) override;
+    virtual void apply(float newValue, const Pointer& source) override;
 
     virtual Pose pose() override { return _currentPose; }
-    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override;
+    virtual void apply(const Pose& value, const Pointer& source) override;
 
     virtual void reset() override;
 
diff --git a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
index b3310e4424..24f3479ea8 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
@@ -38,7 +38,7 @@ float AnyEndpoint::value() {
     return result;
 }
 
-void AnyEndpoint::apply(float newValue, float oldValue, const Endpoint::Pointer& source) {
+void AnyEndpoint::apply(float newValue, const Endpoint::Pointer& source) {
     qFatal("AnyEndpoint is read only");
 }
 
diff --git a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
index 25db6a5a2a..86dd057414 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
@@ -19,7 +19,7 @@ class AnyEndpoint : public Endpoint {
 public:
     AnyEndpoint(Endpoint::List children);
     virtual float value() override;
-    virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override;
+    virtual void apply(float newValue, const Endpoint::Pointer& source) override;
     virtual bool writeable() const override;
     virtual bool readable() const override;
 
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
index 676f43868a..79bb604ec0 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
@@ -24,10 +24,10 @@ public:
         return 0.0;
     }
 
-    virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
+    virtual void apply(float value, const Endpoint::Pointer& source) override {
         for (auto& child : _children) {
             if (child->writeable()) {
-                child->apply(newValue, oldValue, source);
+                child->apply(value, source);
             }
         }
     }
diff --git a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
index 9d89a7d2b3..e5088ef72c 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
@@ -25,7 +25,7 @@ float CompositeEndpoint::value() {
     return result;
 }
 
-void CompositeEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
+void CompositeEndpoint::apply(float newValue, const Pointer& source) {
     // Composites are read only
 }
 
diff --git a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
index b525a2e4ab..ab8b97aa50 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
@@ -18,7 +18,7 @@ namespace controller {
         CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second);
 
         virtual float value() override;
-        virtual void apply(float newValue, float oldValue, const Pointer& source) override;
+        virtual void apply(float newValue, const Pointer& source) override;
     };
 
 }
diff --git a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h
index 195cd33683..d58f0c2e73 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h
@@ -22,9 +22,9 @@ public:
 
     virtual float value() override;
     // FIXME need support for writing back to vibration / force feedback effects
-    virtual void apply(float newValue, float oldValue, const Pointer& source) override {}
+    virtual void apply(float newValue, const Pointer& source) override {}
     virtual Pose pose() override;
-    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
+    virtual void apply(const Pose& value, const Pointer& source) override { }
 
     virtual bool writeable() const { return false; }
     virtual bool readable() const { return !_read; }
diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
index 38ac92bfb6..27f17b5cd3 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
@@ -28,7 +28,7 @@ public:
         return result;
     }
 
-    virtual void apply(float newValue, float oldValue, const Pointer& source) {
+    virtual void apply(float newValue, const Pointer& source) {
         _callable.call(QJSValueList({ QJSValue(newValue) }));
     }
 
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
index 069bcb3c00..d9b4a5fc59 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
@@ -26,22 +26,21 @@ void ScriptEndpoint::updateValue() {
     _lastValueRead = (float)_callable.call().toNumber();
 }
 
-void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
-    if (newValue == _lastValueWritten) {
+void ScriptEndpoint::apply(float value, const Pointer& source) {
+    if (value == _lastValueWritten) {
         return;
     }
-    internalApply(newValue, oldValue, source->getInput().getID());
+    internalApply(value, source->getInput().getID());
 }
 
-void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID) {
-    _lastValueWritten = newValue;
+void ScriptEndpoint::internalApply(float value, int sourceID) {
+    _lastValueWritten = value;
     if (QThread::currentThread() != thread()) {
         QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
-            Q_ARG(float, newValue),
-            Q_ARG(float, oldValue),
+            Q_ARG(float, value),
             Q_ARG(int, sourceID));
         return;
     }
     _callable.call(QScriptValue(),
-        QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) }));
+        QScriptValueList({ QScriptValue(value), QScriptValue(sourceID) }));
 }
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
index a56ac472be..23f77892c6 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
@@ -24,11 +24,11 @@ public:
     }
 
     virtual float value();
-    virtual void apply(float newValue, float oldValue, const Pointer& source);
+    virtual void apply(float newValue, const Pointer& source);
 
 protected:
     Q_INVOKABLE void updateValue();
-    Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID);
+    Q_INVOKABLE virtual void internalApply(float newValue, int sourceID);
 private:
     QScriptValue _callable;
     float _lastValueRead { 0.0f };
diff --git a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h
index 44803a22fd..74adaf825d 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h
@@ -20,8 +20,8 @@ public:
     virtual bool writeable() const override { return !_written; }
     virtual bool readable() const override { return !_read; }
     virtual void reset() override {
-        apply(0.0f, 0.0f, Endpoint::Pointer());
-        apply(Pose(), Pose(), Endpoint::Pointer());
+        apply(0.0f, Endpoint::Pointer());
+        apply(Pose(), Endpoint::Pointer());
         _written = _read = false;
     }
 
@@ -30,12 +30,12 @@ public:
         return VirtualEndpoint::value();
     }
 
-    virtual void apply(float newValue, float oldValue, const Pointer& source) override {
+    virtual void apply(float value, const Pointer& source) override {
         // For standard endpoints, the first NON-ZERO write counts.
-        if (newValue != 0.0) {
+        if (value != 0.0) {
             _written = true;
         }
-        VirtualEndpoint::apply(newValue, oldValue, source);
+        VirtualEndpoint::apply(value, source);
     }
 
     virtual Pose pose() override {
@@ -43,11 +43,11 @@ public:
         return VirtualEndpoint::pose();
     }
 
-    virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
-        if (newValue != Pose()) {
+    virtual void apply(const Pose& value, const Pointer& source) override {
+        if (value != Pose()) {
             _written = true;
         }
-        VirtualEndpoint::apply(newValue, oldValue, source);
+        VirtualEndpoint::apply(value, source);
     }
 
 private:

From a8872d065b2b4aa680b49b86b99680b43e8c31a0 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Mon, 26 Oct 2015 11:23:13 -0700
Subject: [PATCH 167/301] MOve the movingAverage class to shared next to
 SimpleMovingAverage

---
 .../src/input-plugins/SixenseManager.h        | 27 ++----------------
 libraries/shared/src/SimpleMovingAverage.h    | 28 +++++++++++++++++++
 2 files changed, 30 insertions(+), 25 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index b9ca9d8479..c6b938c774 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -24,6 +24,8 @@
 
 #endif
 
+#include <SimpleMovingAverage.h>
+
 #include <controllers/InputDevice.h>
 #include <controllers/StandardControls.h>
 
@@ -95,31 +97,6 @@ private:
     float _lastDistance;
     bool _useSixenseFilter = true;
 
-    template <class T, int MAX_NUM_SAMPLES> class MovingAverage {
-    public:
-        using Samples = std::list< T >;
-        Samples samples;
-        T average;
-
-        void clear() {
-            samples.clear();
-        }
-
-        bool isAverageValid() const { return !samples.empty(); }
-
-        void addSample(T sample) {
-            samples.push_front(sample);
-            int numSamples = samples.size();
-
-            if (numSamples < MAX_NUM_SAMPLES) {
-                average = (sample + average * float(numSamples - 1)) / float(numSamples);
-            } else {
-                T tail = samples.back();
-                samples.pop_back();
-                average = average + (sample - tail) / float(numSamples);
-            }
-        }
-    };
 
     static const int MAX_NUM_AVERAGING_SAMPLES = 50; // At ~100 updates per seconds this means averaging over ~.5s
     using Samples = std::pair<  MovingAverage< glm::vec3, MAX_NUM_AVERAGING_SAMPLES>, MovingAverage< glm::vec4, MAX_NUM_AVERAGING_SAMPLES> >;
diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h
index 194a078194..5f4e7367fc 100644
--- a/libraries/shared/src/SimpleMovingAverage.h
+++ b/libraries/shared/src/SimpleMovingAverage.h
@@ -15,6 +15,7 @@
 #define hifi_SimpleMovingAverage_h
 
 #include <stdint.h>
+#include <list>
 
 class SimpleMovingAverage {
 public:
@@ -40,4 +41,31 @@ private:
     float ONE_MINUS_WEIGHTING;
 };
 
+
+template <class T, int MAX_NUM_SAMPLES> class MovingAverage {
+public:
+    using Samples = std::list< T >;
+    Samples samples;
+    T average;
+
+    void clear() {
+        samples.clear();
+    }
+
+    bool isAverageValid() const { return !samples.empty(); }
+
+    void addSample(T sample) {
+        samples.push_front(sample);
+        int numSamples = samples.size();
+
+        if (numSamples < MAX_NUM_SAMPLES) {
+            average = (sample + average * (float)(numSamples - 1)) / (float)(numSamples);
+        } else {
+            T tail = samples.back();
+            samples.pop_back();
+            average = average + (sample - tail) / (float)(numSamples);
+        }
+    }
+};
+
 #endif // hifi_SimpleMovingAverage_h

From 34b517839373a212fdcca1b0096e0ba80af5f23a Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 26 Oct 2015 11:55:23 -0700
Subject: [PATCH 168/301] Fixing ping-ping entity script

---
 examples/toybox/ping_pong_gun/pingPongGun.js | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/examples/toybox/ping_pong_gun/pingPongGun.js b/examples/toybox/ping_pong_gun/pingPongGun.js
index 879d467293..48b82f0a36 100644
--- a/examples/toybox/ping_pong_gun/pingPongGun.js
+++ b/examples/toybox/ping_pong_gun/pingPongGun.js
@@ -45,6 +45,12 @@
         green: 255,
         blue: 255
     };
+    
+    var TRIGGER_CONTROLS = [
+        Controller.Standard.LT,
+        Controller.Standard.RT,
+    ];
+    
 
     PingPongGun.prototype = {
         hand: null,
@@ -53,11 +59,11 @@
         canShoot: false,
         canShootTimeout: null,
         setRightHand: function() {
-            this.hand = 'RIGHT';
+            this.hand = 1;
         },
 
         setLeftHand: function() {
-            this.hand = 'LEFT';
+            this.hand = 0;
         },
 
         startNearGrab: function() {
@@ -92,12 +98,7 @@
         },
 
         checkTriggerPressure: function(gunHand) {
-            var handClickString = gunHand + "_HAND_CLICK";
-
-            var handClick = Controller.findAction(handClickString);
-
-            this.triggerValue = Controller.getActionValue(handClick);
-
+            this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[gunHand]);
             if (this.triggerValue < RELOAD_THRESHOLD) {
                 // print('RELOAD');
                 this.canShoot = true;

From d91d0a20271c0ffdc063e37ea20c59b9080c7815 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Mon, 26 Oct 2015 12:47:31 -0700
Subject: [PATCH 169/301] Fixing spray can script

---
 examples/toybox/spray_paint/sprayPaintCan.js | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/examples/toybox/spray_paint/sprayPaintCan.js b/examples/toybox/spray_paint/sprayPaintCan.js
index 4e6719af76..60fd12b975 100644
--- a/examples/toybox/spray_paint/sprayPaintCan.js
+++ b/examples/toybox/spray_paint/sprayPaintCan.js
@@ -33,12 +33,17 @@
     var MIN_POINT_DISTANCE = 0.01;
     var STROKE_WIDTH = 0.02;
 
+    var TRIGGER_CONTROLS = [
+        Controller.Standard.LT,
+        Controller.Standard.RT,
+    ];
+    
     this.setRightHand = function () {
-        this.hand = 'RIGHT';
+        this.hand = 1;
     }
 
     this.setLeftHand = function () {
-        this.hand = 'LEFT';
+        this.hand = 0;
     }
 
     this.startNearGrab = function () {
@@ -46,11 +51,7 @@
     }
 
     this.toggleWithTriggerPressure = function () {
-        var handClickString = this.whichHand + "_HAND_CLICK";
-
-        var handClick = Controller.findAction(handClickString);
-
-        this.triggerValue = Controller.getActionValue(handClick);
+        this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.whichHand]);
         if (this.triggerValue < DISABLE_SPRAY_THRESHOLD && this.spraying === true) {
             this.spraying = false;
             this.disableStream();

From 837430329b2df0aae07d1608933d1fa3e8a34dba Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 26 Oct 2015 13:02:17 -0700
Subject: [PATCH 170/301] Fix collision start/end in single physics simulation
 to be lost

---
 libraries/physics/src/PhysicsEngine.cpp           | 9 ++++++---
 libraries/physics/src/ThreadSafeDynamicsWorld.cpp | 3 ++-
 libraries/physics/src/ThreadSafeDynamicsWorld.h   | 6 +++++-
 3 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp
index 75273e62ba..1e87fc9a5d 100644
--- a/libraries/physics/src/PhysicsEngine.cpp
+++ b/libraries/physics/src/PhysicsEngine.cpp
@@ -251,7 +251,12 @@ void PhysicsEngine::stepSimulation() {
         _characterController->preSimulation(timeStep);
     }
 
-    int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, PHYSICS_ENGINE_MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
+    auto onSubStep = [this]() {
+        updateContactMap();
+        _hasOutgoingChanges = true;
+    };
+
+    int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, PHYSICS_ENGINE_MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP, onSubStep);
     if (numSubsteps > 0) {
         BT_PROFILE("postSimulation");
         _numSubsteps += (uint32_t)numSubsteps;
@@ -260,8 +265,6 @@ void PhysicsEngine::stepSimulation() {
         if (_characterController) {
             _characterController->postSimulation();
         }
-        updateContactMap();
-        _hasOutgoingChanges = true;
     }
 }
 
diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
index b59103339c..8bf7cdab20 100644
--- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
+++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
@@ -27,7 +27,7 @@ ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
     :   btDiscreteDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration) {
 }
 
-int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep) {
+int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep, SubStepCallback onSubStep) {
     BT_PROFILE("stepSimulation");
     int subSteps = 0;
     if (maxSubSteps) {
@@ -70,6 +70,7 @@ int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps,
 
         for (int i=0;i<clampedSimulationSteps;i++) {
             internalSingleStepSimulation(fixedTimeStep);
+            onSubStep();
         }
     }
 
diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h
index eacc8ad74a..1f6ce09d0c 100644
--- a/libraries/physics/src/ThreadSafeDynamicsWorld.h
+++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h
@@ -23,6 +23,10 @@
 
 #include "ObjectMotionState.h"
 
+#include <functional>
+
+using SubStepCallback = std::function<void()>;
+
 ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld {
 public:
     BT_DECLARE_ALIGNED_ALLOCATOR();
@@ -34,7 +38,7 @@ public:
             btCollisionConfiguration* collisionConfiguration);
 
     // virtual overrides from btDiscreteDynamicsWorld
-    int stepSimulation( btScalar timeStep, int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.));
+    int stepSimulation( btScalar timeStep, int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.), SubStepCallback onSubStep = []() { });
     void synchronizeMotionStates();
 
     // btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated

From 913026280c082a0d7df6311a1136ca95e45afac1 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 26 Oct 2015 13:02:39 -0700
Subject: [PATCH 171/301] Fix EntityTreeRenderer dropping contact end events

---
 libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index d5bf0bde8a..bed6ae1d0f 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -774,7 +774,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
     }
     // Don't respond to small continuous contacts.
     const float COLLISION_MINUMUM_PENETRATION = 0.002f;
-    if ((collision.type != CONTACT_EVENT_TYPE_START) && (glm::length(collision.penetration) < COLLISION_MINUMUM_PENETRATION)) {
+    if ((collision.type == CONTACT_EVENT_TYPE_CONTINUE) && (glm::length(collision.penetration) < COLLISION_MINUMUM_PENETRATION)) {
         return;
     }
 

From 990764d85577ed5f9e167b3fab91bbb6f1176407 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Mon, 26 Oct 2015 13:29:13 -0700
Subject: [PATCH 172/301] Really fixing the MovingAverage class...

---
 libraries/shared/src/SimpleMovingAverage.h | 22 +++++++++-------------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h
index 5f4e7367fc..53754ae241 100644
--- a/libraries/shared/src/SimpleMovingAverage.h
+++ b/libraries/shared/src/SimpleMovingAverage.h
@@ -15,7 +15,6 @@
 #define hifi_SimpleMovingAverage_h
 
 #include <stdint.h>
-#include <list>
 
 class SimpleMovingAverage {
 public:
@@ -44,27 +43,24 @@ private:
 
 template <class T, int MAX_NUM_SAMPLES> class MovingAverage {
 public:
-    using Samples = std::list< T >;
-    Samples samples;
+    const float WEIGHTING = 1.0f / (float)MAX_NUM_SAMPLES;
+    const float ONE_MINUS_WEIGHTING = 1.0f - WEIGHTING;
+    int numSamples{ 0 };
     T average;
 
     void clear() {
-        samples.clear();
+        numSamples = 0;
     }
 
-    bool isAverageValid() const { return !samples.empty(); }
+    bool isAverageValid() const { return (numSamples > 0); }
 
     void addSample(T sample) {
-        samples.push_front(sample);
-        int numSamples = samples.size();
-
-        if (numSamples < MAX_NUM_SAMPLES) {
-            average = (sample + average * (float)(numSamples - 1)) / (float)(numSamples);
+        if (numSamples > 0) {
+            average = (sample * WEIGHTING) + (average * ONE_MINUS_WEIGHTING);
         } else {
-            T tail = samples.back();
-            samples.pop_back();
-            average = average + (sample - tail) / (float)(numSamples);
+            average = sample;
         }
+        numSamples++;
     }
 };
 

From f5d12ee2c60a139cbde514d3a398cdbe098f60f3 Mon Sep 17 00:00:00 2001
From: black plastick <blackplastick@hifi.cloudmin.lenoir.fapvps.com>
Date: Mon, 26 Oct 2015 17:46:08 -0400
Subject: [PATCH 173/301] Added AvatarList script events for assigment client
 scripts:     AvatarList.avatarAddedEvent(sessionUUID);    
 AvatarList.avatarRemovedEvent(sessionUUID);

---
 assignment-client/src/avatars/AvatarMixer.cpp | 4 ++--
 libraries/avatars/src/AvatarHashMap.cpp       | 4 +++-
 libraries/avatars/src/AvatarHashMap.h         | 4 ++++
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp
index 833b53b729..ae6a8247c1 100644
--- a/assignment-client/src/avatars/AvatarMixer.cpp
+++ b/assignment-client/src/avatars/AvatarMixer.cpp
@@ -254,10 +254,10 @@ void AvatarMixer::broadcastAvatarData() {
                     // potentially update the max full rate distance for this frame
                     maxAvatarDistanceThisFrame = std::max(maxAvatarDistanceThisFrame, distanceToAvatar);
 
-                    if (distanceToAvatar != 0.0f
+		                        if (distanceToAvatar != 0.0f
                         && distribution(generator) > (nodeData->getFullRateDistance() / distanceToAvatar)) {
                         return;
-                    }
+			}
 
                     AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID());
                     AvatarDataSequenceNumber lastSeqFromSender = otherNodeData->getLastReceivedSequenceNumber();
diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp
index 520bb34887..c02fe98b19 100644
--- a/libraries/avatars/src/AvatarHashMap.cpp
+++ b/libraries/avatars/src/AvatarHashMap.cpp
@@ -44,7 +44,7 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe
     avatar->setSessionUUID(sessionUUID);
     avatar->setOwningAvatarMixer(mixerWeakPointer);
     _avatarHash.insert(sessionUUID, avatar);
-
+    emit avatarAddedEvent(sessionUUID);
     return avatar;
 }
 
@@ -131,10 +131,12 @@ void AvatarHashMap::processKillAvatar(QSharedPointer<NLPacket> packet, SharedNod
     // read the node id
     QUuid sessionUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
     removeAvatar(sessionUUID);
+
 }
 
 void AvatarHashMap::removeAvatar(const QUuid& sessionUUID) {
     _avatarHash.remove(sessionUUID);
+    emit avatarRemovedEvent(sessionUUID);
 }
 
 void AvatarHashMap::sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID) {
diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h
index 804233b76a..f90c61ec4d 100644
--- a/libraries/avatars/src/AvatarHashMap.h
+++ b/libraries/avatars/src/AvatarHashMap.h
@@ -33,6 +33,10 @@ public:
     const AvatarHash& getAvatarHash() { return _avatarHash; }
     int size() { return _avatarHash.size(); }
 
+signals:
+    void avatarAddedEvent(const QUuid& sessionUUID);
+    void avatarRemovedEvent(const QUuid& sessionUUID);
+
 public slots:
     bool isAvatarInRange(const glm::vec3 & position, const float range);
     

From 1a1ab29978e04302fb49aff32a2afcfd3611b147 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 26 Oct 2015 16:45:43 -0700
Subject: [PATCH 174/301] Add lineExample.js

---
 examples/example/lineExample.js | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 examples/example/lineExample.js

diff --git a/examples/example/lineExample.js b/examples/example/lineExample.js
new file mode 100644
index 0000000000..6642e499fb
--- /dev/null
+++ b/examples/example/lineExample.js
@@ -0,0 +1,12 @@
+Script.include("../libraries/line.js");
+
+var basePosition = MyAvatar.position;
+var line = new InfiniteLine(basePosition);
+
+for (var i = 0; i < (16 * Math.PI); i += 0.05) {
+    var x = 0
+    var y = 0.25 * Math.sin(i);
+    var z = i / 10;
+
+    line.enqueuePoint(Vec3.sum(basePosition, { x: x, y: y, z: z }));
+}

From 2abb6a2fd5921f474a999eba368296fb00def4b4 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 26 Oct 2015 16:45:58 -0700
Subject: [PATCH 175/301] Clean up line.js

---
 examples/libraries/line.js | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/examples/libraries/line.js b/examples/libraries/line.js
index 0834c6176e..991b691ae8 100644
--- a/examples/libraries/line.js
+++ b/examples/libraries/line.js
@@ -8,15 +8,12 @@ var MAX_LINE_LENGTH = 40; // This must be 2 or greater;
 var PolyLine = function(position, color, defaultStrokeWidth) {
     this.position = position;
     this.color = color;
-    this.defaultStrokeWidth = 0.10;
+    this.defaultStrokeWidth = defaultStrokeWidth;
     this.points = [
-        { x: 0, y: 0, z: 0 }
     ];
     this.strokeWidths = [
-        this.defaultStrokeWidth
     ];
     this.normals = [
-        { x: 1, y: 0, z: 0 }
     ]
     this.entityID = Entities.addEntity({
         type: "PolyLine",
@@ -39,7 +36,7 @@ PolyLine.prototype.enqueuePoint = function(position) {
     position = Vec3.subtract(position, this.position);
     this.points.push(position);
     this.normals.push({ x: 1, y: 0, z: 0 });
-    this.strokeWidths.push(this.defaultStrokeWidth * Math.min(1.0, this.points.length / 10));
+    this.strokeWidths.push(this.defaultStrokeWidth);
     Entities.editEntity(this.entityID, {
         linePoints: this.points,
         normals: this.normals,
@@ -91,7 +88,7 @@ PolyLine.prototype.destroy = function() {
 InfiniteLine = function(position, color) {
     this.position = position;
     this.color = color;
-    this.lines = [new PolyLine(position, color)];
+    this.lines = [new PolyLine(position, color, 0.01)];
     this.size = 0;
 };
 
@@ -99,14 +96,15 @@ InfiniteLine.prototype.enqueuePoint = function(position) {
     var currentLine;
 
     if (this.lines.length == 0) {
-        currentLine = new PolyLine(position, this.color);
+        currentLine = new PolyLine(position, this.color, 0.01);
         this.lines.push(currentLine);
     } else {
         currentLine = this.lines[this.lines.length - 1];
     }
 
     if (currentLine.isFull()) {
-        var newLine = new PolyLine(currentLine.getLastPoint(), this.color);
+        var newLine = new PolyLine(currentLine.getLastPoint(), this.color, 0.01);
+        newLine.enqueuePoint(currentLine.getLastPoint());
         this.lines.push(newLine);
         currentLine = newLine;
     }

From 5bce95189b5a0716185d8a134f00ad468e7b66dc Mon Sep 17 00:00:00 2001
From: AlessandroSigna <alesigna92@gmail.com>
Date: Mon, 26 Oct 2015 18:14:57 -0700
Subject: [PATCH 176/301] fix keyboard mapping (keyboardMouse.js)

---
 .../resources/controllers/keyboardMouse.json  | 51 ++++++++++++++-----
 1 file changed, 38 insertions(+), 13 deletions(-)

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
index 7b9a8d733a..6ea1c42b1e 100644
--- a/interface/resources/controllers/keyboardMouse.json
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -1,28 +1,53 @@
 {
     "name": "Keyboard/Mouse to Actions",
     "channels": [
-        { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, 
-        { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, 
-        { "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" }, 
-        { "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" }, 
+        { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
+        { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
+        { "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
+        { "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" },
+        { "from": "Keyboard.E", "when": "Keyboard.Shift", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.05 } ] },
+        { "from": "Keyboard.C", "when": "Keyboard.Shift", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.05 } ] },
+        { "from": "Keyboard.S", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" },
+        { "from": "Keyboard.W", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" },
 
         { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
-        { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" }, 
-        { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" }, 
-        { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" }, 
+        { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
+        { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" },
+        { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" },
         { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
         { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
 
+        { "from": "Keyboard.Left", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
+        { "from": "Keyboard.Right", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" },
+        { "from": "Keyboard.Left", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
+        { "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
+        { "from": "Keyboard.Down", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" },
+        { "from": "Keyboard.Up", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" },
+
         { "from": "Keyboard.Up", "to": "Actions.LONGITUDINAL_FORWARD" },
-        { "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" }, 
-        { "from": "Keyboard.Left", "to": "Actions.YAW_LEFT" }, 
-        { "from": "Keyboard.Right", "to": "Actions.YAW_RIGHT" }, 
+        { "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" },
+        { "from": "Keyboard.Left", "to": "Actions.YAW_LEFT" },
+        { "from": "Keyboard.Right", "to": "Actions.YAW_RIGHT" },
         { "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
         { "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },
 
-        { "from": "Keyboard.MouseMoveLeft", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_LEFT" }, 
-        { "from": "Keyboard.MouseMoveRight", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_RIGHT" }, 
+        { "from": "Keyboard.MouseMoveLeft", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_LEFT" },
+        { "from": "Keyboard.MouseMoveRight", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_RIGHT" },
         { "from": "Keyboard.MouseMoveUp", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_UP" },
-        { "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_DOWN" }
+        { "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_DOWN" },
+
+        { "from": "Keyboard.TouchpadDown", "to": "Actions.PITCH_DOWN" },
+        { "from": "Keyboard.TouchpadUp", "to": "Actions.PITCH_UP" },
+        { "from": "Keyboard.TouchpadLeft", "to": "Actions.YAW_LEFT" },
+        { "from": "Keyboard.TouchpadRight", "to": "Actions.YAW_RIGHT" },
+
+        { "from": "Keyboard.MouseWheelUp", "to": "Actions.LATERAL_RIGHT" },
+        { "from": "Keyboard.MouseWheelDown", "to": "Actions.LATERAL_LEFT" },
+        { "from": "Keyboard.MouseWheelLeft", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.02 } ]},
+        { "from": "Keyboard.MouseWheelRight", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.02 } ]},
+
+        { "from": "Keyboard.Space", "to": "Actions.SHIFT" },
+        { "from": "Keyboard.R", "to": "Actions.ACTION1" },
+        { "from": "Keyboard.T", "to": "Actions.ACTION2" }
     ]
 }

From d34fc35544fa38715d1990f0e09f3201c1f68679 Mon Sep 17 00:00:00 2001
From: black plastick <blackplastick@yahoo.com>
Date: Tue, 27 Oct 2015 08:11:20 -0400
Subject: [PATCH 177/301] added AvatarList.avatarSessionChanged(sessionUUID,
 oldUUID) for AC scripts.

---
 assignment-client/src/avatars/AvatarMixer.cpp | 6 +++---
 libraries/avatars/src/AvatarHashMap.cpp       | 1 +
 libraries/avatars/src/AvatarHashMap.h         | 1 +
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp
index ae6a8247c1..0a455891f9 100644
--- a/assignment-client/src/avatars/AvatarMixer.cpp
+++ b/assignment-client/src/avatars/AvatarMixer.cpp
@@ -254,10 +254,10 @@ void AvatarMixer::broadcastAvatarData() {
                     // potentially update the max full rate distance for this frame
                     maxAvatarDistanceThisFrame = std::max(maxAvatarDistanceThisFrame, distanceToAvatar);
 
-		                        if (distanceToAvatar != 0.0f
+		    if (distanceToAvatar != 0.0f
                         && distribution(generator) > (nodeData->getFullRateDistance() / distanceToAvatar)) {
-                        return;
-			}
+		      return;
+		    }
 
                     AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID());
                     AvatarDataSequenceNumber lastSeqFromSender = otherNodeData->getLastReceivedSequenceNumber();
diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp
index c02fe98b19..ddc9160041 100644
--- a/libraries/avatars/src/AvatarHashMap.cpp
+++ b/libraries/avatars/src/AvatarHashMap.cpp
@@ -141,4 +141,5 @@ void AvatarHashMap::removeAvatar(const QUuid& sessionUUID) {
 
 void AvatarHashMap::sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID) {
     _lastOwnerSessionUUID = oldUUID;
+    emit avatarSessionChangedEvent(sessionUUID, oldUUID);
 }
diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h
index f90c61ec4d..c0c511bc3a 100644
--- a/libraries/avatars/src/AvatarHashMap.h
+++ b/libraries/avatars/src/AvatarHashMap.h
@@ -36,6 +36,7 @@ public:
 signals:
     void avatarAddedEvent(const QUuid& sessionUUID);
     void avatarRemovedEvent(const QUuid& sessionUUID);
+    void avatarSessionChangedEvent(const QUuid& sessionUUID,const QUuid& oldUUID);
 
 public slots:
     bool isAvatarInRange(const glm::vec3 & position, const float range);

From 983c551ce35c0ff5c153d31fa4294a89f38d422c Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Tue, 27 Oct 2015 09:13:16 -0700
Subject: [PATCH 178/301] Clean up line.js and make lifetime settable

---
 examples/example/lineExample.js |  7 +++++--
 examples/libraries/line.js      | 27 +++++++++++++++------------
 2 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/examples/example/lineExample.js b/examples/example/lineExample.js
index 6642e499fb..e6c3d90cba 100644
--- a/examples/example/lineExample.js
+++ b/examples/example/lineExample.js
@@ -1,12 +1,15 @@
 Script.include("../libraries/line.js");
 
 var basePosition = MyAvatar.position;
-var line = new InfiniteLine(basePosition);
+var color = { red: 128, green: 220, blue: 190 };
+var strokeWidth = 0.01;
+var line = new InfiniteLine(basePosition, color, 20);
 
 for (var i = 0; i < (16 * Math.PI); i += 0.05) {
     var x = 0
     var y = 0.25 * Math.sin(i);
     var z = i / 10;
 
-    line.enqueuePoint(Vec3.sum(basePosition, { x: x, y: y, z: z }));
+    var position = Vec3.sum(basePosition, { x: x, y: y, z: z });
+    line.enqueuePoint(position, strokeWidth);
 }
diff --git a/examples/libraries/line.js b/examples/libraries/line.js
index 991b691ae8..77cb13c124 100644
--- a/examples/libraries/line.js
+++ b/examples/libraries/line.js
@@ -5,10 +5,13 @@ function error(message) {
 // PolyLine
 var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 };
 var MAX_LINE_LENGTH = 40; // This must be 2 or greater;
-var PolyLine = function(position, color, defaultStrokeWidth) {
+var DEFAULT_STROKE_WIDTH = 0.1;
+var DEFAULT_LIFETIME = 20;
+var DEFAULT_COLOR = { red: 255, green: 255, blue: 255 };
+var PolyLine = function(position, color, lifetime) {
     this.position = position;
     this.color = color;
-    this.defaultStrokeWidth = defaultStrokeWidth;
+    this.lifetime = lifetime === undefined ? DEFAULT_LIFETIME : lifetime;
     this.points = [
     ];
     this.strokeWidths = [
@@ -23,11 +26,11 @@ var PolyLine = function(position, color, defaultStrokeWidth) {
         strokeWidths: this.strokeWidths,
         dimensions: LINE_DIMENSIONS,
         color: color,
-        lifetime: 20
+        lifetime: lifetime
     });
 };
 
-PolyLine.prototype.enqueuePoint = function(position) {
+PolyLine.prototype.enqueuePoint = function(position, strokeWidth) {
     if (this.isFull()) {
         error("Hit max PolyLine size");
         return;
@@ -36,7 +39,7 @@ PolyLine.prototype.enqueuePoint = function(position) {
     position = Vec3.subtract(position, this.position);
     this.points.push(position);
     this.normals.push({ x: 1, y: 0, z: 0 });
-    this.strokeWidths.push(this.defaultStrokeWidth);
+    this.strokeWidths.push(strokeWidth);
     Entities.editEntity(this.entityID, {
         linePoints: this.points,
         normals: this.normals,
@@ -83,33 +86,33 @@ PolyLine.prototype.destroy = function() {
 };
 
 
-
 // InfiniteLine
-InfiniteLine = function(position, color) {
+InfiniteLine = function(position, color, lifetime) {
     this.position = position;
     this.color = color;
+    this.lifetime = lifetime === undefined ? DEFAULT_LIFETIME : lifetime;
     this.lines = [new PolyLine(position, color, 0.01)];
     this.size = 0;
 };
 
-InfiniteLine.prototype.enqueuePoint = function(position) {
+InfiniteLine.prototype.enqueuePoint = function(position, strokeWidth) {
     var currentLine;
 
     if (this.lines.length == 0) {
-        currentLine = new PolyLine(position, this.color, 0.01);
+        currentLine = new PolyLine(position, this.color, this.lifetime);
         this.lines.push(currentLine);
     } else {
         currentLine = this.lines[this.lines.length - 1];
     }
 
     if (currentLine.isFull()) {
-        var newLine = new PolyLine(currentLine.getLastPoint(), this.color, 0.01);
-        newLine.enqueuePoint(currentLine.getLastPoint());
+        var newLine = new PolyLine(currentLine.getLastPoint(), this.color, this.lifetime);
+        newLine.enqueuePoint(currentLine.getLastPoint(), strokeWidth);
         this.lines.push(newLine);
         currentLine = newLine;
     }
 
-    currentLine.enqueuePoint(position);
+    currentLine.enqueuePoint(position, strokeWidth);
 
     ++this.size;
 };

From 2cd2af2b13421341224910654921e9413bccd6f6 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Tue, 27 Oct 2015 09:49:52 -0700
Subject: [PATCH 179/301] Add headers to line.js and lineExample.js

---
 examples/example/lineExample.js | 11 +++++++++++
 examples/libraries/line.js      | 11 +++++++++++
 2 files changed, 22 insertions(+)

diff --git a/examples/example/lineExample.js b/examples/example/lineExample.js
index e6c3d90cba..d424d4f9f3 100644
--- a/examples/example/lineExample.js
+++ b/examples/example/lineExample.js
@@ -1,3 +1,14 @@
+//
+//  lineExample.js
+//  examples/example
+//
+//  Created by Ryan Huffman on October 27, 2015
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
 Script.include("../libraries/line.js");
 
 var basePosition = MyAvatar.position;
diff --git a/examples/libraries/line.js b/examples/libraries/line.js
index 77cb13c124..d31a34867b 100644
--- a/examples/libraries/line.js
+++ b/examples/libraries/line.js
@@ -1,3 +1,14 @@
+//
+//  line.js
+//  examples/libraries
+//
+//  Created by Ryan Huffman on October 27, 2015
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
 function error(message) {
     print("[ERROR] " + message);
 }

From 87cf3b237b37bd91ae638cf922693b1479ae5394 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 27 Oct 2015 09:59:22 -0700
Subject: [PATCH 180/301] Supporting a InHMD action and using it to enable
 COmfort mode

---
 interface/resources/controllers/standard.json  |  1 +
 interface/src/Application.cpp                  |  8 ++++++++
 .../controllers/src/controllers/Actions.cpp    |  2 ++
 .../controllers/src/controllers/Actions.h      |  2 ++
 .../src/controllers/UserInputMapper.cpp        | 18 ++++++++++++------
 .../src/controllers/UserInputMapper.h          |  2 ++
 6 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 5d6e8ce32f..20177bfc5e 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -3,6 +3,7 @@
     "channels": [
         { "from": "Standard.LY", "to": "Actions.TranslateZ" },
         { "from": "Standard.LX", "to": "Actions.TranslateX" },
+        { "from": "Standard.RX", "with": "Actions.InHMD", "to": "Actions.StepYaw" },
         { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
 
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 92680ed3e0..c1257e1279 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2703,6 +2703,9 @@ void Application::update(float deltaTime) {
 
     auto myAvatar = getMyAvatar();
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    // Reflect some state into the Actions of the UserInpuMapper
+    userInputMapper->resetActionState(controller::Action::IN_HMD, (float)qApp->getAvatarUpdater()->isHMDMode());
+
     userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
     userInputMapper->update(deltaTime);
 
@@ -2738,6 +2741,11 @@ void Application::update(float deltaTime) {
         }
         myAvatar->setDriveKeys(ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z));
     }
+
+    float lhc = userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK);
+    if (lhc != 0.0f) {
+        std::cout << "Left Hand click = " << lhc << std::endl;
+    }
     controller::Pose leftHand = userInputMapper->getPoseState(controller::Action::LEFT_HAND);
     controller::Pose rightHand = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);
     Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp
index a9bd32b1d8..979c8a70c1 100644
--- a/libraries/controllers/src/controllers/Actions.cpp
+++ b/libraries/controllers/src/controllers/Actions.cpp
@@ -75,6 +75,8 @@ namespace controller {
                 makeAxisPair(Action::BOOM_IN, "BoomIn"),
                 makeAxisPair(Action::BOOM_OUT, "BoomOut"),
 
+                makeButtonPair(Action::IN_HMD, "InHMD"),
+
                 // Deprecated aliases
                 // FIXME remove after we port all scripts
                 makeAxisPair(Action::LONGITUDINAL_BACKWARD, "LONGITUDINAL_BACKWARD"),
diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h
index 47f04141f3..187fcd46a0 100644
--- a/libraries/controllers/src/controllers/Actions.h
+++ b/libraries/controllers/src/controllers/Actions.h
@@ -78,6 +78,8 @@ enum class Action {
     BOOM_IN,
     BOOM_OUT,
 
+    IN_HMD, // THis is a read only action ?
+
     NUM_ACTIONS,
 };
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 2579c7dbec..3d957cbf35 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -953,19 +953,17 @@ Mapping::Pointer UserInputMapper::parseMapping(const QString& json) {
     QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error);
     // check validity of the document
     if (doc.isNull()) {
+        qDebug() << "Invalid JSON...\n";
+        qDebug() << error.errorString();
+        qDebug() << "JSON was:\n" << json << endl;
         return Mapping::Pointer();
     }
 
     if (!doc.isObject()) {
         qWarning() << "Mapping json Document is not an object" << endl;
+        qDebug() << "JSON was:\n" << json << endl;
         return Mapping::Pointer();
     }
-
-    // FIXME how did we detect this?
-    //    qDebug() << "Invalid JSON...\n";
-    //    qDebug() << error.errorString();
-    //    qDebug() << "JSON was:\n" << json << endl;
-    //}
     return parseMapping(doc.object());
 }
 
@@ -1019,5 +1017,13 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
     }
 }
 
+void UserInputMapper::resetActionState(Action action, float value) {
+    auto endpoint = endpointFor(inputFromAction(action));
+    if (endpoint) {
+        endpoint->apply(value, 0.0f, Endpoint::Pointer());
+    }
+    _actionStates[toInt(action)] = value;
+}
+
 }
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 0a6ed3acad..40fe26aff3 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -84,7 +84,9 @@ namespace controller {
         Pose getPoseState(Action action) const { return _poseStates[toInt(action)]; }
         int findAction(const QString& actionName) const;
         QVector<QString> getActionNames() const;
+        Input inputFromAction(Action action) const { return getActionInputs()[toInt(action)].first; }
 
+        void resetActionState(Action action, float value);
         void setActionState(Action action, float value) { _actionStates[toInt(action)] = value; }
         void deltaActionState(Action action, float delta) { _actionStates[toInt(action)] += delta; }
         void setActionState(Action action, const Pose& value) { _poseStates[toInt(action)] = value; }

From 8a85468254d5cdbbc79a38528ed4e78cf25453eb Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Tue, 27 Oct 2015 10:39:44 -0700
Subject: [PATCH 181/301] changing model, repositioning

---
 .../whiteboard/whiteboardEntityScript.js      |   2 +-
 .../painting/whiteboard/whiteboardSpawner.js  | 241 ++++++++----------
 2 files changed, 107 insertions(+), 136 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js
index f38073f389..2d34fc8c40 100644
--- a/examples/painting/whiteboard/whiteboardEntityScript.js
+++ b/examples/painting/whiteboard/whiteboardEntityScript.js
@@ -239,7 +239,7 @@
         unload: function() {
 
             Overlays.deleteOverlay(this.laserPointer);
-            // this.eraseBoard();
+            this.eraseBoard();
         }
 
     };
diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index cbc26da670..0804b992c7 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -16,13 +16,16 @@
 
 Script.include("../../libraries/utils.js");
 var scriptURL = Script.resolvePath("whiteboardEntityScript.js");
+//var modelURL = "https://hifi-public.s3.amazonaws.com/ozan/support/for_eric/whiteboard/whiteboard.fbx";
+var modelURL = "http://localhost:8080/whiteboard.fbx?v1" + Math.random();
 var rotation = Quat.safeEulerAngles(Camera.getOrientation());
 rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
 var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(rotation)));
-center.y += 0.4;
+
+var whiteboardDimensions, colorIndicator, eraseAllText
+var colorBoxes = [];
 
 var colors = [
-    hexToRgb("#2F8E84"),
     hexToRgb("#66CCB3"),
     hexToRgb("#A43C37"),
     hexToRgb("#491849"),
@@ -30,21 +33,13 @@ var colors = [
     hexToRgb("#993369"),
     hexToRgb("#9B47C2")
 ];
-
-//WHITEBOARD
-var whiteboardDimensions = {
-    x: 2,
-    y: 1.5,
-    z: 0.08
-};
 var whiteboard = Entities.addEntity({
     type: "Model",
-    modelURL: "https://hifi-public.s3.amazonaws.com/ozan/support/for_eric/whiteboard/whiteboard.fbx",
+    modelURL: modelURL,
     name: "whiteboard",
     position: center,
     rotation: rotation,
     script: scriptURL,
-    dimensions: whiteboardDimensions,
     color: {
         red: 255,
         green: 255,
@@ -52,144 +47,119 @@ var whiteboard = Entities.addEntity({
     }
 });
 
+Script.setTimeout(function() {
+    whiteboardDimensions = Entities.getEntityProperties(whiteboard, "naturalDimensions").naturalDimensions;
+    setUp();
+}, 500)
 
-// COLOR INDICATOR BOX
-var colorIndicatorDimensions = {
-    x: whiteboardDimensions.x,
-    y: 0.05,
-    z: 0.02
-};
-scriptURL = Script.resolvePath("colorIndicatorEntityScript.js");
-var colorIndicatorPosition = Vec3.sum(center, {
-    x: 0,
-    y: whiteboardDimensions.y / 2 + colorIndicatorDimensions.y / 2,
-    z: 0
-});
-var colorIndicatorBox = Entities.addEntity({
-    type: "Box",
-    name: "Color Indicator",
-    color: colors[0],
-    rotation: rotation,
-    position: colorIndicatorPosition,
-    dimensions: colorIndicatorDimensions,
-    script: scriptURL,
-    userData: JSON.stringify({
-        whiteboard: whiteboard
-    })
-});
 
-Entities.editEntity(whiteboard, {
-    userData: JSON.stringify({
-        color: {
-            currentColor: colors[0]
-        },
-        colorIndicator: colorIndicatorBox
-    })
-});
-
-//COLOR BOXES
-var direction = Quat.getRight(rotation);
-var colorBoxPosition = Vec3.subtract(center, Vec3.multiply(direction, whiteboardDimensions.x / 2));
-var colorBoxes = [];
-var colorSquareDimensions = {
-    x: (whiteboardDimensions.x / 2) / (colors.length - 1),
-    y: 0.1,
-    z: 0.05
-};
-colorBoxPosition.y += whiteboardDimensions.y / 2 + colorIndicatorDimensions.y + colorSquareDimensions.y / 2;
-var spaceBetweenColorBoxes = Vec3.multiply(direction, colorSquareDimensions.x * 2);
-var scriptURL = Script.resolvePath("colorSelectorEntityScript.js");
-for (var i = 0; i < colors.length; i++) {
-    var colorBox = Entities.addEntity({
+function setUp() {
+    // COLOR INDICATOR BOX
+    var colorIndicatorDimensions = {
+        x: whiteboardDimensions.x,
+        y: 0.05,
+        z: 0.02
+    };
+    scriptURL = Script.resolvePath("colorIndicatorEntityScript.js");
+    var colorIndicatorPosition = Vec3.sum(center, {
+        x: 0,
+        y: whiteboardDimensions.y / 2 + colorIndicatorDimensions.y / 2,
+        z: 0
+    });
+    colorIndicatorBox = Entities.addEntity({
         type: "Box",
-        name: "Color Selector",
-        position: colorBoxPosition,
-        dimensions: colorSquareDimensions,
+        name: "Color Indicator",
+        color: colors[0],
         rotation: rotation,
-        color: colors[i],
+        position: colorIndicatorPosition,
+        dimensions: colorIndicatorDimensions,
         script: scriptURL,
         userData: JSON.stringify({
-            whiteboard: whiteboard,
+            whiteboard: whiteboard
+        })
+    });
+
+    Entities.editEntity(whiteboard, {
+        userData: JSON.stringify({
+            color: {
+                currentColor: colors[0]
+            },
             colorIndicator: colorIndicatorBox
         })
     });
-    colorBoxes.push(colorBox);
-    colorBoxPosition = Vec3.sum(colorBoxPosition, spaceBetweenColorBoxes);
+
+    //COLOR BOXES
+    var direction = Quat.getRight(rotation);
+    var colorBoxPosition = Vec3.subtract(center, Vec3.multiply(direction, whiteboardDimensions.x / 2));
+    var colorSquareDimensions = {
+        x: 0.1,
+        y: 0.1,
+        z: 0.002
+    };
+    colorBoxPosition.y += whiteboardDimensions.y / 2 + colorIndicatorDimensions.y + colorSquareDimensions.y / 2;
+    var spaceBetweenColorBoxes = Vec3.multiply(direction, colorSquareDimensions.x * 2);
+    var scriptURL = Script.resolvePath("colorSelectorEntityScript.js");
+    for (var i = 0; i < colors.length; i++) {
+        var colorBox = Entities.addEntity({
+            type: "Box",
+            name: "Color Selector",
+            position: colorBoxPosition,
+            dimensions: colorSquareDimensions,
+            rotation: rotation,
+            color: colors[i],
+            script: scriptURL,
+            userData: JSON.stringify({
+                whiteboard: whiteboard,
+                colorIndicator: colorIndicatorBox
+            })
+        });
+        colorBoxes.push(colorBox);
+        colorBoxPosition = Vec3.sum(colorBoxPosition, spaceBetweenColorBoxes);
+    }
+
+
+
+    var eraseBoxDimensions = {
+        x: 0.5,
+        y: 0.1,
+        z: 0.01
+    };
+
+
+    var eraseBoxPosition = Vec3.sum(center, Vec3.multiply(direction, whiteboardDimensions.x / 2 + eraseBoxDimensions.x / 2 + 0.01));
+    eraseBoxPosition.y += 0.3;
+    scriptURL = Script.resolvePath("eraseBoardEntityScript.js");
+    eraseAllText = Entities.addEntity({
+        type: "Text",
+        position: eraseBoxPosition,
+        name: "Eraser",
+        script: scriptURL,
+        rotation: rotation,
+        dimensions: eraseBoxDimensions,
+        backgroundColor: {
+            red: 0,
+            green: 60,
+            blue: 0
+        },
+        textColor: {
+            red: 255,
+            green: 10,
+            blue: 10
+        },
+        text: "ERASE BOARD",
+        lineHeight: 0.07,
+        userData: JSON.stringify({
+            whiteboard: whiteboard
+        })
+    });
+
+
+
 }
 
-
-// BLACK BOX
-var blackBoxDimensions = {
-    x: 0.3,
-    y: 0.3,
-    z: 0.01
-};
-
-colorBoxPosition = Vec3.subtract(center, Vec3.multiply(direction, whiteboardDimensions.x / 2 + blackBoxDimensions.x / 2 - 0.01));
-colorBoxPosition.y += 0.3;
-var fragShaderURL = Script.resolvePath('blackInk.fs?v1' + Math.random());
-var blackBox = Entities.addEntity({
-    type: 'Box',
-    name: "Black Color",
-    position: colorBoxPosition,
-    dimensions: blackBoxDimensions,
-    rotation: rotation,
-    color: {
-        red: 0,
-        green: 0,
-        blue: 0
-    },
-    script: scriptURL,
-    userData: JSON.stringify({
-        whiteboard: whiteboard,
-        version: 2,
-        ProceduralEntity: {
-            shaderUrl: fragShaderURL
-        }
-    })
-});
-
-
-var eraseBoxDimensions = {
-    x: 0.5,
-    y: 0.1,
-    z: 0.01
-};
-
-
-var eraseBoxPosition = Vec3.sum(center, Vec3.multiply(direction, whiteboardDimensions.x / 2 + eraseBoxDimensions.x / 2 + 0.01));
-eraseBoxPosition.y += 0.3;
-scriptURL = Script.resolvePath("eraseBoardEntityScript.js");
-var eraseAllText = Entities.addEntity({
-    type: "Text",
-    position: eraseBoxPosition,
-    name: "Eraser",
-    script: scriptURL,
-    rotation: rotation,
-    dimensions: eraseBoxDimensions,
-    backgroundColor: {
-        red: 0,
-        green: 60,
-        blue: 0
-    },
-    textColor: {
-        red: 255,
-        green: 10,
-        blue: 10
-    },
-    text: "ERASE BOARD",
-    lineHeight: 0.07,
-    userData: JSON.stringify({
-        whiteboard: whiteboard
-    })
-});
-
-
-
 function cleanup() {
     Entities.deleteEntity(whiteboard);
     Entities.deleteEntity(eraseAllText);
-    Entities.deleteEntity(blackBox);
     Entities.deleteEntity(colorIndicatorBox);
     colorBoxes.forEach(function(colorBox) {
         Entities.deleteEntity(colorBox);
@@ -197,5 +167,6 @@ function cleanup() {
 }
 
 
+
 // Uncomment this line to delete whiteboard and all associated entity on script close
 Script.scriptEnding.connect(cleanup);
\ No newline at end of file

From 596b315286bdf2de3ce0d627756f5c0a468a2d95 Mon Sep 17 00:00:00 2001
From: EdgarPironti <pacepiro@hotmail.it>
Date: Tue, 27 Oct 2015 11:35:30 -0700
Subject: [PATCH 182/301] Fixed standard.json

---
 interface/resources/controllers/standard.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 5d6e8ce32f..8ba9056076 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -6,7 +6,7 @@
         { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
 
-        { "from": [ "Standard.DU", "Standard.DU", "Standard.DU", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
+        { "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
         { "from": "Standard.Back", "to": "Standard.LeftSecondaryThumb" },
 
         { "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" },

From fa22249f7a25a822791a20ae186829ef11630713 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Tue, 27 Oct 2015 12:03:30 -0700
Subject: [PATCH 183/301] Improving model

---
 .../painting/whiteboard/whiteboardSpawner.js    | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 0804b992c7..2de9821810 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -31,7 +31,7 @@ var colors = [
     hexToRgb("#491849"),
     hexToRgb("#6AB03B"),
     hexToRgb("#993369"),
-    hexToRgb("#9B47C2")
+    hexToRgb("#000000")
 ];
 var whiteboard = Entities.addEntity({
     type: "Model",
@@ -92,12 +92,19 @@ function setUp() {
     var direction = Quat.getRight(rotation);
     var colorBoxPosition = Vec3.subtract(center, Vec3.multiply(direction, whiteboardDimensions.x / 2));
     var colorSquareDimensions = {
-        x: 0.1,
-        y: 0.1,
+        x: 0.13,
+        y: 0.13,
         z: 0.002
     };
-    colorBoxPosition.y += whiteboardDimensions.y / 2 + colorIndicatorDimensions.y + colorSquareDimensions.y / 2;
-    var spaceBetweenColorBoxes = Vec3.multiply(direction, colorSquareDimensions.x * 2);
+
+    var palleteDepthOffset = -0.06;
+    var palleteHeightOffset = -0.28;
+
+    colorBoxPosition = Vec3.sum(colorBoxPosition, Vec3.multiply(palleteDepthOffset, Quat.getFront(rotation)));
+    colorBoxPosition.y += palleteHeightOffset;
+    var spaceBetweenColorBoxes = Vec3.multiply(direction, colorSquareDimensions.x * 1.76);
+    var palleteXOffset = Vec3.multiply(direction, 0.43);
+    colorBoxPosition = Vec3.sum(colorBoxPosition, palleteXOffset);
     var scriptURL = Script.resolvePath("colorSelectorEntityScript.js");
     for (var i = 0; i < colors.length; i++) {
         var colorBox = Entities.addEntity({

From f0a1335957aa0a80d61ecca1ddf98f03c4b03c4d Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Tue, 27 Oct 2015 12:09:07 -0700
Subject: [PATCH 184/301] fixed paint initially showing up white

---
 examples/painting/whiteboard/whiteboardSpawner.js | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 2de9821810..6a4f800441 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -44,7 +44,12 @@ var whiteboard = Entities.addEntity({
         red: 255,
         green: 255,
         blue: 255
-    }
+    },
+    userData: JSON.stringify({
+        color: {
+            currentColor: colors[0]
+        }
+    })
 });
 
 Script.setTimeout(function() {

From 8fcc07102699807e6eee5392c6765df9076e3ade Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Tue, 27 Oct 2015 12:24:29 -0700
Subject: [PATCH 185/301] only can draw on whiteboard

---
 .../painting/whiteboard/whiteboardSpawner.js  | 33 ++++++++++++-------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 6a4f800441..366aa2b73d 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -33,24 +33,32 @@ var colors = [
     hexToRgb("#993369"),
     hexToRgb("#000000")
 ];
+
 var whiteboard = Entities.addEntity({
     type: "Model",
     modelURL: modelURL,
-    name: "whiteboard",
+    name: "whiteboard base",
     position: center,
     rotation: rotation,
+});
+
+var surfaceCenter = Vec3.sum(center, Vec3.multiply(-0.1, Quat.getFront(rotation)));
+surfaceCenter.y +=  0.55;
+var drawingSurface = Entities.addEntity({
+    type: "Box",
+    color: {red: 255, green: 255, blue: 255},
+    name: "whiteboard surface",
+    position: surfaceCenter,
+    dimensions: {x: 1.8, y: 1.4, z: 0.01},
     script: scriptURL,
-    color: {
-        red: 255,
-        green: 255,
-        blue: 255
-    },
-    userData: JSON.stringify({
+    rotation: rotation, 
+     userData: JSON.stringify({
         color: {
             currentColor: colors[0]
         }
     })
-});
+
+})
 
 Script.setTimeout(function() {
     whiteboardDimensions = Entities.getEntityProperties(whiteboard, "naturalDimensions").naturalDimensions;
@@ -80,11 +88,11 @@ function setUp() {
         dimensions: colorIndicatorDimensions,
         script: scriptURL,
         userData: JSON.stringify({
-            whiteboard: whiteboard
+            whiteboard: drawingSurface
         })
     });
 
-    Entities.editEntity(whiteboard, {
+    Entities.editEntity(drawingSurface, {
         userData: JSON.stringify({
             color: {
                 currentColor: colors[0]
@@ -121,7 +129,7 @@ function setUp() {
             color: colors[i],
             script: scriptURL,
             userData: JSON.stringify({
-                whiteboard: whiteboard,
+                whiteboard: drawingSurface,
                 colorIndicator: colorIndicatorBox
             })
         });
@@ -161,7 +169,7 @@ function setUp() {
         text: "ERASE BOARD",
         lineHeight: 0.07,
         userData: JSON.stringify({
-            whiteboard: whiteboard
+            whiteboard: drawingSurface
         })
     });
 
@@ -171,6 +179,7 @@ function setUp() {
 
 function cleanup() {
     Entities.deleteEntity(whiteboard);
+    Entities.deleteEntity(drawingSurface);
     Entities.deleteEntity(eraseAllText);
     Entities.deleteEntity(colorIndicatorBox);
     colorBoxes.forEach(function(colorBox) {

From 25ded2bd9212f5c26a5285c64a79e8195fd18e16 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Tue, 27 Oct 2015 13:03:44 -0700
Subject: [PATCH 186/301] added shapetype

---
 examples/painting/whiteboard/whiteboardSpawner.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 366aa2b73d..a7cfc0719a 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -36,6 +36,7 @@ var colors = [
 
 var whiteboard = Entities.addEntity({
     type: "Model",
+    shapeType: "box",
     modelURL: modelURL,
     name: "whiteboard base",
     position: center,

From 0512da0e3971c21c57cb5c8e1233e3ba801004b2 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Tue, 27 Oct 2015 13:07:11 -0700
Subject: [PATCH 187/301] updated url

---
 examples/painting/whiteboard/whiteboardSpawner.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index a7cfc0719a..16953129af 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -17,7 +17,8 @@
 Script.include("../../libraries/utils.js");
 var scriptURL = Script.resolvePath("whiteboardEntityScript.js");
 //var modelURL = "https://hifi-public.s3.amazonaws.com/ozan/support/for_eric/whiteboard/whiteboard.fbx";
-var modelURL = "http://localhost:8080/whiteboard.fbx?v1" + Math.random();
+//var modelURL = "http://localhost:8080/whiteboard.fbx?v1" + Math.random();
+var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx";
 var rotation = Quat.safeEulerAngles(Camera.getOrientation());
 rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
 var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(rotation)));

From ed6a866ff9dddc7b6cf1aee39bdaf9b3f52e1eda Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Tue, 27 Oct 2015 13:43:13 -0700
Subject: [PATCH 188/301] ready for demo

---
 examples/painting/whiteboard/whiteboardEntityScript.js | 2 +-
 examples/painting/whiteboard/whiteboardSpawner.js      | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js
index 2d34fc8c40..f38073f389 100644
--- a/examples/painting/whiteboard/whiteboardEntityScript.js
+++ b/examples/painting/whiteboard/whiteboardEntityScript.js
@@ -239,7 +239,7 @@
         unload: function() {
 
             Overlays.deleteOverlay(this.laserPointer);
-            this.eraseBoard();
+            // this.eraseBoard();
         }
 
     };
diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 16953129af..82d7f63239 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -17,7 +17,7 @@
 Script.include("../../libraries/utils.js");
 var scriptURL = Script.resolvePath("whiteboardEntityScript.js");
 //var modelURL = "https://hifi-public.s3.amazonaws.com/ozan/support/for_eric/whiteboard/whiteboard.fbx";
-//var modelURL = "http://localhost:8080/whiteboard.fbx?v1" + Math.random();
+// var modelURL = "http://localhost:8080/whiteboard.fbx?v1" + Math.random();
 var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx";
 var rotation = Quat.safeEulerAngles(Camera.getOrientation());
 rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
@@ -192,4 +192,4 @@ function cleanup() {
 
 
 // Uncomment this line to delete whiteboard and all associated entity on script close
-Script.scriptEnding.connect(cleanup);
\ No newline at end of file
+// Script.scriptEnding.connect(cleanup);
\ No newline at end of file

From d67f4958cdab2d60d2b7e08654e5b62667fbcb20 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Tue, 27 Oct 2015 13:44:29 -0700
Subject: [PATCH 189/301] wait longer for dimensions

---
 examples/painting/whiteboard/whiteboardSpawner.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 82d7f63239..4303803266 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -65,7 +65,7 @@ var drawingSurface = Entities.addEntity({
 Script.setTimeout(function() {
     whiteboardDimensions = Entities.getEntityProperties(whiteboard, "naturalDimensions").naturalDimensions;
     setUp();
-}, 500)
+}, 1000)
 
 
 function setUp() {

From 5a42991e0ccd075100c2da985f7d67925fd076c5 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Tue, 27 Oct 2015 12:30:34 -0700
Subject: [PATCH 190/301] first pass at cleaning up MyAvatars use of PalmData

---
 interface/src/Application.cpp                 | 165 ++++++++++--------
 interface/src/Application.h                   |  15 +-
 interface/src/avatar/Avatar.cpp               |  32 ----
 interface/src/avatar/Avatar.h                 |   6 +-
 interface/src/avatar/Hand.cpp                 |  18 +-
 interface/src/avatar/MyAvatar.cpp             |  76 +++-----
 interface/src/avatar/MyAvatar.h               |   4 +-
 interface/src/avatar/SkeletonModel.cpp        |  46 +++--
 interface/src/avatar/SkeletonModel.h          |   2 +-
 .../ControllerScriptingInterface.cpp          |  45 -----
 .../scripting/ControllerScriptingInterface.h  |   5 -
 interface/src/ui/ApplicationCompositor.cpp    |  15 +-
 libraries/avatars/src/HandData.cpp            |  33 ++--
 libraries/avatars/src/HandData.h              |  73 +++-----
 14 files changed, 213 insertions(+), 322 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 92680ed3e0..910cbb19e2 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2741,13 +2741,13 @@ void Application::update(float deltaTime) {
     controller::Pose leftHand = userInputMapper->getPoseState(controller::Action::LEFT_HAND);
     controller::Pose rightHand = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);
     Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
-    setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK));
-    setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK));
+    setPalmData(hand, leftHand, deltaTime, HandData::LeftHand, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK));
+    setPalmData(hand, rightHand, deltaTime, HandData::RightHand, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK));
     if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
         emulateMouse(hand, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK),
-            userInputMapper->getActionState(controller::Action::SHIFT), LEFT_HAND_INDEX);
+            userInputMapper->getActionState(controller::Action::SHIFT), HandData::LeftHand);
         emulateMouse(hand, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK),
-            userInputMapper->getActionState(controller::Action::SHIFT), RIGHT_HAND_INDEX);
+            userInputMapper->getActionState(controller::Action::SHIFT), HandData::RightHand);
     }
 
     updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
@@ -4805,86 +4805,101 @@ mat4 Application::getHMDSensorPose() const {
     return mat4();
 }
 
-void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue) {
-    PalmData* palm;
-    bool foundHand = false;
-    for (size_t j = 0; j < hand->getNumPalms(); j++) {
-        if (hand->getPalms()[j].getSixenseID() == index) {
-            palm = &(hand->getPalms()[j]);
-            foundHand = true;
-            break;
+void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue) {
+
+    // NOTE: the Hand::modifyPalms() will allow the lambda to modify the palm data while ensuring some other user isn't
+    // reading or writing to the Palms. This is definitely not the best way of handling this, and I'd like to see more
+    // of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about
+    // controller::Pose. More work is needed to clean this up.
+    hand->modifyPalms([&](std::vector<PalmData>& palms) {
+        auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
+        PalmData* palm;
+        bool foundHand = false;
+
+        // FIXME - this little chuck of code is a hot mess. It's basically searching the palms
+        // for the one that matches the "sixenseID" that is the "index" parameter. If it 
+        // doesn't find it, then it creates a new palm and sets that palm's ID this really
+        // can and should be inside the HandData class
+        for (size_t j = 0; j < palms.size(); j++) {
+            if (palms[j].whichHand() == whichHand) {
+                palm = &(palms[j]);
+                foundHand = true;
+                break;
+            }
+        }
+        if (!foundHand) {
+            PalmData newPalm(hand);
+            palms.push_back(newPalm);
+            palm = &(palms[palms.size() - 1]); // FIXME - lame
+            palm->setHand(whichHand);
         }
-    }
-    if (!foundHand) {
-        PalmData newPalm(hand);
-        hand->getPalms().push_back(newPalm);
-        palm = &(hand->getPalms()[hand->getNumPalms() - 1]);
-        palm->setSixenseID(index);
-    }
     
-    palm->setActive(pose.isValid());
+        palm->setActive(pose.isValid());
 
-    // transform from sensor space, to world space, to avatar model space.
-    glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation());
-    glm::mat4 sensorToWorldMat = getMyAvatar()->getSensorToWorldMatrix();
-    glm::mat4 modelMat = createMatFromQuatAndPos(getMyAvatar()->getOrientation(), getMyAvatar()->getPosition());
-    glm::mat4 objectPose = glm::inverse(modelMat) * sensorToWorldMat * poseMat;
+        // transform from sensor space, to world space, to avatar model space.
+        glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation());
+        glm::mat4 sensorToWorldMat = myAvatar->getSensorToWorldMatrix();
+        glm::mat4 modelMat = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition());
+        glm::mat4 objectPose = glm::inverse(modelMat) * sensorToWorldMat * poseMat;
 
-    glm::vec3 position = extractTranslation(objectPose);
-    glm::quat rotation = glm::quat_cast(objectPose);
+        glm::vec3 position = extractTranslation(objectPose);
+        glm::quat rotation = glm::quat_cast(objectPose);
 
-    //  Compute current velocity from position change
-    glm::vec3 rawVelocity;
-    if (deltaTime > 0.0f) {
-        rawVelocity = (position - palm->getRawPosition()) / deltaTime;
-    } else {
-        rawVelocity = glm::vec3(0.0f);
-    }
-    palm->setRawVelocity(rawVelocity);   //  meters/sec
+        //  Compute current velocity from position change
+        glm::vec3 rawVelocity;
+        if (deltaTime > 0.0f) {
+            rawVelocity = (position - palm->getRawPosition()) / deltaTime;
+        } else {
+            rawVelocity = glm::vec3(0.0f);
+        }
+        palm->setRawVelocity(rawVelocity);   //  meters/sec
     
-    //  Angular Velocity of Palm
-    glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation());
-    glm::vec3 angularVelocity(0.0f);
-    float rotationAngle = glm::angle(deltaRotation);
-    if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) {
-        angularVelocity = glm::normalize(glm::axis(deltaRotation));
-        angularVelocity *= (rotationAngle / deltaTime);
-        palm->setRawAngularVelocity(angularVelocity);
-    } else {
-        palm->setRawAngularVelocity(glm::vec3(0.0f));
-    }
+        //  Angular Velocity of Palm
+        glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation());
+        glm::vec3 angularVelocity(0.0f);
+        float rotationAngle = glm::angle(deltaRotation);
+        if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) {
+            angularVelocity = glm::normalize(glm::axis(deltaRotation));
+            angularVelocity *= (rotationAngle / deltaTime);
+            palm->setRawAngularVelocity(angularVelocity);
+        } else {
+            palm->setRawAngularVelocity(glm::vec3(0.0f));
+        }
 
-    if (controller::InputDevice::getLowVelocityFilter()) {
-        //  Use a velocity sensitive filter to damp small motions and preserve large ones with
-        //  no latency.
-        float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
-        position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
-        rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter);
-    }
-    palm->setRawPosition(position);
-    palm->setRawRotation(rotation);
+        if (controller::InputDevice::getLowVelocityFilter()) {
+            //  Use a velocity sensitive filter to damp small motions and preserve large ones with
+            //  no latency.
+            float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
+            position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
+            rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter);
+        }
+        palm->setRawPosition(position);
+        palm->setRawRotation(rotation);
 
-    // Store the one fingertip in the palm structure so we can track velocity
-    const float FINGER_LENGTH = 0.3f;   //  meters
-    const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f);
-    const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
-    glm::vec3 oldTipPosition = palm->getTipRawPosition();
-    if (deltaTime > 0.0f) {
-        palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
-    } else {
-        palm->setTipVelocity(glm::vec3(0.0f));
-    }
-    palm->setTipPosition(newTipPosition);
-    palm->setTrigger(triggerValue);
+        // Store the one fingertip in the palm structure so we can track velocity
+        const float FINGER_LENGTH = 0.3f;   //  meters
+        const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f);
+        const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
+        glm::vec3 oldTipPosition = palm->getTipRawPosition();
+        if (deltaTime > 0.0f) {
+            palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
+        } else {
+            palm->setTipVelocity(glm::vec3(0.0f));
+        }
+        palm->setTipPosition(newTipPosition);
+        palm->setTrigger(triggerValue);
+    });
 }
 
-void Application::emulateMouse(Hand* hand, float click, float shift, int index) {
+void Application::emulateMouse(Hand* hand, float click, float shift, HandData::Hand whichHand) {
+    auto palms = hand->getCopyOfPalms();
+
     // Locate the palm, if it exists and is active
     PalmData* palm;
     bool foundHand = false;
-    for (size_t j = 0; j < hand->getNumPalms(); j++) {
-        if (hand->getPalms()[j].getSixenseID() == index) {
-            palm = &(hand->getPalms()[j]);
+    for (size_t j = 0; j < palms.size(); j++) {
+        if (palms[j].whichHand() == whichHand) {
+            palm = &(palms[j]);
             foundHand = true;
             break;
         }
@@ -4896,12 +4911,14 @@ void Application::emulateMouse(Hand* hand, float click, float shift, int index)
     // Process the mouse events
     QPoint pos;
 
-    unsigned int deviceID = index == 0 ? CONTROLLER_0_EVENT : CONTROLLER_1_EVENT;
+
+    // FIXME - this mouse emulation stuff needs to be reworked for new controller input plugins
+    unsigned int deviceID = whichHand == HandData::LeftHand ? CONTROLLER_0_EVENT : CONTROLLER_1_EVENT;
+    int index = (int)whichHand; // FIXME - hack attack
 
     if (isHMDMode()) {
         pos = getApplicationCompositor().getPalmClickLocation(palm);
-    }
-    else {
+    } else {
         // Get directon relative to avatar orientation
         glm::vec3 direction = glm::inverse(getMyAvatar()->getOrientation()) * palm->getFingerDirection();
 
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 75cc418e94..301eb3b262 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -352,8 +352,8 @@ private:
 
     void update(float deltaTime);
 
-    void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue);
-    void emulateMouse(Hand* hand, float click, float shift, int index);
+    void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue);
+    void emulateMouse(Hand* hand, float click, float shift, HandData::Hand whichHand);
 
     // Various helper functions called during update()
     void updateLOD();
@@ -522,10 +522,13 @@ private:
     ApplicationCompositor _compositor;
     OverlayConductor _overlayConductor;
 
-    int _oldHandMouseX[2];
-    int _oldHandMouseY[2];
-    bool _oldHandLeftClick[2];
-    bool _oldHandRightClick[2];
+
+    // FIXME - Hand Controller to mouse emulation helpers. This is crufty and should be moved
+    // into the input plugins or something.
+    int _oldHandMouseX[(int)HandData::NUMBER_OF_HANDS];
+    int _oldHandMouseY[(int)HandData::NUMBER_OF_HANDS];
+    bool _oldHandLeftClick[(int)HandData::NUMBER_OF_HANDS];
+    bool _oldHandRightClick[(int)HandData::NUMBER_OF_HANDS];
 
     DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface();
 
diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp
index 9f4e7ee3cf..8c29ce1a41 100644
--- a/interface/src/avatar/Avatar.cpp
+++ b/interface/src/avatar/Avatar.cpp
@@ -1177,22 +1177,6 @@ glm::vec3 Avatar::getLeftPalmPosition() {
     return leftHandPosition;
 }
 
-glm::vec3 Avatar::getLeftPalmVelocity() {
-    const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
-    if (palm != NULL) {
-        return palm->getVelocity();
-    }
-    return glm::vec3(0.0f);
-}
-
-glm::vec3 Avatar::getLeftPalmAngularVelocity() {
-    const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
-    if (palm != NULL) {
-        return palm->getRawAngularVelocity();
-    }
-    return glm::vec3(0.0f);
-}
-
 glm::quat Avatar::getLeftPalmRotation() {
     glm::quat leftRotation;
     getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
@@ -1208,22 +1192,6 @@ glm::vec3 Avatar::getRightPalmPosition() {
     return rightHandPosition;
 }
 
-glm::vec3 Avatar::getRightPalmVelocity() {
-    const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
-    if (palm != NULL) {
-        return palm->getVelocity();
-    }
-    return glm::vec3(0.0f);
-}
-
-glm::vec3 Avatar::getRightPalmAngularVelocity() {
-    const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
-    if (palm != NULL) {
-        return palm->getRawAngularVelocity();
-    }
-    return glm::vec3(0.0f);
-}
-
 glm::quat Avatar::getRightPalmRotation() {
     glm::quat rightRotation;
     getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h
index 6a1f216089..44b5d91015 100644
--- a/interface/src/avatar/Avatar.h
+++ b/interface/src/avatar/Avatar.h
@@ -160,13 +160,11 @@ public:
     AvatarMotionState* getMotionState() { return _motionState; }
 
 public slots:
+
+    // FIXME - these should be migrated to use Pose data instead
     glm::vec3 getLeftPalmPosition();
-    glm::vec3 getLeftPalmVelocity();
-    glm::vec3 getLeftPalmAngularVelocity();
     glm::quat getLeftPalmRotation();
     glm::vec3 getRightPalmPosition();
-    glm::vec3 getRightPalmVelocity();
-    glm::vec3 getRightPalmAngularVelocity();
     glm::quat getRightPalmRotation();
 
 protected:
diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp
index 0eeb7222b6..dfac5e393f 100644
--- a/interface/src/avatar/Hand.cpp
+++ b/interface/src/avatar/Hand.cpp
@@ -31,13 +31,7 @@ Hand::Hand(Avatar* owningAvatar) :
 }
 
 void Hand::simulate(float deltaTime, bool isMine) {
-    if (isMine) {
-        //  Iterate hand controllers, take actions as needed
-        for (size_t i = 0; i < getNumPalms(); ++i) {
-            PalmData& palm = getPalms()[i];
-            palm.setLastControllerButtons(palm.getControllerButtons());
-        }
-    }
+    // nothing to do here
 }
 
 void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
@@ -53,10 +47,12 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
     const glm::vec3 grayColor(0.5f);
     const float SPHERE_RADIUS = 0.03f * avatarScale;
 
+    auto palms = getCopyOfPalms();
+
     gpu::Batch& batch = *renderArgs->_batch;
     if (isMine) {
-        for (size_t i = 0; i < getNumPalms(); i++) {
-            PalmData& palm = getPalms()[i];
+        for (size_t i = 0; i < palms.size(); i++) {
+            PalmData& palm = palms[i];
             if (!palm.isActive()) {
                 continue;
             }
@@ -82,8 +78,8 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
     const float AXIS_LENGTH = 10.0f * SPHERE_RADIUS;
 
     // Draw the coordinate frames of the hand targets
-    for (size_t i = 0; i < getNumPalms(); ++i) {
-        PalmData& palm = getPalms()[i];
+    for (size_t i = 0; i < palms.size(); ++i) {
+        PalmData& palm = palms[i];
         if (palm.isActive()) {
             glm::vec3 root = palm.getPosition();
 
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 6e08ca24cf..5483219318 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -554,74 +554,76 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
 // first active controller. If you have both controllers held up or just the left, that
 // will be correct. But if you lift the right controller, then it will be reported
 // as "left"... you also see this in the avatars hands. 
-const PalmData* MyAvatar::getActivePalm(int palmIndex) const {
-    const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
-    int numberOfPalms = handData->getNumPalms();
+PalmData MyAvatar::getActivePalmData(int palmIndex) const {
+    auto palms = getHandData()->getCopyOfPalms();
+
+    int numberOfPalms = palms.size();
     int numberOfActivePalms = 0;
     for (int i = 0; i < numberOfPalms; i++) {
-        auto palm = handData->getPalms()[i];
+        auto palm = palms[i];
         if (palm.isActive()) {
             // if we've reached the requested "active" palm, then we will return it
             if (numberOfActivePalms == palmIndex) {
-                return &handData->getPalms()[i];
+                return palm;
             }
             numberOfActivePalms++;
         }
     }
-    return NULL;
+    PalmData noData(nullptr);
+    return noData;
 }
 
 
 glm::vec3 MyAvatar::getLeftHandPosition() const {
     const int LEFT_HAND = 0;
-    auto palmData = getActivePalm(LEFT_HAND);
-    return palmData ? palmData->getPosition() : glm::vec3(0.0f);
+    auto palmData = getActivePalmData(LEFT_HAND);
+    return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
 }
 
 glm::vec3 MyAvatar::getRightHandPosition() const {
     const int RIGHT_HAND = 1;
-    auto palmData = getActivePalm(RIGHT_HAND);
-    return palmData ? palmData->getPosition() : glm::vec3(0.0f);
+    auto palmData = getActivePalmData(RIGHT_HAND);
+    return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
 }
 
 glm::vec3 MyAvatar::getLeftHandTipPosition() const {
     const int LEFT_HAND = 0;
-    auto palmData = getActivePalm(LEFT_HAND);
-    return palmData ? palmData->getTipPosition() : glm::vec3(0.0f);
+    auto palmData = getActivePalmData(LEFT_HAND);
+    return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
 }
 
 glm::vec3 MyAvatar::getRightHandTipPosition() const {
     const int RIGHT_HAND = 1;
-    auto palmData = getActivePalm(RIGHT_HAND);
-    return palmData ? palmData->getTipPosition() : glm::vec3(0.0f);
+    auto palmData = getActivePalmData(RIGHT_HAND);
+    return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
 }
 
 controller::Pose MyAvatar::getLeftHandPose() const {
     const int LEFT_HAND = 0;
-    auto palmData = getActivePalm(LEFT_HAND);
-    return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
-        palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+    auto palmData = getActivePalmData(LEFT_HAND);
+    return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
+        palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getRightHandPose() const {
     const int RIGHT_HAND = 1;
-    auto palmData = getActivePalm(RIGHT_HAND);
-    return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
-        palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+    auto palmData = getActivePalmData(RIGHT_HAND);
+    return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
+        palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getLeftHandTipPose() const {
     const int LEFT_HAND = 0;
-    auto palmData = getActivePalm(LEFT_HAND);
-    return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
-        palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+    auto palmData = getActivePalmData(LEFT_HAND);
+    return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
+        palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getRightHandTipPose() const {
     const int RIGHT_HAND = 1;
-    auto palmData = getActivePalm(RIGHT_HAND);
-    return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
-        palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
+    auto palmData = getActivePalmData(RIGHT_HAND);
+    return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
+        palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 // virtual
@@ -1967,28 +1969,6 @@ void MyAvatar::updateMotionBehaviorFromMenu() {
     _characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController));
 }
 
-//Renders sixense laser pointers for UI selection with controllers
-void MyAvatar::renderLaserPointers(gpu::Batch& batch) {
-    const float PALM_TIP_ROD_RADIUS = 0.002f;
-
-    //If the Oculus is enabled, we will draw a blue cursor ray
-
-    for (size_t i = 0; i < getHand()->getNumPalms(); ++i) {
-        PalmData& palm = getHand()->getPalms()[i];
-        if (palm.isActive()) {
-            glm::vec3 tip = getLaserPointerTipPosition(&palm);
-            glm::vec3 root = palm.getPosition();
-
-            //Scale the root vector with the avatar scale
-            scaleVectorRelativeToPosition(root);
-            Transform transform = Transform();
-            transform.setTranslation(glm::vec3());
-            batch.setModelTransform(transform);
-            Avatar::renderJointConnectingCone(batch, root, tip, PALM_TIP_ROD_RADIUS, PALM_TIP_ROD_RADIUS, glm::vec4(0, 1, 1, 1));
-        }
-    }
-}
-
 //Gets the tip position for the laser pointer
 glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
     glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition());
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 0a3d7dedf4..b6cce7165a 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -294,7 +294,6 @@ private:
                         const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f,
                         bool allowDuplicates = false, bool useSaved = true) override;
 
-    void renderLaserPointers(gpu::Batch& batch);
     const RecorderPointer getRecorder() const { return _recorder; }
     const PlayerPointer getPlayer() const { return _player; }
 
@@ -310,8 +309,7 @@ private:
 
     void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
 
-    const PalmData* getActivePalm(int palmIndex) const;
-
+    PalmData getActivePalmData(int palmIndex) const;
 
     // derive avatar body position and orientation from the current HMD Sensor location.
     // results are in sensor space
diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp
index 28c7941c52..f821c79d59 100644
--- a/interface/src/avatar/SkeletonModel.cpp
+++ b/interface/src/avatar/SkeletonModel.cpp
@@ -97,17 +97,6 @@ void SkeletonModel::initJointStates(QVector<JointState> states) {
     emit skeletonLoaded();
 }
 
-static const PalmData* getPalmWithIndex(Hand* hand, int index) {
-    const PalmData* palm = nullptr;
-    for (size_t j = 0; j < hand->getNumPalms(); j++) {
-        if (hand->getPalms()[j].getSixenseID() == index) {
-            palm = &(hand->getPalms()[j]);
-            break;
-        }
-    }
-    return palm;
-}
-
 const float PALM_PRIORITY = DEFAULT_PRIORITY;
 // Called within Model::simulate call, below.
 void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
@@ -169,22 +158,22 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
 
         Rig::HandParameters handParams;
 
-        const PalmData* leftPalm = getPalmWithIndex(myAvatar->getHand(), LEFT_HAND_INDEX);
-        if (leftPalm && leftPalm->isActive()) {
+        auto leftPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand);
+        if (leftPalm.isValid() && leftPalm.isActive()) {
             handParams.isLeftEnabled = true;
-            handParams.leftPosition = leftPalm->getRawPosition();
-            handParams.leftOrientation = leftPalm->getRawRotation();
-            handParams.leftTrigger = leftPalm->getTrigger();
+            handParams.leftPosition = leftPalm.getRawPosition();
+            handParams.leftOrientation = leftPalm.getRawRotation();
+            handParams.leftTrigger = leftPalm.getTrigger();
         } else {
             handParams.isLeftEnabled = false;
         }
 
-        const PalmData* rightPalm = getPalmWithIndex(myAvatar->getHand(), RIGHT_HAND_INDEX);
-        if (rightPalm && rightPalm->isActive()) {
+        auto rightPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::RightHand);
+        if (rightPalm.isValid() && rightPalm.isActive()) {
             handParams.isRightEnabled = true;
-            handParams.rightPosition = rightPalm->getRawPosition();
-            handParams.rightOrientation = rightPalm->getRawRotation();
-            handParams.rightTrigger = rightPalm->getTrigger();
+            handParams.rightPosition = rightPalm.getRawPosition();
+            handParams.rightOrientation = rightPalm.getRawRotation();
+            handParams.rightTrigger = rightPalm.getTrigger();
         } else {
             handParams.isRightEnabled = false;
         }
@@ -250,10 +239,15 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
     // find the left and rightmost active palms
     int leftPalmIndex, rightPalmIndex;
     Hand* hand = _owningAvatar->getHand();
-    hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
+
+    // FIXME - it's possible that the left/right hand indices could change between this call
+    // and the call to hand->getCopyOfPalms(); This logic should be reworked to only operate on
+    // the copy of the palms data
+    hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); 
 
     // Don't Relax toward hand positions when in animGraph mode.
     if (!_rig->getEnableAnimGraph()) {
+        auto palms = hand->getCopyOfPalms();
         const float HAND_RESTORATION_RATE = 0.25f;
         if (leftPalmIndex == -1 && rightPalmIndex == -1) {
             // palms are not yet set, use mouse
@@ -268,17 +262,17 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
 
         } else if (leftPalmIndex == rightPalmIndex) {
             // right hand only
-            applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]);
+            applyPalmData(geometry.rightHandJointIndex, palms[leftPalmIndex]);
             restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
 
         } else {
             if (leftPalmIndex != -1) {
-                applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]);
+                applyPalmData(geometry.leftHandJointIndex, palms[leftPalmIndex]);
             } else {
                 restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
             }
             if (rightPalmIndex != -1) {
-                applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]);
+                applyPalmData(geometry.rightHandJointIndex, palms[rightPalmIndex]);
             } else {
                 restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
             }
@@ -329,7 +323,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position)
                                   PALM_PRIORITY);
 }
 
-void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
+void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) {
     if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) {
         return;
     }
diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h
index d655d6e01f..dc08168a8c 100644
--- a/interface/src/avatar/SkeletonModel.h
+++ b/interface/src/avatar/SkeletonModel.h
@@ -118,7 +118,7 @@ protected:
     /// \param position position of joint in model-frame
     void applyHandPosition(int jointIndex, const glm::vec3& position);
 
-    void applyPalmData(int jointIndex, PalmData& palm);
+    void applyPalmData(int jointIndex, const PalmData& palm);
 private:
 
     void renderJointConstraints(gpu::Batch& batch, int jointIndex);
diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp
index 31f823de8b..547f16ea8b 100644
--- a/interface/src/scripting/ControllerScriptingInterface.cpp
+++ b/interface/src/scripting/ControllerScriptingInterface.cpp
@@ -35,51 +35,6 @@ void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
     }
 }
 
-const PalmData* ControllerScriptingInterface::getPrimaryPalm() const {
-    int leftPalmIndex, rightPalmIndex;
-
-    const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
-    handData->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
-    
-    if (rightPalmIndex != -1) {
-        return &handData->getPalms()[rightPalmIndex];
-    }
-
-    return NULL;
-}
-
-int ControllerScriptingInterface::getNumberOfActivePalms() const {
-    const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
-    int numberOfPalms = handData->getNumPalms();
-    int numberOfActivePalms = 0;
-    for (int i = 0; i < numberOfPalms; i++) {
-        if (getPalm(i)->isActive()) {
-            numberOfActivePalms++;
-        }
-    }
-    return numberOfActivePalms;
-}
-
-const PalmData* ControllerScriptingInterface::getPalm(int palmIndex) const {
-    const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
-    return &handData->getPalms()[palmIndex];
-}
-
-const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const {
-    const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
-    int numberOfPalms = handData->getNumPalms();
-    int numberOfActivePalms = 0;
-    for (int i = 0; i < numberOfPalms; i++) {
-        if (getPalm(i)->isActive()) {
-            if (numberOfActivePalms == palmIndex) {
-                return &handData->getPalms()[i];
-            }
-            numberOfActivePalms++;
-        }
-    }
-    return NULL;
-}
-
 bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const {
     return isKeyCaptured(KeyEvent(*event));
 }
diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h
index 3133f93804..4c69551dd2 100644
--- a/interface/src/scripting/ControllerScriptingInterface.h
+++ b/interface/src/scripting/ControllerScriptingInterface.h
@@ -123,11 +123,6 @@ signals:
 private:
     QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript
 
-    const PalmData* getPrimaryPalm() const;
-    const PalmData* getPalm(int palmIndex) const;
-    int getNumberOfActivePalms() const;
-    const PalmData* getActivePalm(int palmIndex) const;
-    
     QMultiMap<int,KeyEvent> _capturedKeys;
     QSet<int> _capturedJoysticks;
 
diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp
index ca5c60dc04..2f442a3284 100644
--- a/interface/src/ui/ApplicationCompositor.cpp
+++ b/interface/src/ui/ApplicationCompositor.cpp
@@ -320,8 +320,9 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
         // Only render the hand pointers if the EnableHandMouseInput is enabled
         if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
             MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
-            for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
-                PalmData& palm = myAvatar->getHand()->getPalms()[i];
+            auto palms = myAvatar->getHand()->getCopyOfPalms();
+            for (int i = 0; i < (int)palms.size(); i++) {
+                const auto& palm = palms[i];
                 if (palm.isActive()) {
                     glm::vec2 polar = getPolarCoordinates(palm);
                     // Convert to quaternion
@@ -446,6 +447,7 @@ void ApplicationCompositor::renderPointers(gpu::Batch& batch) {
 }
 
 
+// FIXME - this is old code that likely needs to be removed and/or reworked to support the new input control model
 void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) {
     MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
 
@@ -455,23 +457,24 @@ void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) {
     static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false };
 
     const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
+    auto palms = handData->getCopyOfPalms();
 
     for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) {
         const int index = palmIndex - 1;
 
         const PalmData* palmData = NULL;
 
-        if (palmIndex >= handData->getPalms().size()) {
+        if (palmIndex >= palms.size()) {
             return;
         }
 
-        if (handData->getPalms()[palmIndex].isActive()) {
-            palmData = &handData->getPalms()[palmIndex];
+        if (palms[palmIndex].isActive()) {
+            palmData = &palms[palmIndex];
         } else {
             continue;
         }
 
-        int controllerButtons = palmData->getControllerButtons();
+        int controllerButtons = 0;
 
         //Check for if we should toggle or drag the magnification window
         if (controllerButtons & BUTTON_3) {
diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp
index 1a9b6775d3..4e08f5190f 100644
--- a/libraries/avatars/src/HandData.cpp
+++ b/libraries/avatars/src/HandData.cpp
@@ -21,6 +21,8 @@
 HandData::HandData(AvatarData* owningAvatar) :
     _owningAvatarData(owningAvatar)
 {
+    // FIXME - this is likely the source of the fact that with Hydras and other input plugins with hand controllers
+    // we end up with 4 palms... because we end up adding palms once we know the SixenseIDs
     // Start with two palms
     addNewPalm();
     addNewPalm();
@@ -31,32 +33,35 @@ glm::vec3 HandData::worldToLocalVector(const glm::vec3& worldVector) const {
 }
 
 PalmData& HandData::addNewPalm()  {
+    QWriteLocker locker(&_palmsLock);
     _palms.push_back(PalmData(this));
     return _palms.back();
 }
 
-const PalmData* HandData::getPalm(int sixSenseID) const {
+PalmData HandData::getCopyOfPalmData(Hand hand) const {
+    QReadLocker locker(&_palmsLock);
+
     // the palms are not necessarily added in left-right order, 
-    // so we have to search for the right SixSenseID
-    for (unsigned int i = 0; i < _palms.size(); i++) {
-        const PalmData* palm = &(_palms[i]);
-        if (palm->getSixenseID() == sixSenseID) {
-            return palm->isActive() ? palm : NULL;
+    // so we have to search for the correct hand
+    for (const auto& palm : _palms) {
+        if (palm.whichHand() == hand && palm.isActive()) {
+            return palm;
         }
     }
-    return NULL;
+    return PalmData(nullptr); // invalid hand
 }
 
 void HandData::getLeftRightPalmIndices(int& leftPalmIndex, int& rightPalmIndex) const {
+    QReadLocker locker(&_palmsLock);
     leftPalmIndex = -1;
     rightPalmIndex = -1;
     for (size_t i = 0; i < _palms.size(); i++) {
         const PalmData& palm = _palms[i];
         if (palm.isActive()) {
-            if (palm.getSixenseID() == LEFT_HAND_INDEX) {
+            if (palm.whichHand() == LeftHand) {
                 leftPalmIndex = i;
             }
-            if (palm.getSixenseID() == RIGHT_HAND_INDEX) {
+            if (palm.whichHand() == RightHand) {
                 rightPalmIndex = i;
             }
         }
@@ -69,14 +74,9 @@ _rawPosition(0.0f),
 _rawVelocity(0.0f),
 _rawAngularVelocity(0.0f),
 _totalPenetration(0.0f),
-_controllerButtons(0),
 _isActive(false),
-_sixenseID(SIXENSEID_INVALID),
 _numFramesWithoutData(0),
-_owningHandData(owningHandData),
-_isCollidingWithVoxel(false),
-_isCollidingWithPalm(false),
-_collisionlessPaddleExpiry(0) {
+_owningHandData(owningHandData) {
 }
 
 void PalmData::addToPosition(const glm::vec3& delta) {
@@ -85,7 +85,8 @@ void PalmData::addToPosition(const glm::vec3& delta) {
 
 bool HandData::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration, 
                                         const PalmData*& collidingPalm) const {
-    
+    QReadLocker locker(&_palmsLock);
+
     for (size_t i = 0; i < _palms.size(); ++i) {
         const PalmData& palm = _palms[i];
         if (!palm.isActive()) {
diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h
index 855da63870..ca2aa9836a 100644
--- a/libraries/avatars/src/HandData.h
+++ b/libraries/avatars/src/HandData.h
@@ -12,26 +12,30 @@
 #ifndef hifi_HandData_h
 #define hifi_HandData_h
 
+#include <functional>
 #include <iostream>
 #include <vector>
 
 #include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
 
+#include <QReadWriteLock>
+
 #include <NumericalConstants.h>
 #include <SharedUtil.h>
 
 class AvatarData;
 class PalmData;
 
-const int LEFT_HAND_INDEX = 0;
-const int RIGHT_HAND_INDEX = 1;
-const int NUM_HANDS = 2;
-
-const int SIXENSEID_INVALID = -1;
-
 class HandData {
 public:
+    enum Hand {
+        UnknownHand,
+        RightHand,
+        LeftHand,
+        NUMBER_OF_HANDS
+    };
+
     HandData(AvatarData* owningAvatar);
     virtual ~HandData() {}
     
@@ -46,11 +50,10 @@ public:
 
     glm::vec3 worldToLocalVector(const glm::vec3& worldVector) const;
 
-    std::vector<PalmData>& getPalms() { return _palms; }
-    const std::vector<PalmData>& getPalms() const { return _palms; }
-    const PalmData* getPalm(int sixSenseID) const;
-    size_t getNumPalms() const { return _palms.size(); }
+    PalmData getCopyOfPalmData(Hand hand) const;
+
     PalmData& addNewPalm();
+    std::vector<PalmData> getCopyOfPalms() const { QReadLocker locker(&_palmsLock); return _palms; }
 
     /// Finds the indices of the left and right palms according to their locations, or -1 if either or
     /// both is not found.
@@ -67,10 +70,15 @@ public:
 
     glm::quat getBaseOrientation() const;
 
+    /// Allows a lamda function write access to the palms for this Hand
+    void modifyPalms(std::function<void(std::vector<PalmData>& palms)> callback) 
+            { QWriteLocker locker(&_palmsLock); callback(_palms);}
+
     friend class AvatarData;
 protected:
     AvatarData* _owningAvatarData;
     std::vector<PalmData> _palms;
+    mutable QReadWriteLock _palmsLock{ QReadWriteLock::Recursive };
     
     glm::vec3 getBasePosition() const;
     float getBaseScale() const;
@@ -90,10 +98,12 @@ public:
 
     const glm::vec3& getRawPosition() const { return _rawPosition; }
     bool isActive() const { return _isActive; }
-    int getSixenseID() const { return _sixenseID; }
+    bool isValid() const { return _owningHandData; }
 
     void setActive(bool active) { _isActive = active; }
-    void setSixenseID(int id) { _sixenseID = id; }
+
+    HandData::Hand whichHand() const { return _hand; }
+    void setHand(HandData::Hand hand) { _hand = hand; }
 
     void setRawRotation(const glm::quat rawRotation) { _rawRotation = rawRotation; };
     glm::quat getRawRotation() const { return _rawRotation; }
@@ -123,31 +133,11 @@ public:
     void resetFramesWithoutData() { _numFramesWithoutData = 0; }
     int  getFramesWithoutData() const { return _numFramesWithoutData; }
     
-    // Controller buttons
-    void setControllerButtons(unsigned int controllerButtons) { _controllerButtons = controllerButtons; }
-    void setLastControllerButtons(unsigned int controllerButtons) { _lastControllerButtons = controllerButtons; }
-
-    unsigned int getControllerButtons() const { return _controllerButtons; }
-    unsigned int getLastControllerButtons() const { return _lastControllerButtons; }
-    
+    // FIXME - these are used in SkeletonModel::updateRig() the skeleton/rig should probably get this information
+    // from an action and/or the UserInputMapper instead of piping it through here.
     void setTrigger(float trigger) { _trigger = trigger; }
     float getTrigger() const { return _trigger; }
-    void setJoystick(float joystickX, float joystickY) { _joystickX = joystickX; _joystickY = joystickY; }
-    float getJoystickX() const { return _joystickX; }
-    float getJoystickY() const { return _joystickY; }
     
-    bool getIsCollidingWithVoxel() const { return _isCollidingWithVoxel; }
-    void setIsCollidingWithVoxel(bool isCollidingWithVoxel) { _isCollidingWithVoxel = isCollidingWithVoxel; }
-
-    bool getIsCollidingWithPalm() const { return _isCollidingWithPalm; }
-    void setIsCollidingWithPalm(bool isCollidingWithPalm) { _isCollidingWithPalm = isCollidingWithPalm; }
-
-    bool hasPaddle() const { return _collisionlessPaddleExpiry < usecTimestampNow(); }
-    void updateCollisionlessPaddleExpiry() { _collisionlessPaddleExpiry = usecTimestampNow() + USECS_PER_SECOND; }
-
-    /// Store position where the palm holds the ball.
-    void getBallHoldPosition(glm::vec3& position) const;
-
     // return world-frame:
     glm::vec3 getFingerDirection() const;
     glm::vec3 getNormal() const;
@@ -163,21 +153,14 @@ private:
     
     glm::vec3 _tipPosition;
     glm::vec3 _tipVelocity;
-    glm::vec3 _totalPenetration;    // accumulator for per-frame penetrations
+    glm::vec3 _totalPenetration; /// accumulator for per-frame penetrations
 
-    unsigned int _controllerButtons;
-    unsigned int _lastControllerButtons;
     float _trigger;
-    float _joystickX, _joystickY;
     
-    bool      _isActive;             // This has current valid data
-    int       _sixenseID;            // Sixense controller ID for this palm
-    int       _numFramesWithoutData; // after too many frames without data, this tracked object assumed lost.
+    bool _isActive; /// This has current valid data
+    HandData::Hand _hand = HandData::UnknownHand;
+    int _numFramesWithoutData; /// after too many frames without data, this tracked object assumed lost.
     HandData* _owningHandData;
-    
-    bool      _isCollidingWithVoxel;  /// Whether the finger of this palm is inside a leaf voxel
-    bool      _isCollidingWithPalm;
-    quint64  _collisionlessPaddleExpiry; /// Timestamp after which paddle starts colliding
 };
 
 #endif // hifi_HandData_h

From 133d48ebee8c24cfd1fba989037da20b361573e7 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Tue, 27 Oct 2015 15:53:48 -0700
Subject: [PATCH 191/301] CR feedback

---
 interface/src/Application.cpp      | 53 +++++++++---------------------
 libraries/avatars/src/HandData.cpp | 19 +++++------
 libraries/avatars/src/HandData.h   | 28 +++++++++++-----
 3 files changed, 44 insertions(+), 56 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 910cbb19e2..29f4bd6ece 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -4811,30 +4811,9 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de
     // reading or writing to the Palms. This is definitely not the best way of handling this, and I'd like to see more
     // of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about
     // controller::Pose. More work is needed to clean this up.
-    hand->modifyPalms([&](std::vector<PalmData>& palms) {
+    hand->modifyPalm(whichHand, [&](PalmData& palm) {
         auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
-        PalmData* palm;
-        bool foundHand = false;
-
-        // FIXME - this little chuck of code is a hot mess. It's basically searching the palms
-        // for the one that matches the "sixenseID" that is the "index" parameter. If it 
-        // doesn't find it, then it creates a new palm and sets that palm's ID this really
-        // can and should be inside the HandData class
-        for (size_t j = 0; j < palms.size(); j++) {
-            if (palms[j].whichHand() == whichHand) {
-                palm = &(palms[j]);
-                foundHand = true;
-                break;
-            }
-        }
-        if (!foundHand) {
-            PalmData newPalm(hand);
-            palms.push_back(newPalm);
-            palm = &(palms[palms.size() - 1]); // FIXME - lame
-            palm->setHand(whichHand);
-        }
-    
-        palm->setActive(pose.isValid());
+        palm.setActive(pose.isValid());
 
         // transform from sensor space, to world space, to avatar model space.
         glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation());
@@ -4848,46 +4827,46 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de
         //  Compute current velocity from position change
         glm::vec3 rawVelocity;
         if (deltaTime > 0.0f) {
-            rawVelocity = (position - palm->getRawPosition()) / deltaTime;
+            rawVelocity = (position - palm.getRawPosition()) / deltaTime;
         } else {
             rawVelocity = glm::vec3(0.0f);
         }
-        palm->setRawVelocity(rawVelocity);   //  meters/sec
+        palm.setRawVelocity(rawVelocity);   //  meters/sec
     
         //  Angular Velocity of Palm
-        glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation());
+        glm::quat deltaRotation = rotation * glm::inverse(palm.getRawRotation());
         glm::vec3 angularVelocity(0.0f);
         float rotationAngle = glm::angle(deltaRotation);
         if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) {
             angularVelocity = glm::normalize(glm::axis(deltaRotation));
             angularVelocity *= (rotationAngle / deltaTime);
-            palm->setRawAngularVelocity(angularVelocity);
+            palm.setRawAngularVelocity(angularVelocity);
         } else {
-            palm->setRawAngularVelocity(glm::vec3(0.0f));
+            palm.setRawAngularVelocity(glm::vec3(0.0f));
         }
 
         if (controller::InputDevice::getLowVelocityFilter()) {
             //  Use a velocity sensitive filter to damp small motions and preserve large ones with
             //  no latency.
             float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
-            position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
-            rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter);
+            position = palm.getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
+            rotation = safeMix(palm.getRawRotation(), rotation, 1.0f - velocityFilter);
         }
-        palm->setRawPosition(position);
-        palm->setRawRotation(rotation);
+        palm.setRawPosition(position);
+        palm.setRawRotation(rotation);
 
         // Store the one fingertip in the palm structure so we can track velocity
         const float FINGER_LENGTH = 0.3f;   //  meters
         const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f);
         const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
-        glm::vec3 oldTipPosition = palm->getTipRawPosition();
+        glm::vec3 oldTipPosition = palm.getTipRawPosition();
         if (deltaTime > 0.0f) {
-            palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
+            palm.setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
         } else {
-            palm->setTipVelocity(glm::vec3(0.0f));
+            palm.setTipVelocity(glm::vec3(0.0f));
         }
-        palm->setTipPosition(newTipPosition);
-        palm->setTrigger(triggerValue);
+        palm.setTipPosition(newTipPosition);
+        palm.setTrigger(triggerValue);
     });
 }
 
diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp
index 4e08f5190f..0237f8ecd9 100644
--- a/libraries/avatars/src/HandData.cpp
+++ b/libraries/avatars/src/HandData.cpp
@@ -21,20 +21,17 @@
 HandData::HandData(AvatarData* owningAvatar) :
     _owningAvatarData(owningAvatar)
 {
-    // FIXME - this is likely the source of the fact that with Hydras and other input plugins with hand controllers
-    // we end up with 4 palms... because we end up adding palms once we know the SixenseIDs
-    // Start with two palms
-    addNewPalm();
-    addNewPalm();
+    addNewPalm(LeftHand);
+    addNewPalm(RightHand);
 }
 
 glm::vec3 HandData::worldToLocalVector(const glm::vec3& worldVector) const {
     return glm::inverse(getBaseOrientation()) * worldVector / getBaseScale();
 }
 
-PalmData& HandData::addNewPalm()  {
+PalmData& HandData::addNewPalm(Hand whichHand)  {
     QWriteLocker locker(&_palmsLock);
-    _palms.push_back(PalmData(this));
+    _palms.push_back(PalmData(this, whichHand));
     return _palms.back();
 }
 
@@ -48,7 +45,8 @@ PalmData HandData::getCopyOfPalmData(Hand hand) const {
             return palm;
         }
     }
-    return PalmData(nullptr); // invalid hand
+    PalmData noData;
+    return noData; // invalid hand
 }
 
 void HandData::getLeftRightPalmIndices(int& leftPalmIndex, int& rightPalmIndex) const {
@@ -68,7 +66,7 @@ void HandData::getLeftRightPalmIndices(int& leftPalmIndex, int& rightPalmIndex)
     }
 }
 
-PalmData::PalmData(HandData* owningHandData) :
+PalmData::PalmData(HandData* owningHandData, HandData::Hand hand) :
 _rawRotation(0.0f, 0.0f, 0.0f, 1.0f),
 _rawPosition(0.0f),
 _rawVelocity(0.0f),
@@ -76,7 +74,8 @@ _rawAngularVelocity(0.0f),
 _totalPenetration(0.0f),
 _isActive(false),
 _numFramesWithoutData(0),
-_owningHandData(owningHandData) {
+_owningHandData(owningHandData),
+_hand(hand) {
 }
 
 void PalmData::addToPosition(const glm::vec3& delta) {
diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h
index ca2aa9836a..10292daccc 100644
--- a/libraries/avatars/src/HandData.h
+++ b/libraries/avatars/src/HandData.h
@@ -30,9 +30,9 @@ class PalmData;
 class HandData {
 public:
     enum Hand {
-        UnknownHand,
-        RightHand,
         LeftHand,
+        RightHand,
+        UnknownHand,
         NUMBER_OF_HANDS
     };
 
@@ -52,7 +52,6 @@ public:
 
     PalmData getCopyOfPalmData(Hand hand) const;
 
-    PalmData& addNewPalm();
     std::vector<PalmData> getCopyOfPalms() const { QReadLocker locker(&_palmsLock); return _palms; }
 
     /// Finds the indices of the left and right palms according to their locations, or -1 if either or
@@ -70,9 +69,17 @@ public:
 
     glm::quat getBaseOrientation() const;
 
-    /// Allows a lamda function write access to the palms for this Hand
-    void modifyPalms(std::function<void(std::vector<PalmData>& palms)> callback) 
-            { QWriteLocker locker(&_palmsLock); callback(_palms);}
+    /// Allows a lamda function write access to the specific palm for this Hand, this might
+    /// modify the _palms vector
+    template<typename PalmModifierFunction> void modifyPalm(Hand whichHand, PalmModifierFunction callback) {
+        QReadLocker locker(&_palmsLock);
+        for (auto& palm : _palms) {
+            if (palm.whichHand() == whichHand && palm.isValid()) {
+                callback(palm);
+                return;
+            }
+        }
+    }
 
     friend class AvatarData;
 protected:
@@ -82,7 +89,10 @@ protected:
     
     glm::vec3 getBasePosition() const;
     float getBaseScale() const;
-    
+
+    PalmData& addNewPalm(Hand whichHand);
+    PalmData& getPalmData(Hand hand);
+
 private:
     // privatize copy ctor and assignment operator so copies of this object cannot be made
     HandData(const HandData&);
@@ -92,7 +102,7 @@ private:
 
 class PalmData {
 public:
-    PalmData(HandData* owningHandData);
+    PalmData(HandData* owningHandData = nullptr, HandData::Hand hand = HandData::UnknownHand);
     glm::vec3 getPosition() const { return _owningHandData->localToWorldPosition(_rawPosition); }
     glm::vec3 getVelocity() const { return _owningHandData->localToWorldDirection(_rawVelocity); }
 
@@ -158,7 +168,7 @@ private:
     float _trigger;
     
     bool _isActive; /// This has current valid data
-    HandData::Hand _hand = HandData::UnknownHand;
+    HandData::Hand _hand;
     int _numFramesWithoutData; /// after too many frames without data, this tracked object assumed lost.
     HandData* _owningHandData;
 };

From eb1936412954d0eabf2152f9fc759b5a2c9405c0 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Tue, 27 Oct 2015 15:56:27 -0700
Subject: [PATCH 192/301] CR feedback

---
 interface/src/avatar/MyAvatar.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 5483219318..1b1a2a18e0 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -569,8 +569,8 @@ PalmData MyAvatar::getActivePalmData(int palmIndex) const {
             numberOfActivePalms++;
         }
     }
-    PalmData noData(nullptr);
-    return noData;
+    ;
+    return PalmData();
 }
 
 

From 19743c1f39c17743634d3b7894a57a882f8d3b55 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Tue, 27 Oct 2015 16:16:03 -0700
Subject: [PATCH 193/301] gak, build busters and more CR feedback

---
 interface/src/Application.cpp      |  4 +--
 interface/src/avatar/MyAvatar.cpp  | 50 +++++-------------------------
 libraries/avatars/src/HandData.cpp |  3 +-
 libraries/avatars/src/HandData.h   | 24 +++++++-------
 4 files changed, 24 insertions(+), 57 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 29f4bd6ece..5f5b8e68c5 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -4807,7 +4807,7 @@ mat4 Application::getHMDSensorPose() const {
 
 void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue) {
 
-    // NOTE: the Hand::modifyPalms() will allow the lambda to modify the palm data while ensuring some other user isn't
+    // NOTE: the Hand::modifyPalm() will allow the lambda to modify the palm data while ensuring some other user isn't
     // reading or writing to the Palms. This is definitely not the best way of handling this, and I'd like to see more
     // of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about
     // controller::Pose. More work is needed to clean this up.
@@ -4866,7 +4866,7 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de
             palm.setTipVelocity(glm::vec3(0.0f));
         }
         palm.setTipPosition(newTipPosition);
-        palm.setTrigger(triggerValue);
+        palm.setTrigger(triggerValue); // FIXME - we want to get rid of this idea of PalmData having a trigger
     });
 }
 
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 1b1a2a18e0..18a7f4eb52 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -548,80 +548,46 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
 }
 
 
-// FIXME - this is super duper dumb... but this is how master works. When you have
-// hydras plugged in, you'll get 4 "palms" but only the number of controllers lifted
-// of the base station are considered active. So when you ask for "left" you get the
-// first active controller. If you have both controllers held up or just the left, that
-// will be correct. But if you lift the right controller, then it will be reported
-// as "left"... you also see this in the avatars hands. 
-PalmData MyAvatar::getActivePalmData(int palmIndex) const {
-    auto palms = getHandData()->getCopyOfPalms();
-
-    int numberOfPalms = palms.size();
-    int numberOfActivePalms = 0;
-    for (int i = 0; i < numberOfPalms; i++) {
-        auto palm = palms[i];
-        if (palm.isActive()) {
-            // if we've reached the requested "active" palm, then we will return it
-            if (numberOfActivePalms == palmIndex) {
-                return palm;
-            }
-            numberOfActivePalms++;
-        }
-    }
-    ;
-    return PalmData();
-}
-
-
 glm::vec3 MyAvatar::getLeftHandPosition() const {
-    const int LEFT_HAND = 0;
-    auto palmData = getActivePalmData(LEFT_HAND);
+    auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
     return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
 }
 
 glm::vec3 MyAvatar::getRightHandPosition() const {
-    const int RIGHT_HAND = 1;
-    auto palmData = getActivePalmData(RIGHT_HAND);
+    auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
     return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
 }
 
 glm::vec3 MyAvatar::getLeftHandTipPosition() const {
-    const int LEFT_HAND = 0;
-    auto palmData = getActivePalmData(LEFT_HAND);
+    auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
     return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
 }
 
 glm::vec3 MyAvatar::getRightHandTipPosition() const {
-    const int RIGHT_HAND = 1;
-    auto palmData = getActivePalmData(RIGHT_HAND);
+    auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
     return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
 }
 
 controller::Pose MyAvatar::getLeftHandPose() const {
-    const int LEFT_HAND = 0;
-    auto palmData = getActivePalmData(LEFT_HAND);
+    auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
     return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
         palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getRightHandPose() const {
-    const int RIGHT_HAND = 1;
-    auto palmData = getActivePalmData(RIGHT_HAND);
+    auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
     return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
         palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getLeftHandTipPose() const {
-    const int LEFT_HAND = 0;
-    auto palmData = getActivePalmData(LEFT_HAND);
+    auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
     return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
         palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
 }
 
 controller::Pose MyAvatar::getRightHandTipPose() const {
-    const int RIGHT_HAND = 1;
-    auto palmData = getActivePalmData(RIGHT_HAND);
+    auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
     return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
         palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
 }
diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp
index 0237f8ecd9..413a5ea955 100644
--- a/libraries/avatars/src/HandData.cpp
+++ b/libraries/avatars/src/HandData.cpp
@@ -45,8 +45,7 @@ PalmData HandData::getCopyOfPalmData(Hand hand) const {
             return palm;
         }
     }
-    PalmData noData;
-    return noData; // invalid hand
+    return PalmData(); // invalid hand
 }
 
 void HandData::getLeftRightPalmIndices(int& leftPalmIndex, int& rightPalmIndex) const {
diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h
index 10292daccc..b475248d9e 100644
--- a/libraries/avatars/src/HandData.h
+++ b/libraries/avatars/src/HandData.h
@@ -71,15 +71,7 @@ public:
 
     /// Allows a lamda function write access to the specific palm for this Hand, this might
     /// modify the _palms vector
-    template<typename PalmModifierFunction> void modifyPalm(Hand whichHand, PalmModifierFunction callback) {
-        QReadLocker locker(&_palmsLock);
-        for (auto& palm : _palms) {
-            if (palm.whichHand() == whichHand && palm.isValid()) {
-                callback(palm);
-                return;
-            }
-        }
-    }
+    template<typename PalmModifierFunction> void modifyPalm(Hand whichHand, PalmModifierFunction callback);
 
     friend class AvatarData;
 protected:
@@ -115,7 +107,7 @@ public:
     HandData::Hand whichHand() const { return _hand; }
     void setHand(HandData::Hand hand) { _hand = hand; }
 
-    void setRawRotation(const glm::quat rawRotation) { _rawRotation = rawRotation; };
+    void setRawRotation(const glm::quat& rawRotation) { _rawRotation = rawRotation; };
     glm::quat getRawRotation() const { return _rawRotation; }
     glm::quat getRotation() const { return _owningHandData->getBaseOrientation() * _rawRotation; }
     void setRawPosition(const glm::vec3& pos)  { _rawPosition = pos; }
@@ -168,9 +160,19 @@ private:
     float _trigger;
     
     bool _isActive; /// This has current valid data
-    HandData::Hand _hand;
     int _numFramesWithoutData; /// after too many frames without data, this tracked object assumed lost.
     HandData* _owningHandData;
+    HandData::Hand _hand;
 };
 
+template<typename PalmModifierFunction> void HandData::modifyPalm(Hand whichHand, PalmModifierFunction callback) {
+    QReadLocker locker(&_palmsLock);
+    for (auto& palm : _palms) {
+        if (palm.whichHand() == whichHand && palm.isValid()) {
+            callback(palm);
+            return;
+        }
+    }
+}
+
 #endif // hifi_HandData_h

From b8f189dea752744e1e9ef58c0f42edb602b19a47 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Tue, 27 Oct 2015 16:25:29 -0700
Subject: [PATCH 194/301] Fixing hydras

---
 .../src/input-plugins/SixenseManager.cpp      | 52 ++++++++++---------
 .../src/input-plugins/SixenseManager.h        |  9 +---
 2 files changed, 28 insertions(+), 33 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 008645abfe..d5ff4c93a8 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -67,11 +67,7 @@ const float DEFAULT_REACH_LENGTH = 1.5f;
 
 SixenseManager::SixenseManager() :
     InputDevice("Hydra"),
-    _reachLength(DEFAULT_REACH_LENGTH),
-#ifdef __APPLE__
-    _sixenseLibrary(nullptr),
-#endif
-    _hydrasConnected(false)
+    _reachLength(DEFAULT_REACH_LENGTH) 
 {
 }
 
@@ -94,6 +90,9 @@ void SixenseManager::activate() {
                            [this] (bool clicked) { this->setSixenseFilter(clicked); },
                            true, true);
 
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+    userInputMapper->registerDevice(this);
+
 #ifdef __APPLE__
 
     if (!_sixenseLibrary) {
@@ -121,9 +120,6 @@ void SixenseManager::activate() {
 #endif
     loadSettings();
     sixenseInit();
-    _activated = true;
-    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
-    userInputMapper->registerDevice(this);
 #endif
 }
 
@@ -134,13 +130,19 @@ void SixenseManager::deactivate() {
     CONTAINER->removeMenu(MENU_PATH);
 
     _poseStateMap.clear();
+    _collectedSamples.clear();
+
+    if (_deviceID != controller::Input::INVALID_DEVICE) {
+        auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+        userInputMapper->removeDevice(_deviceID);
+        _deviceID = controller::Input::INVALID_DEVICE;
+    }
 
 #ifdef __APPLE__
     SixenseBaseFunction sixenseExit = (SixenseBaseFunction)_sixenseLibrary->resolve("sixenseExit");
 #endif
 
     sixenseExit();
-    _activated = false;
 
 #ifdef __APPLE__
     delete _sixenseLibrary;
@@ -176,30 +178,32 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
 
     auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
 
+    static const float MAX_DISCONNECTED_TIME = 2.0f;
+    static bool disconnected { false };
+    static float disconnectedInterval { 0.0f };
     if (sixenseGetNumActiveControllers() == 0) {
-        if (_hydrasConnected) {
-            qCDebug(inputplugins) << "hydra disconnected" << _badDataCount;
-            if (_badDataCount++ < _allowedBadDataCount) { // gotta get some no-active in a row before we shut things down
-                return;
-            }
+        if (!disconnected) {
+            disconnectedInterval += deltaTime;
         }
-        _hydrasConnected = false;
-        if (_deviceID != 0) {
-            userInputMapper->removeDevice(_deviceID);
-            _deviceID = 0;
+        if (disconnectedInterval > MAX_DISCONNECTED_TIME) {
+            disconnected = true;
+            _axisStateMap.clear();
+            _buttonPressedMap.clear();
             _poseStateMap.clear();
             _collectedSamples.clear();
         }
         return;
     }
 
-    PerformanceTimer perfTimer("sixense");
-    if (!_hydrasConnected) {
-        _hydrasConnected = true;
-        _badDataCount = 0;
-        UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
+    if (disconnected) {
+        disconnected = 0;
+        disconnectedInterval = 0.0f;
     }
 
+    PerformanceTimer perfTimer("sixense");
+    // FIXME send this message once when we've positively identified hydra hardware
+    //UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
+
 #ifdef __APPLE__
     SixenseBaseFunction sixenseGetMaxControllers =
     (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers");
@@ -600,7 +604,6 @@ void SixenseManager::saveSettings() const {
         settings.setVec3Value(QString("avatarPosition"), _avatarPosition);
         settings.setQuatValue(QString("avatarRotation"), _avatarRotation);
         settings.setValue(QString("reachLength"), QVariant(_reachLength));
-        settings.setValue(QString("allowedHydraFailures"), 120);
     }
     settings.endGroup();
 }
@@ -613,7 +616,6 @@ void SixenseManager::loadSettings() {
         settings.getVec3ValueIfValid(QString("avatarPosition"), _avatarPosition);
         settings.getQuatValueIfValid(QString("avatarRotation"), _avatarRotation);
         settings.getFloatValueIfValid(QString("reachLength"), _reachLength);
-        _allowedBadDataCount = settings.value(QString("allowedHydraFailures"), 120).toInt();
     }
     settings.endGroup();
 }
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index aab475963c..a44f527238 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -104,18 +104,11 @@ private:
     MovingAverageMap _collectedSamples;
     
 #ifdef __APPLE__
-    QLibrary* _sixenseLibrary;
+    QLibrary* _sixenseLibrary { nullptr };
 #endif
     
-    bool _hydrasConnected;
-    int _badDataCount;
-    int _allowedBadDataCount;
-
     static const QString NAME;
     static const QString HYDRA_ID_STRING;
-
-    bool _activated = false;
-
 };
 
 #endif // hifi_SixenseManager_h

From d86f1b50a7c8a68c1d261879520eb0d915dc19ca Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Tue, 27 Oct 2015 16:37:43 -0700
Subject: [PATCH 195/301] more cleanup

---
 interface/src/avatar/Hand.cpp              | 6 ++----
 interface/src/ui/ApplicationCompositor.cpp | 3 +--
 libraries/avatars/src/HandData.cpp         | 3 +--
 3 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp
index dfac5e393f..15a3163998 100644
--- a/interface/src/avatar/Hand.cpp
+++ b/interface/src/avatar/Hand.cpp
@@ -51,8 +51,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
 
     gpu::Batch& batch = *renderArgs->_batch;
     if (isMine) {
-        for (size_t i = 0; i < palms.size(); i++) {
-            PalmData& palm = palms[i];
+        for (const auto& palm : palms) {
             if (!palm.isActive()) {
                 continue;
             }
@@ -78,8 +77,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
     const float AXIS_LENGTH = 10.0f * SPHERE_RADIUS;
 
     // Draw the coordinate frames of the hand targets
-    for (size_t i = 0; i < palms.size(); ++i) {
-        PalmData& palm = palms[i];
+    for (const auto& palm : palms) {
         if (palm.isActive()) {
             glm::vec3 root = palm.getPosition();
 
diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp
index 2f442a3284..2a2a45b67b 100644
--- a/interface/src/ui/ApplicationCompositor.cpp
+++ b/interface/src/ui/ApplicationCompositor.cpp
@@ -321,8 +321,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
         if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
             MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
             auto palms = myAvatar->getHand()->getCopyOfPalms();
-            for (int i = 0; i < (int)palms.size(); i++) {
-                const auto& palm = palms[i];
+            for (const auto& palm : palms) {
                 if (palm.isActive()) {
                     glm::vec2 polar = getPolarCoordinates(palm);
                     // Convert to quaternion
diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp
index 413a5ea955..fc6d18932a 100644
--- a/libraries/avatars/src/HandData.cpp
+++ b/libraries/avatars/src/HandData.cpp
@@ -85,8 +85,7 @@ bool HandData::findSpherePenetration(const glm::vec3& penetratorCenter, float pe
                                         const PalmData*& collidingPalm) const {
     QReadLocker locker(&_palmsLock);
 
-    for (size_t i = 0; i < _palms.size(); ++i) {
-        const PalmData& palm = _palms[i];
+    for (const auto& palm : _palms) {
         if (!palm.isActive()) {
             continue;
         }

From 6ec87086bc08d43a318eb838eaa08dba5fadd685 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 27 Oct 2015 16:57:06 -0700
Subject: [PATCH 196/301] Adding the state controller

---
 examples/controllers/handPosesDebug.js        | 42 ++++++++++++++++++-
 interface/resources/controllers/standard.json |  3 +-
 interface/src/Application.cpp                 |  3 +-
 .../src/controllers/DeviceProxy.cpp           |  1 -
 .../controllers/src/controllers/DeviceProxy.h |  7 +++-
 .../src/controllers/UserInputMapper.cpp       | 20 +++++----
 .../src/controllers/UserInputMapper.h         |  1 +
 7 files changed, 62 insertions(+), 15 deletions(-)

diff --git a/examples/controllers/handPosesDebug.js b/examples/controllers/handPosesDebug.js
index 6c933b2565..3eabee8f53 100644
--- a/examples/controllers/handPosesDebug.js
+++ b/examples/controllers/handPosesDebug.js
@@ -32,6 +32,7 @@ var RIGHT_HAND = 1;
 
 var COLORS = [ { red: 255, green: 0, blue: 0 }, { red: 0, green: 0, blue: 255 } ];
 
+
 function index(handNum, indexNum) {
 	return handNum * NUM_HANDS + indexNum;
 }
@@ -84,9 +85,46 @@ function updateHand(handNum, deltaTime) {
 	}
 }
 
+function updateHydra(handNum, deltaTime) {
+	var pose;
+	var handName = "right";
+	if (handNum == LEFT_HAND) {
+		pose = Controller.getPoseValue(Controller.Hardware.Hydra.LeftHand);
+		handName = "left";
+	} else {
+		pose = Controller.getPoseValue(Controller.Hardware.Hydra.RightHand);
+		handName = "right";
+	}
+
+	if (pose.valid) {
+		//print(handName + " hand moving" +  JSON.stringify(pose));
+		var wpos = Vec3.sum(MyAvatar.getPosition(), pose.translation);
+	    
+		Overlays.editOverlay(app.spheres[index(handNum, 0)], {
+	        position: pose.translation,
+	        visible: true,
+	    });
+	   	/*var vpos = Vec3.sum(Vec3.multiply(10 * deltaTime, pose.velocity), pose.translation);
+	    Overlays.editOverlay(app.spheres[index(handNum, 1)], {
+	        position: vpos,
+	        visible: true,
+	    });*/
+	} else {
+		Overlays.editOverlay(app.spheres[index(handNum, 0)], {
+	        visible: false
+	    });
+
+	    Overlays.editOverlay(app.spheres[index(handNum, 1)], {
+	        visible: false
+	    });
+	}
+}
+
 function update(deltaTime) {
-	updateHand(LEFT_HAND, deltaTime);
-	updateHand(RIGHT_HAND, deltaTime);
+	//updateHand(LEFT_HAND, deltaTime);
+	//updateHand(RIGHT_HAND, deltaTime);
+	updateHydra(LEFT_HAND, deltaTime);
+	updateHydra(RIGHT_HAND, deltaTime);
 }
 
 function scriptEnding() {
diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 20177bfc5e..69193b40c5 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -3,8 +3,7 @@
     "channels": [
         { "from": "Standard.LY", "to": "Actions.TranslateZ" },
         { "from": "Standard.LX", "to": "Actions.TranslateX" },
-        { "from": "Standard.RX", "with": "Actions.InHMD", "to": "Actions.StepYaw" },
-        { "from": "Standard.RX", "to": "Actions.Yaw" },
+         { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
 
         { "from": [ "Standard.DU", "Standard.DU", "Standard.DU", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index c1257e1279..403da6ddc5 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2707,7 +2707,7 @@ void Application::update(float deltaTime) {
     userInputMapper->resetActionState(controller::Action::IN_HMD, (float)qApp->getAvatarUpdater()->isHMDMode());
 
     userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
-    userInputMapper->update(deltaTime);
+  //  userInputMapper->update(deltaTime);
 
     bool jointsCaptured = false;
     for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
@@ -2718,6 +2718,7 @@ void Application::update(float deltaTime) {
             }
         }
     }
+    userInputMapper->update(deltaTime);
 
     // Transfer the user inputs to the driveKeys
     // FIXME can we drop drive keys and just have the avatar read the action states directly?
diff --git a/libraries/controllers/src/controllers/DeviceProxy.cpp b/libraries/controllers/src/controllers/DeviceProxy.cpp
index 6cbfc1048d..1bd65d4900 100644
--- a/libraries/controllers/src/controllers/DeviceProxy.cpp
+++ b/libraries/controllers/src/controllers/DeviceProxy.cpp
@@ -26,6 +26,5 @@ namespace controller {
             return NAN;
         }
     }
-
 }
 
diff --git a/libraries/controllers/src/controllers/DeviceProxy.h b/libraries/controllers/src/controllers/DeviceProxy.h
index 064abdbc7f..5f94e748f7 100644
--- a/libraries/controllers/src/controllers/DeviceProxy.h
+++ b/libraries/controllers/src/controllers/DeviceProxy.h
@@ -23,7 +23,8 @@ namespace controller {
 
     using Modifiers = std::vector<Input>;
     typedef QPair<Input, QString> InputPair;
-
+    class Endpoint;
+    using EndpointPtr = std::shared_ptr<Endpoint>;
     
     template<typename T>
     using InputGetter = std::function<T(const Input& input, int timestamp)>;
@@ -32,6 +33,7 @@ namespace controller {
     using PoseGetter = InputGetter<Pose>;
     using ResetBindings = std::function<bool()>;
     using AvailableInputGetter = std::function<Input::NamedVector()>;
+    using EndpointCreator = std::function<EndpointPtr(const Input&)>;
 
     class DeviceProxy {
     public:
@@ -42,6 +44,9 @@ namespace controller {
         PoseGetter getPose = [](const Input& input, int timestamp) -> Pose { return Pose(); };
         AvailableInputGetter getAvailabeInputs = []() -> Input::NamedVector const { return Input::NamedVector(); };
         float getValue(const Input& input, int timestamp = 0) const;
+        
+        EndpointCreator createEndpoint = [](const Input& input) -> EndpointPtr { return EndpointPtr(); };
+
         QString _name;
     };
 }
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 67a9fdc244..8539083265 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -43,6 +43,7 @@
 
 namespace controller {
     const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
+    const uint16_t UserInputMapper::STATE_DEVICE = ACTIONS_DEVICE - 0xFF;
     const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
 }
 
@@ -89,13 +90,16 @@ void UserInputMapper::registerDevice(InputDevice* device) {
         if (_endpointsByInput.count(input)) {
             continue;
         }
-        Endpoint::Pointer endpoint;
-        if (input.device == STANDARD_DEVICE) {
-            endpoint = std::make_shared<StandardEndpoint>(input);
-        } else if (input.device == ACTIONS_DEVICE) {
-            endpoint = std::make_shared<ActionEndpoint>(input);
-        } else {
-            endpoint = std::make_shared<InputEndpoint>(input);
+
+        Endpoint::Pointer endpoint = proxy->createEndpoint(input);
+        if (!endpoint) {
+            if (input.device == STANDARD_DEVICE) {
+                endpoint = std::make_shared<StandardEndpoint>(input);
+            } else if (input.device == ACTIONS_DEVICE) {
+                endpoint = std::make_shared<ActionEndpoint>(input);
+            } else {
+                endpoint = std::make_shared<InputEndpoint>(input);
+            }
         }
         _inputsByEndpoint[endpoint] = input;
         _endpointsByInput[input] = endpoint;
@@ -1020,7 +1024,7 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
 void UserInputMapper::resetActionState(Action action, float value) {
     auto endpoint = endpointFor(inputFromAction(action));
     if (endpoint) {
-        endpoint->apply(value, 0.0f, Endpoint::Pointer());
+        endpoint->apply(value, Endpoint::Pointer());
     }
     _actionStates[toInt(action)] = value;
 }
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 40fe26aff3..311d54c11c 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -58,6 +58,7 @@ namespace controller {
 
         static const uint16_t ACTIONS_DEVICE;
         static const uint16_t STANDARD_DEVICE;
+        static const uint16_t STATE_DEVICE;
 
         UserInputMapper();
         virtual ~UserInputMapper();

From 65eae3543329ac8b2585f7a24fac18cc40752c2e Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Tue, 27 Oct 2015 17:09:43 -0700
Subject: [PATCH 197/301] a little more cleanup

---
 interface/src/avatar/SkeletonModel.cpp | 31 +++++++++-----------------
 libraries/avatars/src/HandData.cpp     | 17 --------------
 libraries/avatars/src/HandData.h       |  4 ----
 3 files changed, 10 insertions(+), 42 deletions(-)

diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp
index f821c79d59..e39bfe246b 100644
--- a/interface/src/avatar/SkeletonModel.cpp
+++ b/interface/src/avatar/SkeletonModel.cpp
@@ -236,20 +236,15 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
 
     const FBXGeometry& geometry = _geometry->getFBXGeometry();
 
-    // find the left and rightmost active palms
-    int leftPalmIndex, rightPalmIndex;
-    Hand* hand = _owningAvatar->getHand();
-
-    // FIXME - it's possible that the left/right hand indices could change between this call
-    // and the call to hand->getCopyOfPalms(); This logic should be reworked to only operate on
-    // the copy of the palms data
-    hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); 
-
     // Don't Relax toward hand positions when in animGraph mode.
     if (!_rig->getEnableAnimGraph()) {
-        auto palms = hand->getCopyOfPalms();
+
+        Hand* hand = _owningAvatar->getHand();
+        auto leftPalm = hand->getCopyOfPalmData(HandData::LeftHand);
+        auto rightPalm = hand->getCopyOfPalmData(HandData::RightHand);
+
         const float HAND_RESTORATION_RATE = 0.25f;
-        if (leftPalmIndex == -1 && rightPalmIndex == -1) {
+        if (!leftPalm.isActive() && !rightPalm.isActive()) {
             // palms are not yet set, use mouse
             if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
                 restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
@@ -259,20 +254,14 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
                 applyHandPosition(geometry.rightHandJointIndex, handPosition);
             }
             restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
-
-        } else if (leftPalmIndex == rightPalmIndex) {
-            // right hand only
-            applyPalmData(geometry.rightHandJointIndex, palms[leftPalmIndex]);
-            restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
-
         } else {
-            if (leftPalmIndex != -1) {
-                applyPalmData(geometry.leftHandJointIndex, palms[leftPalmIndex]);
+            if (leftPalm.isActive()) {
+                applyPalmData(geometry.leftHandJointIndex, leftPalm);
             } else {
                 restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
             }
-            if (rightPalmIndex != -1) {
-                applyPalmData(geometry.rightHandJointIndex, palms[rightPalmIndex]);
+            if (rightPalm.isActive()) {
+                applyPalmData(geometry.rightHandJointIndex, rightPalm);
             } else {
                 restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
             }
diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp
index fc6d18932a..5d783a671e 100644
--- a/libraries/avatars/src/HandData.cpp
+++ b/libraries/avatars/src/HandData.cpp
@@ -48,23 +48,6 @@ PalmData HandData::getCopyOfPalmData(Hand hand) const {
     return PalmData(); // invalid hand
 }
 
-void HandData::getLeftRightPalmIndices(int& leftPalmIndex, int& rightPalmIndex) const {
-    QReadLocker locker(&_palmsLock);
-    leftPalmIndex = -1;
-    rightPalmIndex = -1;
-    for (size_t i = 0; i < _palms.size(); i++) {
-        const PalmData& palm = _palms[i];
-        if (palm.isActive()) {
-            if (palm.whichHand() == LeftHand) {
-                leftPalmIndex = i;
-            }
-            if (palm.whichHand() == RightHand) {
-                rightPalmIndex = i;
-            }
-        }
-    }
-}
-
 PalmData::PalmData(HandData* owningHandData, HandData::Hand hand) :
 _rawRotation(0.0f, 0.0f, 0.0f, 1.0f),
 _rawPosition(0.0f),
diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h
index b475248d9e..d782f240ee 100644
--- a/libraries/avatars/src/HandData.h
+++ b/libraries/avatars/src/HandData.h
@@ -54,10 +54,6 @@ public:
 
     std::vector<PalmData> getCopyOfPalms() const { QReadLocker locker(&_palmsLock); return _palms; }
 
-    /// Finds the indices of the left and right palms according to their locations, or -1 if either or
-    /// both is not found.
-    void getLeftRightPalmIndices(int& leftPalmIndex, int& rightPalmIndex) const;
-
     /// Checks for penetration between the described sphere and the hand.
     /// \param penetratorCenter the center of the penetration test sphere
     /// \param penetratorRadius the radius of the penetration test sphere

From 2f835b19fa1c181513412293964ebce6c1f5f30f Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Tue, 27 Oct 2015 17:17:19 -0700
Subject: [PATCH 198/301] surface is now a model

---
 .../painting/whiteboard/whiteboardSpawner.js  | 42 +++++++++++++------
 1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 4303803266..037be61459 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -17,13 +17,17 @@
 Script.include("../../libraries/utils.js");
 var scriptURL = Script.resolvePath("whiteboardEntityScript.js");
 //var modelURL = "https://hifi-public.s3.amazonaws.com/ozan/support/for_eric/whiteboard/whiteboard.fbx";
-// var modelURL = "http://localhost:8080/whiteboard.fbx?v1" + Math.random();
-var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx";
+var modelURL = "http://localhost:8080/whiteboard.fbx?v1" + Math.random();
+// var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx";
+
+var colorIndicatorBorderModelURL = "http://localhost:8080/colorIndicatorBorder.fbx?v1" + Math.random();
+
+var surfaceModelURL = "http://localhost:8080/boardSurface.fbx?v1" + Math.random();
 var rotation = Quat.safeEulerAngles(Camera.getOrientation());
 rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
 var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(rotation)));
 
-var whiteboardDimensions, colorIndicator, eraseAllText
+var whiteboardDimensions, colorIndicatorBoxDimensions, colorIndicatorBox, eraseAllText
 var colorBoxes = [];
 
 var colors = [
@@ -44,14 +48,26 @@ var whiteboard = Entities.addEntity({
     rotation: rotation,
 });
 
+var colorIndicatorPosition = {x: center.x, y: center.y, z: center.z};
+colorIndicatorPosition.y += 1.55;
+colorIndicatorPosition = Vec3.sum(colorIndicatorPosition, Vec3.multiply(-0.1, Quat.getFront(rotation)));
+var colorIndicatorBorder = Entities.addEntity({
+    type: "Model",
+    position: colorIndicatorPosition,
+    modelURL: colorIndicatorBorderModelURL,
+    rotation: rotation,
+    shapeType: "box"
+});
+
 var surfaceCenter = Vec3.sum(center, Vec3.multiply(-0.1, Quat.getFront(rotation)));
-surfaceCenter.y +=  0.55;
+surfaceCenter.y +=  0.6;
 var drawingSurface = Entities.addEntity({
-    type: "Box",
-    color: {red: 255, green: 255, blue: 255},
+    type: "Model",
+    modelURL: surfaceModelURL,
+    shapeType: "box",
     name: "whiteboard surface",
     position: surfaceCenter,
-    dimensions: {x: 1.8, y: 1.4, z: 0.01},
+    // dimensions: {x: 1.7, y: 1.3, z: 0.01},
     script: scriptURL,
     rotation: rotation, 
      userData: JSON.stringify({
@@ -64,15 +80,18 @@ var drawingSurface = Entities.addEntity({
 
 Script.setTimeout(function() {
     whiteboardDimensions = Entities.getEntityProperties(whiteboard, "naturalDimensions").naturalDimensions;
+    colorIndicatorDimensions = Entities.getEntityProperties(colorIndicatorBorder, "naturalDimensions").naturalDimensions;
     setUp();
 }, 1000)
 
 
 function setUp() {
     // COLOR INDICATOR BOX
+
+
     var colorIndicatorDimensions = {
         x: whiteboardDimensions.x,
-        y: 0.05,
+        y: 0.5,
         z: 0.02
     };
     scriptURL = Script.resolvePath("colorIndicatorEntityScript.js");
@@ -112,7 +131,7 @@ function setUp() {
         z: 0.002
     };
 
-    var palleteDepthOffset = -0.06;
+    var palleteDepthOffset = -0.07;
     var palleteHeightOffset = -0.28;
 
     colorBoxPosition = Vec3.sum(colorBoxPosition, Vec3.multiply(palleteDepthOffset, Quat.getFront(rotation)));
@@ -139,8 +158,6 @@ function setUp() {
         colorBoxPosition = Vec3.sum(colorBoxPosition, spaceBetweenColorBoxes);
     }
 
-
-
     var eraseBoxDimensions = {
         x: 0.5,
         y: 0.1,
@@ -182,6 +199,7 @@ function setUp() {
 function cleanup() {
     Entities.deleteEntity(whiteboard);
     Entities.deleteEntity(drawingSurface);
+    Entities.deleteEntity(colorIndicatorBorder);
     Entities.deleteEntity(eraseAllText);
     Entities.deleteEntity(colorIndicatorBox);
     colorBoxes.forEach(function(colorBox) {
@@ -192,4 +210,4 @@ function cleanup() {
 
 
 // Uncomment this line to delete whiteboard and all associated entity on script close
-// Script.scriptEnding.connect(cleanup);
\ No newline at end of file
+Script.scriptEnding.connect(cleanup);
\ No newline at end of file

From 06897aa474535c49453fb66db832f256eef49a6a Mon Sep 17 00:00:00 2001
From: Stephen Birarda <commit@birarda.com>
Date: Wed, 21 Oct 2015 11:53:38 -0700
Subject: [PATCH 199/301] don't force parenting of AssetRequest/AssetUpload

---
 libraries/networking/src/AssetClient.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp
index b7f1205847..6a1b46340c 100644
--- a/libraries/networking/src/AssetClient.cpp
+++ b/libraries/networking/src/AssetClient.cpp
@@ -89,7 +89,6 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext
         
         // Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case)
         request->moveToThread(thread());
-        request->setParent(this);
         
         return request;
     } else {
@@ -105,7 +104,6 @@ AssetUpload* AssetClient::createUpload(const QString& filename) {
         auto upload = new AssetUpload(filename);
         
         upload->moveToThread(thread());
-        upload->setParent(this);
         
         return upload;
     } else {
@@ -118,7 +116,6 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex
         auto upload = new AssetUpload(data, extension);
         
         upload->moveToThread(thread());
-        upload->setParent(this);
         
         return upload;
     } else {

From 92ca658aae617ba217202afc58afc4c894bb8c42 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 28 Oct 2015 09:23:20 -0700
Subject: [PATCH 200/301] Trying to get a state controller to work

---
 interface/resources/controllers/standard.json |   1 +
 interface/src/Application.cpp                 | 101 ++++++++++--------
 .../src/controllers/UserInputMapper.cpp       |  10 +-
 .../src/controllers/UserInputMapper.h         |   2 -
 4 files changed, 57 insertions(+), 57 deletions(-)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 4ef0a1b90f..7b18641636 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -3,6 +3,7 @@
     "channels": [
         { "from": "Standard.LY", "to": "Actions.TranslateZ" },
         { "from": "Standard.LX", "to": "Actions.TranslateX" },
+         { "from": "Standard.RX", "width": "Application.InHMD", to": "Actions.StepYaw" },
          { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
 
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 403da6ddc5..7733fec494 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -143,6 +143,8 @@
 #include "ui/UpdateDialog.h"
 #include "Util.h"
 
+#include "controllers/StateController.h"
+
 // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
 // FIXME seems to be broken.
 #if defined(Q_OS_WIN)
@@ -346,47 +348,47 @@ int _keyboardFocusHighlightID{ -1 };
 PluginContainer* _pluginContainer;
 
 Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
-        QApplication(argc, argv),
-        _dependencyManagerIsSetup(setupEssentials(argc, argv)),
-        _window(new MainWindow(desktop())),
-        _toolWindow(NULL),
-        _undoStackScriptingInterface(&_undoStack),
-        _frameCount(0),
-        _fps(60.0f),
-        _physicsEngine(new PhysicsEngine(Vectors::ZERO)),
-        _entities(true, this, this),
-        _entityClipboardRenderer(false, this, this),
-        _entityClipboard(new EntityTree()),
-        _lastQueriedTime(usecTimestampNow()),
-        _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
-        _firstRun("firstRun", true),
-        _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
-        _scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION),
-        _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
-        _scaleMirror(1.0f),
-        _rotateMirror(0.0f),
-        _raiseMirror(0.0f),
-        _lastMouseMoveWasSimulated(false),
-        _enableProcessOctreeThread(true),
-        _runningScriptsWidget(NULL),
-        _runningScriptsWidgetWasVisible(false),
-        _lastNackTime(usecTimestampNow()),
-        _lastSendDownstreamAudioStats(usecTimestampNow()),
-        _aboutToQuit(false),
-        _notifiedPacketVersionMismatchThisDomain(false),
-        _maxOctreePPS(maxOctreePacketsPerSecond.get()),
-        _lastFaceTrackerUpdate(0)
+QApplication(argc, argv),
+_dependencyManagerIsSetup(setupEssentials(argc, argv)),
+_window(new MainWindow(desktop())),
+_toolWindow(NULL),
+_undoStackScriptingInterface(&_undoStack),
+_frameCount(0),
+_fps(60.0f),
+_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
+_entities(true, this, this),
+_entityClipboardRenderer(false, this, this),
+_entityClipboard(new EntityTree()),
+_lastQueriedTime(usecTimestampNow()),
+_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
+_firstRun("firstRun", true),
+_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
+_scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION),
+_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
+_scaleMirror(1.0f),
+_rotateMirror(0.0f),
+_raiseMirror(0.0f),
+_lastMouseMoveWasSimulated(false),
+_enableProcessOctreeThread(true),
+_runningScriptsWidget(NULL),
+_runningScriptsWidgetWasVisible(false),
+_lastNackTime(usecTimestampNow()),
+_lastSendDownstreamAudioStats(usecTimestampNow()),
+_aboutToQuit(false),
+_notifiedPacketVersionMismatchThisDomain(false),
+_maxOctreePPS(maxOctreePacketsPerSecond.get()),
+_lastFaceTrackerUpdate(0)
 {
     thread()->setObjectName("Main Thread");
-    
+
     setInstance(this);
-    
+
     auto controllerScriptingInterface = DependencyManager::get<controller::ScriptingInterface>().data();
     _controllerScriptingInterface = dynamic_cast<ControllerScriptingInterface*>(controllerScriptingInterface);
     // to work around the Qt constant wireless scanning, set the env for polling interval very high
     const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT_MAX).toLocal8Bit();
     qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
-    
+
     _entityClipboard->createRootElement();
 
     _pluginContainer = new PluginContainerProxy();
@@ -449,7 +451,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     audioIO->moveToThread(audioThread);
 
     auto& audioScriptingInterface = AudioScriptingInterface::getInstance();
-    
+
     connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start);
     connect(audioIO.data(), &AudioClient::destroyed, audioThread, &QThread::quit);
     connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater);
@@ -488,7 +490,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
     connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived);
     connect(&domainHandler, &DomainHandler::hostnameChanged,
-            DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
+        DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
 
     // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one
     const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000;
@@ -499,7 +501,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
 
     // if we get a domain change, immediately attempt update location in metaverse server
     connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain,
-            discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
+        discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
 
     connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded);
     connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled);
@@ -538,14 +540,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle);
     connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress);
 
-    #ifdef _WIN32
+#ifdef _WIN32
     WSADATA WsaData;
-    int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData);
-    #endif
+    int wsaresult = WSAStartup(MAKEWORD(2, 2), &WsaData);
+#endif
 
     // tell the NodeList instance who to tell the domain server we care about
     nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
-                                                 << NodeType::EntityServer << NodeType::AssetServer);
+        << NodeType::EntityServer << NodeType::AssetServer);
 
     // connect to the packet sent signal of the _entityEditSender
     connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
@@ -618,12 +620,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     // hook up bandwidth estimator
     QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
     connect(nodeList.data(), &LimitedNodeList::dataSent,
-            bandwidthRecorder.data(), &BandwidthRecorder::updateOutboundData);
+        bandwidthRecorder.data(), &BandwidthRecorder::updateOutboundData);
     connect(&nodeList->getPacketReceiver(), &PacketReceiver::dataReceived,
-            bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData);
+        bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData);
 
     connect(&getMyAvatar()->getSkeletonModel(), &SkeletonModel::skeletonLoaded,
-            this, &Application::checkSkeleton, Qt::QueuedConnection);
+        this, &Application::checkSkeleton, Qt::QueuedConnection);
 
     // Setup the userInputMapper with the actions
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
@@ -633,9 +635,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
         }
     });
 
+    static controller::StateController _stateController;
+    auto InHMDLambda = controller::StateController::ReadLambda([]() -> float {
+        return (float) qApp->getAvatarUpdater()->isHMDMode();
+    });
+    _stateController.addInputVariant("InHMD", InHMDLambda);
+
+    userInputMapper->registerDevice(&_stateController);
+    
     // Setup the keyboardMouseDevice and the user input mapper with the default bindings
     userInputMapper->registerDevice(_keyboardMouseDevice);
 
+    //userInputMapper->getApplicationDevice()->(float)qApp->getAvatarUpdater()->isHMDMode()
+
     // check first run...
     if (_firstRun.get()) {
         qCDebug(interfaceapp) << "This is a first run...";
@@ -2703,9 +2715,6 @@ void Application::update(float deltaTime) {
 
     auto myAvatar = getMyAvatar();
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    // Reflect some state into the Actions of the UserInpuMapper
-    userInputMapper->resetActionState(controller::Action::IN_HMD, (float)qApp->getAvatarUpdater()->isHMDMode());
-
     userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
   //  userInputMapper->update(deltaTime);
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 8539083265..257e4ebe85 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -21,6 +21,7 @@
 #include <NumericalConstants.h>
 
 #include "StandardController.h"
+#include "StateController.h"
 
 #include "Logging.h"
 
@@ -43,7 +44,6 @@
 
 namespace controller {
     const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
-    const uint16_t UserInputMapper::STATE_DEVICE = ACTIONS_DEVICE - 0xFF;
     const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
 }
 
@@ -1021,13 +1021,5 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
     }
 }
 
-void UserInputMapper::resetActionState(Action action, float value) {
-    auto endpoint = endpointFor(inputFromAction(action));
-    if (endpoint) {
-        endpoint->apply(value, Endpoint::Pointer());
-    }
-    _actionStates[toInt(action)] = value;
-}
-
 }
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 311d54c11c..e28fbd740d 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -58,7 +58,6 @@ namespace controller {
 
         static const uint16_t ACTIONS_DEVICE;
         static const uint16_t STANDARD_DEVICE;
-        static const uint16_t STATE_DEVICE;
 
         UserInputMapper();
         virtual ~UserInputMapper();
@@ -87,7 +86,6 @@ namespace controller {
         QVector<QString> getActionNames() const;
         Input inputFromAction(Action action) const { return getActionInputs()[toInt(action)].first; }
 
-        void resetActionState(Action action, float value);
         void setActionState(Action action, float value) { _actionStates[toInt(action)] = value; }
         void deltaActionState(Action action, float delta) { _actionStates[toInt(action)] += delta; }
         void setActionState(Action action, const Pose& value) { _poseStates[toInt(action)] = value; }

From 37f967bc33c3e57a1d3973ed55a329b8f5342194 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 28 Oct 2015 09:23:57 -0700
Subject: [PATCH 201/301] And adding the StateCOntroller class

---
 .../src/controllers/StateController.cpp       | 61 +++++++++++++++++++
 .../src/controllers/StateController.h         | 49 +++++++++++++++
 2 files changed, 110 insertions(+)
 create mode 100644 libraries/controllers/src/controllers/StateController.cpp
 create mode 100644 libraries/controllers/src/controllers/StateController.h

diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp
new file mode 100644
index 0000000000..93985fe8e3
--- /dev/null
+++ b/libraries/controllers/src/controllers/StateController.cpp
@@ -0,0 +1,61 @@
+//
+//  StateController.cpp
+//  controllers/src/controllers
+//
+//  Created by Sam Gateau on 2015-10-27.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "StateController.h"
+
+#include <PathUtils.h>
+
+#include "DeviceProxy.h"
+#include "UserInputMapper.h"
+#include "impl/Endpoint.h"
+
+namespace controller {
+
+StateController::StateController() : InputDevice("Application") {
+}
+
+StateController::~StateController() {
+}
+
+void StateController::update(float deltaTime, bool jointsCaptured) {}
+
+void StateController::focusOutEvent() {}
+
+void StateController::addInputVariant(QString name, ReadLambda& lambda) {
+    namedReadLambdas.push_back(NamedReadLambda(name, lambda));
+}
+void StateController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
+    proxy->_name = _name;
+    proxy->getButton = [this] (const Input& input, int timestamp) -> bool { return getButton(input.getChannel()); };
+    proxy->getAxis = [this] (const Input& input, int timestamp) -> float { return getAxis(input.getChannel()); };
+    proxy->getAvailabeInputs = [this] () -> QVector<Input::NamedPair> {
+    
+        
+        QVector<Input::NamedPair> availableInputs;
+        
+        int i = 0;
+        for (auto pair : namedReadLambdas) {
+            availableInputs.push_back(Input::NamedPair(Input(_deviceID, i, ChannelType::BUTTON), pair.first));
+            i++;
+        }
+        return availableInputs;
+    };
+    proxy->createEndpoint = [this] (const Input& input) -> Endpoint::Pointer {
+        if (input.getChannel() < namedReadLambdas.size()) {
+            return std::make_shared<LambdaEndpoint>(namedReadLambdas[input.getChannel()].second);
+        }
+
+        return Endpoint::Pointer();
+    };
+}
+
+
+}
diff --git a/libraries/controllers/src/controllers/StateController.h b/libraries/controllers/src/controllers/StateController.h
new file mode 100644
index 0000000000..f17b31f64b
--- /dev/null
+++ b/libraries/controllers/src/controllers/StateController.h
@@ -0,0 +1,49 @@
+//
+//  StateController.h
+//  controllers/src/controllers
+//
+//  Created by Sam Gateau on 2015-10-27.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_StateController_h
+#define hifi_StateController_h
+
+#include <QtCore/QObject>
+#include <QtCore/QVector>
+
+#include "InputDevice.h"
+
+namespace controller {
+
+class StateController : public QObject, public InputDevice {
+    Q_OBJECT
+    Q_PROPERTY(QString name READ getName)
+
+public:
+    const QString& getName() const { return _name; }
+
+    // Device functions
+    virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override;
+    virtual QString getDefaultMappingConfig() override { return QString(); }
+    virtual void update(float deltaTime, bool jointsCaptured) override;
+    virtual void focusOutEvent() override;
+
+    StateController();
+    virtual ~StateController();
+
+    using ReadLambda = std::function<float()>;
+    using NamedReadLambda = QPair<QString, ReadLambda>;
+
+    void addInputVariant(QString name, ReadLambda& lambda);
+
+    QVector<NamedReadLambda> namedReadLambdas;
+    QVector<Input::NamedPair> availableInputs;
+};
+
+}
+
+#endif // hifi_StateController_h
\ No newline at end of file

From 30f7c44f611dc644922673f1423cde1fe063995e Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 28 Oct 2015 09:34:18 -0700
Subject: [PATCH 202/301] emit hardwareChanged signal to scripts

---
 examples/controllers/controllerMappings.js                 | 7 ++++++-
 .../controllers/src/controllers/ScriptingInterface.cpp     | 1 +
 libraries/controllers/src/controllers/ScriptingInterface.h | 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js
index 66efa63676..42494816f4 100644
--- a/examples/controllers/controllerMappings.js
+++ b/examples/controllers/controllerMappings.js
@@ -87,4 +87,9 @@ Object.keys(Controller.Hardware).forEach(function (deviceName) {
 Object.keys(Controller.Actions).forEach(function (actionName) {
     print("Controller.Actions." + actionName + ":" + Controller.Actions[actionName]);
 });
-*/
\ No newline at end of file
+*/
+
+
+Controller.hardwareChanged.connect(function () {
+    print("hardwareChanged");
+});
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index bb09705684..b5630cfab1 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -50,6 +50,7 @@ controller::ScriptingInterface::ScriptingInterface() {
     // FIXME make this thread safe
     connect(userInputMapper.data(), &UserInputMapper::hardwareChanged, [=] {
         updateMaps();
+        emit hardwareChanged();
     });
 
 
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h
index db724044fa..9af478e709 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.h
+++ b/libraries/controllers/src/controllers/ScriptingInterface.h
@@ -132,6 +132,7 @@ namespace controller {
     signals:
         void actionEvent(int action, float state);
         void inputEvent(int action, float state);
+        void hardwareChanged();
 
     private:
         // Update the exposed variant maps reporting active hardware

From 457ec76d3d85f69e6153b66b1d63afa0c73ab432 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Wed, 28 Oct 2015 11:21:53 -0700
Subject: [PATCH 203/301] CR feedback

---
 libraries/controllers/src/controllers/ScriptingInterface.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index b5630cfab1..8d00000c45 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -48,12 +48,11 @@ controller::ScriptingInterface::ScriptingInterface() {
     connect(userInputMapper.data(), &UserInputMapper::inputEvent, this, &controller::ScriptingInterface::inputEvent);
 
     // FIXME make this thread safe
-    connect(userInputMapper.data(), &UserInputMapper::hardwareChanged, [=] {
+    connect(userInputMapper.data(), &UserInputMapper::hardwareChanged, this, [=] {
         updateMaps();
         emit hardwareChanged();
     });
 
-
     qCDebug(controllers) << "Setting up standard controller abstraction";
     _standard = createDeviceMap(userInputMapper->getStandardDevice());
 

From fc15c7cd98f147f0b7c410904ff460bf26f6a2aa Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 28 Oct 2015 12:15:14 -0700
Subject: [PATCH 204/301] Adding the ApplicationStateDevice to the APplication
 class and add one entry ythere

---
 interface/resources/controllers/standard.json |  1 -
 interface/src/Application.cpp                 | 76 ++++++++++---------
 interface/src/Application.h                   |  5 ++
 .../src/controllers/StateController.cpp       |  2 +-
 .../src/controllers/StateController.h         |  2 +-
 5 files changed, 47 insertions(+), 39 deletions(-)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 7b18641636..4ef0a1b90f 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -3,7 +3,6 @@
     "channels": [
         { "from": "Standard.LY", "to": "Actions.TranslateZ" },
         { "from": "Standard.LX", "to": "Actions.TranslateX" },
-         { "from": "Standard.RX", "width": "Application.InHMD", to": "Actions.StepYaw" },
          { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
 
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 9c7c152f03..d47c2b547e 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -66,6 +66,7 @@
 #include <input-plugins/InputPlugin.h>
 #include <input-plugins/Joystick.h> // this should probably be removed
 #include <controllers/UserInputMapper.h>
+#include <controllers/StateController.h>
 #include <LogHandler.h>
 #include <MainWindow.h>
 #include <MessageDialog.h>
@@ -143,7 +144,6 @@
 #include "ui/UpdateDialog.h"
 #include "Util.h"
 
-#include "controllers/StateController.h"
 
 // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
 // FIXME seems to be broken.
@@ -348,36 +348,36 @@ int _keyboardFocusHighlightID{ -1 };
 PluginContainer* _pluginContainer;
 
 Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
-QApplication(argc, argv),
-_dependencyManagerIsSetup(setupEssentials(argc, argv)),
-_window(new MainWindow(desktop())),
-_toolWindow(NULL),
-_undoStackScriptingInterface(&_undoStack),
-_frameCount(0),
-_fps(60.0f),
-_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
-_entities(true, this, this),
-_entityClipboardRenderer(false, this, this),
-_entityClipboard(new EntityTree()),
-_lastQueriedTime(usecTimestampNow()),
-_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
-_firstRun("firstRun", true),
-_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
-_scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION),
-_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
-_scaleMirror(1.0f),
-_rotateMirror(0.0f),
-_raiseMirror(0.0f),
-_lastMouseMoveWasSimulated(false),
-_enableProcessOctreeThread(true),
-_runningScriptsWidget(NULL),
-_runningScriptsWidgetWasVisible(false),
-_lastNackTime(usecTimestampNow()),
-_lastSendDownstreamAudioStats(usecTimestampNow()),
-_aboutToQuit(false),
-_notifiedPacketVersionMismatchThisDomain(false),
-_maxOctreePPS(maxOctreePacketsPerSecond.get()),
-_lastFaceTrackerUpdate(0)
+    QApplication(argc, argv),
+    _dependencyManagerIsSetup(setupEssentials(argc, argv)),
+    _window(new MainWindow(desktop())),
+    _toolWindow(NULL),
+    _undoStackScriptingInterface(&_undoStack),
+    _frameCount(0),
+    _fps(60.0f),
+    _physicsEngine(new PhysicsEngine(Vectors::ZERO)),
+    _entities(true, this, this),
+    _entityClipboardRenderer(false, this, this),
+    _entityClipboard(new EntityTree()),
+    _lastQueriedTime(usecTimestampNow()),
+    _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
+    _firstRun("firstRun", true),
+    _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
+    _scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION),
+    _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
+    _scaleMirror(1.0f),
+    _rotateMirror(0.0f),
+    _raiseMirror(0.0f),
+    _lastMouseMoveWasSimulated(false),
+    _enableProcessOctreeThread(true),
+    _runningScriptsWidget(NULL),
+    _runningScriptsWidgetWasVisible(false),
+    _lastNackTime(usecTimestampNow()),
+    _lastSendDownstreamAudioStats(usecTimestampNow()),
+    _aboutToQuit(false),
+    _notifiedPacketVersionMismatchThisDomain(false),
+    _maxOctreePPS(maxOctreePacketsPerSecond.get()),
+    _lastFaceTrackerUpdate(0)
 {
     thread()->setObjectName("Main Thread");
 
@@ -635,13 +635,14 @@ _lastFaceTrackerUpdate(0)
         }
     });
 
-    static controller::StateController _stateController;
+    // A new controllerInput device used to reflect current values from the application state
+    _applicationStateDevice = new controller::StateController("Application");
     auto InHMDLambda = controller::StateController::ReadLambda([]() -> float {
         return (float) qApp->getAvatarUpdater()->isHMDMode();
     });
-    _stateController.addInputVariant("InHMD", InHMDLambda);
+    _applicationStateDevice->addInputVariant("InHMD", InHMDLambda);
 
-    userInputMapper->registerDevice(&_stateController);
+    userInputMapper->registerDevice(_applicationStateDevice);
     
     // Setup the keyboardMouseDevice and the user input mapper with the default bindings
     userInputMapper->registerDevice(_keyboardMouseDevice);
@@ -807,6 +808,10 @@ void Application::cleanupBeforeQuit() {
 
     AnimDebugDraw::getInstance().shutdown();
 
+    // FIXME: once we move to shared pointer for the INputDevice we shoud remove this naked delete:
+    delete _applicationStateDevice;
+    _applicationStateDevice = nullptr;
+
     if (_keyboardFocusHighlightID > 0) {
         getOverlays().deleteOverlay(_keyboardFocusHighlightID);
         _keyboardFocusHighlightID = -1;
@@ -2716,7 +2721,7 @@ void Application::update(float deltaTime) {
     auto myAvatar = getMyAvatar();
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
-  //  userInputMapper->update(deltaTime);
+    userInputMapper->update(deltaTime);
 
     bool jointsCaptured = false;
     for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
@@ -2727,7 +2732,6 @@ void Application::update(float deltaTime) {
             }
         }
     }
-    userInputMapper->update(deltaTime);
 
     // Transfer the user inputs to the driveKeys
     // FIXME can we drop drive keys and just have the avatar read the action states directly?
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 301eb3b262..50a39bd2eb 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -71,6 +71,10 @@ class FaceTracker;
 class MainWindow;
 class AssetUpload;
 
+namespace controller {
+    class StateController;
+}
+
 #ifdef Q_OS_WIN
 static const UINT UWM_IDENTIFY_INSTANCES =
     RegisterWindowMessage("UWM_IDENTIFY_INSTANCES_{8AB82783-B74A-4258-955B-8188C22AA0D6}_" + qgetenv("USERNAME"));
@@ -442,6 +446,7 @@ private:
 
     OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
 
+    controller::StateController* _applicationStateDevice{ nullptr }; // Default ApplicationDevice reflecting the state of different properties of the session
     KeyboardMouseDevice* _keyboardMouseDevice{ nullptr };   // Default input device, the good old keyboard mouse and maybe touchpad
     AvatarUpdate* _avatarUpdate {nullptr};
     SimpleMovingAverage _avatarSimsPerSecond {10};
diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp
index 93985fe8e3..ef735422db 100644
--- a/libraries/controllers/src/controllers/StateController.cpp
+++ b/libraries/controllers/src/controllers/StateController.cpp
@@ -19,7 +19,7 @@
 
 namespace controller {
 
-StateController::StateController() : InputDevice("Application") {
+StateController::StateController(QString name) : InputDevice(name) {
 }
 
 StateController::~StateController() {
diff --git a/libraries/controllers/src/controllers/StateController.h b/libraries/controllers/src/controllers/StateController.h
index f17b31f64b..afd0456b5a 100644
--- a/libraries/controllers/src/controllers/StateController.h
+++ b/libraries/controllers/src/controllers/StateController.h
@@ -32,7 +32,7 @@ public:
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
-    StateController();
+    StateController(QString name);
     virtual ~StateController();
 
     using ReadLambda = std::function<float()>;

From b37a6f689a2e2478409cddff5885b4bf2f9b3ca3 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 28 Oct 2015 12:51:22 -0700
Subject: [PATCH 205/301] Fixing typo and review comments

---
 interface/resources/controllers/standard.json             | 2 +-
 interface/src/Application.cpp                             | 1 -
 libraries/controllers/src/controllers/Actions.cpp         | 2 --
 libraries/controllers/src/controllers/Actions.h           | 4 +---
 libraries/controllers/src/controllers/StateController.cpp | 8 ++++----
 libraries/controllers/src/controllers/StateController.h   | 3 +--
 6 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 4ef0a1b90f..8ba9056076 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -3,7 +3,7 @@
     "channels": [
         { "from": "Standard.LY", "to": "Actions.TranslateZ" },
         { "from": "Standard.LX", "to": "Actions.TranslateX" },
-         { "from": "Standard.RX", "to": "Actions.Yaw" },
+        { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
 
         { "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index d47c2b547e..0ccb9de28a 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -647,7 +647,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     // Setup the keyboardMouseDevice and the user input mapper with the default bindings
     userInputMapper->registerDevice(_keyboardMouseDevice);
 
-    //userInputMapper->getApplicationDevice()->(float)qApp->getAvatarUpdater()->isHMDMode()
 
     // check first run...
     if (_firstRun.get()) {
diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp
index 979c8a70c1..a9bd32b1d8 100644
--- a/libraries/controllers/src/controllers/Actions.cpp
+++ b/libraries/controllers/src/controllers/Actions.cpp
@@ -75,8 +75,6 @@ namespace controller {
                 makeAxisPair(Action::BOOM_IN, "BoomIn"),
                 makeAxisPair(Action::BOOM_OUT, "BoomOut"),
 
-                makeButtonPair(Action::IN_HMD, "InHMD"),
-
                 // Deprecated aliases
                 // FIXME remove after we port all scripts
                 makeAxisPair(Action::LONGITUDINAL_BACKWARD, "LONGITUDINAL_BACKWARD"),
diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h
index 187fcd46a0..971da13cf0 100644
--- a/libraries/controllers/src/controllers/Actions.h
+++ b/libraries/controllers/src/controllers/Actions.h
@@ -77,9 +77,7 @@ enum class Action {
     // Biseced aliases for TRANSLATE_CAMERA_Z
     BOOM_IN,
     BOOM_OUT,
-
-    IN_HMD, // THis is a read only action ?
-
+    
     NUM_ACTIONS,
 };
 
diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp
index ef735422db..29b30bc24e 100644
--- a/libraries/controllers/src/controllers/StateController.cpp
+++ b/libraries/controllers/src/controllers/StateController.cpp
@@ -30,7 +30,7 @@ void StateController::update(float deltaTime, bool jointsCaptured) {}
 void StateController::focusOutEvent() {}
 
 void StateController::addInputVariant(QString name, ReadLambda& lambda) {
-    namedReadLambdas.push_back(NamedReadLambda(name, lambda));
+    _namedReadLambdas.push_back(NamedReadLambda(name, lambda));
 }
 void StateController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
     proxy->_name = _name;
@@ -42,15 +42,15 @@ void StateController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
         QVector<Input::NamedPair> availableInputs;
         
         int i = 0;
-        for (auto pair : namedReadLambdas) {
+        for (auto& pair : _namedReadLambdas) {
             availableInputs.push_back(Input::NamedPair(Input(_deviceID, i, ChannelType::BUTTON), pair.first));
             i++;
         }
         return availableInputs;
     };
     proxy->createEndpoint = [this] (const Input& input) -> Endpoint::Pointer {
-        if (input.getChannel() < namedReadLambdas.size()) {
-            return std::make_shared<LambdaEndpoint>(namedReadLambdas[input.getChannel()].second);
+        if (input.getChannel() < _namedReadLambdas.size()) {
+            return std::make_shared<LambdaEndpoint>(_namedReadLambdas[input.getChannel()].second);
         }
 
         return Endpoint::Pointer();
diff --git a/libraries/controllers/src/controllers/StateController.h b/libraries/controllers/src/controllers/StateController.h
index afd0456b5a..963f884d98 100644
--- a/libraries/controllers/src/controllers/StateController.h
+++ b/libraries/controllers/src/controllers/StateController.h
@@ -40,8 +40,7 @@ public:
 
     void addInputVariant(QString name, ReadLambda& lambda);
 
-    QVector<NamedReadLambda> namedReadLambdas;
-    QVector<Input::NamedPair> availableInputs;
+    QVector<NamedReadLambda> _namedReadLambdas;
 };
 
 }

From bbc6d9f5e7709427d1ab37b9ac4b9124dcc03a34 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 28 Oct 2015 12:52:21 -0700
Subject: [PATCH 206/301] Fixing typo and review comments

---
 interface/src/Application.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 0ccb9de28a..2c79d5a288 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2755,10 +2755,6 @@ void Application::update(float deltaTime) {
         myAvatar->setDriveKeys(ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z));
     }
 
-    float lhc = userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK);
-    if (lhc != 0.0f) {
-        std::cout << "Left Hand click = " << lhc << std::endl;
-    }
     controller::Pose leftHand = userInputMapper->getPoseState(controller::Action::LEFT_HAND);
     controller::Pose rightHand = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);
     Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();

From 40277823354d9ecd526628d799982356959d7e00 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Wed, 28 Oct 2015 13:18:57 -0700
Subject: [PATCH 207/301] Fixed issue with overlays disapearing on release grab

---
 .../whiteboard/whiteboardEntityScript.js      |  4 +
 .../painting/whiteboard/whiteboardSpawner.js  | 88 ++++++++-----------
 2 files changed, 40 insertions(+), 52 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js
index f38073f389..fffaa78a8c 100644
--- a/examples/painting/whiteboard/whiteboardEntityScript.js
+++ b/examples/painting/whiteboard/whiteboardEntityScript.js
@@ -47,6 +47,7 @@
             if (this.painting) {
                 return;
             }
+            this.whichHand = this.hand;
             if (this.hand === RIGHT_HAND) {
                 this.getHandPosition = MyAvatar.getRightPalmPosition;
                 this.getHandRotation = MyAvatar.getRightPalmRotation;
@@ -183,6 +184,9 @@
         },
 
         releaseGrab: function() {
+            if(this.hand !== this.whichHand) {
+                return;
+            }
             this.stopPainting();
 
         },
diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 037be61459..c40a763bf6 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -22,12 +22,14 @@ var modelURL = "http://localhost:8080/whiteboard.fbx?v1" + Math.random();
 
 var colorIndicatorBorderModelURL = "http://localhost:8080/colorIndicatorBorder.fbx?v1" + Math.random();
 
+var eraseModelURL = "http://localhost:8080/eraser.fbx?v1" + Math.random();
+
 var surfaceModelURL = "http://localhost:8080/boardSurface.fbx?v1" + Math.random();
 var rotation = Quat.safeEulerAngles(Camera.getOrientation());
 rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
 var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(rotation)));
 
-var whiteboardDimensions, colorIndicatorBoxDimensions, colorIndicatorBox, eraseAllText
+var whiteboardDimensions, colorIndicatorBoxDimensions, colorIndicatorBox, eraser;
 var colorBoxes = [];
 
 var colors = [
@@ -48,7 +50,11 @@ var whiteboard = Entities.addEntity({
     rotation: rotation,
 });
 
-var colorIndicatorPosition = {x: center.x, y: center.y, z: center.z};
+var colorIndicatorPosition = {
+    x: center.x,
+    y: center.y,
+    z: center.z
+};
 colorIndicatorPosition.y += 1.55;
 colorIndicatorPosition = Vec3.sum(colorIndicatorPosition, Vec3.multiply(-0.1, Quat.getFront(rotation)));
 var colorIndicatorBorder = Entities.addEntity({
@@ -60,27 +66,40 @@ var colorIndicatorBorder = Entities.addEntity({
 });
 
 var surfaceCenter = Vec3.sum(center, Vec3.multiply(-0.1, Quat.getFront(rotation)));
-surfaceCenter.y +=  0.6;
+surfaceCenter.y += 0.6;
 var drawingSurface = Entities.addEntity({
     type: "Model",
     modelURL: surfaceModelURL,
     shapeType: "box",
     name: "whiteboard surface",
     position: surfaceCenter,
-    // dimensions: {x: 1.7, y: 1.3, z: 0.01},
     script: scriptURL,
-    rotation: rotation, 
-     userData: JSON.stringify({
+    rotation: rotation,
+    userData: JSON.stringify({
         color: {
             currentColor: colors[0]
         }
     })
 
-})
+});
+
+var eraseModelPosition = Vec3.sum(center, {x: 0, y: 2, z: 0 });
+scriptURL = Script.resolvePath("eraseBoardEntityScript.js");
+var eraser = Entities.addEntity({
+    type: "Model",
+    modelURL: eraseModelURL,
+    position: eraseModelPosition,
+    name: "Eraser",
+    script: scriptURL,
+    rotation: rotation,
+    userData: JSON.stringify({
+        whiteboard: drawingSurface
+    })
+});
 
 Script.setTimeout(function() {
     whiteboardDimensions = Entities.getEntityProperties(whiteboard, "naturalDimensions").naturalDimensions;
-    colorIndicatorDimensions = Entities.getEntityProperties(colorIndicatorBorder, "naturalDimensions").naturalDimensions;
+    colorIndicatorBorderDimensions = Entities.getEntityProperties(colorIndicatorBorder, "naturalDimensions").naturalDimensions;
     setUp();
 }, 1000)
 
@@ -89,24 +108,25 @@ function setUp() {
     // COLOR INDICATOR BOX
 
 
-    var colorIndicatorDimensions = {
-        x: whiteboardDimensions.x,
-        y: 0.5,
-        z: 0.02
-    };
+    var eraseModelDimensions = Entities.getEntityProperties(eraser, "naturalDimensions").naturalDimensions;
+    Entities.editEntity(eraser, {dimensions: eraseModelDimensions});
+    Entities.editEntity(colorIndicatorBorder, {dimensions: colorIndicatorBorderDimensions});
+
     scriptURL = Script.resolvePath("colorIndicatorEntityScript.js");
     var colorIndicatorPosition = Vec3.sum(center, {
         x: 0,
-        y: whiteboardDimensions.y / 2 + colorIndicatorDimensions.y / 2,
+        y: whiteboardDimensions.y / 2 + colorIndicatorBorderDimensions.y / 2,
         z: 0
     });
+    colorIndicatorPosition = Vec3.sum(colorIndicatorPosition, Vec3.multiply(-.1, Quat.getFront(rotation)));
+    var colorIndicatorBoxDimensions = Vec3.multiply(colorIndicatorBorderDimensions, 0.9);
     colorIndicatorBox = Entities.addEntity({
         type: "Box",
         name: "Color Indicator",
         color: colors[0],
         rotation: rotation,
         position: colorIndicatorPosition,
-        dimensions: colorIndicatorDimensions,
+        dimensions: colorIndicatorBoxDimensions,
         script: scriptURL,
         userData: JSON.stringify({
             whiteboard: drawingSurface
@@ -158,49 +178,13 @@ function setUp() {
         colorBoxPosition = Vec3.sum(colorBoxPosition, spaceBetweenColorBoxes);
     }
 
-    var eraseBoxDimensions = {
-        x: 0.5,
-        y: 0.1,
-        z: 0.01
-    };
-
-
-    var eraseBoxPosition = Vec3.sum(center, Vec3.multiply(direction, whiteboardDimensions.x / 2 + eraseBoxDimensions.x / 2 + 0.01));
-    eraseBoxPosition.y += 0.3;
-    scriptURL = Script.resolvePath("eraseBoardEntityScript.js");
-    eraseAllText = Entities.addEntity({
-        type: "Text",
-        position: eraseBoxPosition,
-        name: "Eraser",
-        script: scriptURL,
-        rotation: rotation,
-        dimensions: eraseBoxDimensions,
-        backgroundColor: {
-            red: 0,
-            green: 60,
-            blue: 0
-        },
-        textColor: {
-            red: 255,
-            green: 10,
-            blue: 10
-        },
-        text: "ERASE BOARD",
-        lineHeight: 0.07,
-        userData: JSON.stringify({
-            whiteboard: drawingSurface
-        })
-    });
-
-
-
 }
 
 function cleanup() {
     Entities.deleteEntity(whiteboard);
     Entities.deleteEntity(drawingSurface);
     Entities.deleteEntity(colorIndicatorBorder);
-    Entities.deleteEntity(eraseAllText);
+    Entities.deleteEntity(eraser);
     Entities.deleteEntity(colorIndicatorBox);
     colorBoxes.forEach(function(colorBox) {
         Entities.deleteEntity(colorBox);

From b90af1a1ce636f6dc66d098011b8a8ac508643ab Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 28 Oct 2015 13:21:45 -0700
Subject: [PATCH 208/301] Fixing typo and review comments

---
 examples/controllers/handPosesDebug.js        | 143 +++++++-----------
 .../src/controllers/StateController.h         |   1 +
 2 files changed, 54 insertions(+), 90 deletions(-)

diff --git a/examples/controllers/handPosesDebug.js b/examples/controllers/handPosesDebug.js
index 3eabee8f53..e770abd957 100644
--- a/examples/controllers/handPosesDebug.js
+++ b/examples/controllers/handPosesDebug.js
@@ -11,17 +11,17 @@
 
 
 function makeSphere(color) {
-	var SPHERE_SIZE = 0.05;
-	var sphere = Overlays.addOverlay("sphere", {
-	    position: { x: 0, y: 0, z: 0 },
-	    size: SPHERE_SIZE,
-	    color: color,
-	    alpha: 1.0,
-	    solid: true,
-	    visible: true,
-	});
+    var SPHERE_SIZE = 0.05;
+    var sphere = Overlays.addOverlay("sphere", {
+        position: { x: 0, y: 0, z: 0 },
+        size: SPHERE_SIZE,
+        color: color,
+        alpha: 1.0,
+        solid: true,
+        visible: true,
+    });
 
-	return sphere;
+    return sphere;
 }
 
 
@@ -34,104 +34,67 @@ var COLORS = [ { red: 255, green: 0, blue: 0 }, { red: 0, green: 0, blue: 255 }
 
 
 function index(handNum, indexNum) {
-	return handNum * NUM_HANDS + indexNum;
+    return handNum * NUM_HANDS + indexNum;
 }
 
 var app = {};
 
 
 function setup() {
-	app.spheres = new Array();
+    app.spheres = new Array();
 
-	for (var h = 0; h < NUM_HANDS; h++) {
-		for (var s = 0; s < NUM_SPHERES_PER_HAND; s++) {
-			var i = index(h, s);
-			app.spheres[i] = makeSphere(COLORS[h]);
-			print("Added Sphere num " + i + " = " + JSON.stringify(app.spheres[i]));
-		}
-	}
+    for (var h = 0; h < NUM_HANDS; h++) {
+        for (var s = 0; s < NUM_SPHERES_PER_HAND; s++) {
+            var i = index(h, s);
+            app.spheres[i] = makeSphere(COLORS[h]);
+            print("Added Sphere num " + i + " = " + JSON.stringify(app.spheres[i]));
+        }
+    }
 }
 
 function updateHand(handNum, deltaTime) {
-	var pose;
-	var handName = "right";
-	if (handNum == LEFT_HAND) {
-		pose = MyAvatar.getLeftHandPose();
-		handName = "left";
-	} else {
-		pose = MyAvatar.getRightHandPose();
-		handName = "right";
-	}
+    var pose;
+    var handName = "right";
+    if (handNum == LEFT_HAND) {
+        pose = MyAvatar.getLeftHandPose();
+        handName = "left";
+    } else {
+        pose = MyAvatar.getRightHandPose();
+        handName = "right";
+    }
 
-	if (pose.valid) {
-		//print(handName + " hand moving" +  JSON.stringify(pose));
-		Overlays.editOverlay(app.spheres[index(handNum, 0)], {
-	        position: pose.translation,
-	        visible: true,
-	    });
-	   	var vpos = Vec3.sum(Vec3.multiply(10 * deltaTime, pose.velocity), pose.translation);
-	    Overlays.editOverlay(app.spheres[index(handNum, 1)], {
-	        position: vpos,
-	        visible: true,
-	    });
-	} else {
-		Overlays.editOverlay(app.spheres[index(handNum, 0)], {
-	        visible: false
-	    });
+    if (pose.valid) {
+        //print(handName + " hand moving" +  JSON.stringify(pose));
+        Overlays.editOverlay(app.spheres[index(handNum, 0)], {
+            position: pose.translation,
+            visible: true,
+        });
+        var vpos = Vec3.sum(Vec3.multiply(10 * deltaTime, pose.velocity), pose.translation);
+        Overlays.editOverlay(app.spheres[index(handNum, 1)], {
+            position: vpos,
+            visible: true,
+        });
+    } else {
+        Overlays.editOverlay(app.spheres[index(handNum, 0)], {
+            visible: false
+        });
 
-	    Overlays.editOverlay(app.spheres[index(handNum, 1)], {
-	        visible: false
-	    });
-	}
-}
-
-function updateHydra(handNum, deltaTime) {
-	var pose;
-	var handName = "right";
-	if (handNum == LEFT_HAND) {
-		pose = Controller.getPoseValue(Controller.Hardware.Hydra.LeftHand);
-		handName = "left";
-	} else {
-		pose = Controller.getPoseValue(Controller.Hardware.Hydra.RightHand);
-		handName = "right";
-	}
-
-	if (pose.valid) {
-		//print(handName + " hand moving" +  JSON.stringify(pose));
-		var wpos = Vec3.sum(MyAvatar.getPosition(), pose.translation);
-	    
-		Overlays.editOverlay(app.spheres[index(handNum, 0)], {
-	        position: pose.translation,
-	        visible: true,
-	    });
-	   	/*var vpos = Vec3.sum(Vec3.multiply(10 * deltaTime, pose.velocity), pose.translation);
-	    Overlays.editOverlay(app.spheres[index(handNum, 1)], {
-	        position: vpos,
-	        visible: true,
-	    });*/
-	} else {
-		Overlays.editOverlay(app.spheres[index(handNum, 0)], {
-	        visible: false
-	    });
-
-	    Overlays.editOverlay(app.spheres[index(handNum, 1)], {
-	        visible: false
-	    });
-	}
+        Overlays.editOverlay(app.spheres[index(handNum, 1)], {
+            visible: false
+        });
+    }
 }
 
 function update(deltaTime) {
-	//updateHand(LEFT_HAND, deltaTime);
-	//updateHand(RIGHT_HAND, deltaTime);
-	updateHydra(LEFT_HAND, deltaTime);
-	updateHydra(RIGHT_HAND, deltaTime);
+    updateHand(LEFT_HAND, deltaTime);
+    updateHand(RIGHT_HAND, deltaTime);
 }
 
 function scriptEnding() {
-	print("Removing spheres = " + JSON.stringify(app.spheres));
-	for (var i = 0; i < app.spheres.length; i++) {
-		Overlays.deleteOverlay(app.spheres[i]);
-	}
+    print("Removing spheres = " + JSON.stringify(app.spheres));
+    for (var i = 0; i < app.spheres.length; i++) {
+        Overlays.deleteOverlay(app.spheres[i]);
+    }
 }
 
 setup();
diff --git a/libraries/controllers/src/controllers/StateController.h b/libraries/controllers/src/controllers/StateController.h
index 963f884d98..fad3b0abba 100644
--- a/libraries/controllers/src/controllers/StateController.h
+++ b/libraries/controllers/src/controllers/StateController.h
@@ -40,6 +40,7 @@ public:
 
     void addInputVariant(QString name, ReadLambda& lambda);
 
+protected:
     QVector<NamedReadLambda> _namedReadLambdas;
 };
 

From ac2effb33cce4e55c9c91e0b3263cd0177da4979 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Wed, 28 Oct 2015 13:32:10 -0700
Subject: [PATCH 209/301] Not erasing board, models hosted on s3

---
 .../whiteboard/whiteboardEntityScript.js      |  4 +---
 .../painting/whiteboard/whiteboardSpawner.js  | 21 +++++++------------
 2 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js
index fffaa78a8c..ce0e8a82b1 100644
--- a/examples/painting/whiteboard/whiteboardEntityScript.js
+++ b/examples/painting/whiteboard/whiteboardEntityScript.js
@@ -243,12 +243,10 @@
         unload: function() {
 
             Overlays.deleteOverlay(this.laserPointer);
-            // this.eraseBoard();
+            this.eraseBoard();
         }
-
     };
 
-
     // entity scripts always need to return a newly constructed object of our type
     return new Whiteboard();
 });
\ No newline at end of file
diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index c40a763bf6..573432b77a 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -16,15 +16,11 @@
 
 Script.include("../../libraries/utils.js");
 var scriptURL = Script.resolvePath("whiteboardEntityScript.js");
-//var modelURL = "https://hifi-public.s3.amazonaws.com/ozan/support/for_eric/whiteboard/whiteboard.fbx";
-var modelURL = "http://localhost:8080/whiteboard.fbx?v1" + Math.random();
-// var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx";
+var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx";
 
-var colorIndicatorBorderModelURL = "http://localhost:8080/colorIndicatorBorder.fbx?v1" + Math.random();
-
-var eraseModelURL = "http://localhost:8080/eraser.fbx?v1" + Math.random();
-
-var surfaceModelURL = "http://localhost:8080/boardSurface.fbx?v1" + Math.random();
+var colorIndicatorBorderModelURL = "https://s3.amazonaws.com/hifi-public/eric/models/colorIndicatorBorder.fbx";
+var eraserModelURL = "https://s3.amazonaws.com/hifi-public/eric/models/eraser.fbx";
+var surfaceModelURL = "https://s3.amazonaws.com/hifi-public/eric/models/boardSurface.fbx";
 var rotation = Quat.safeEulerAngles(Camera.getOrientation());
 rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
 var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(rotation)));
@@ -87,7 +83,7 @@ var eraseModelPosition = Vec3.sum(center, {x: 0, y: 2, z: 0 });
 scriptURL = Script.resolvePath("eraseBoardEntityScript.js");
 var eraser = Entities.addEntity({
     type: "Model",
-    modelURL: eraseModelURL,
+    modelURL: eraserModelURL,
     position: eraseModelPosition,
     name: "Eraser",
     script: scriptURL,
@@ -101,13 +97,10 @@ Script.setTimeout(function() {
     whiteboardDimensions = Entities.getEntityProperties(whiteboard, "naturalDimensions").naturalDimensions;
     colorIndicatorBorderDimensions = Entities.getEntityProperties(colorIndicatorBorder, "naturalDimensions").naturalDimensions;
     setUp();
-}, 1000)
+}, 2000)
 
 
 function setUp() {
-    // COLOR INDICATOR BOX
-
-
     var eraseModelDimensions = Entities.getEntityProperties(eraser, "naturalDimensions").naturalDimensions;
     Entities.editEntity(eraser, {dimensions: eraseModelDimensions});
     Entities.editEntity(colorIndicatorBorder, {dimensions: colorIndicatorBorderDimensions});
@@ -194,4 +187,4 @@ function cleanup() {
 
 
 // Uncomment this line to delete whiteboard and all associated entity on script close
-Script.scriptEnding.connect(cleanup);
\ No newline at end of file
+// Script.scriptEnding.connect(cleanup);
\ No newline at end of file

From e9bdb872bdd8d3c78a6c0f6e3f28b2b407c64bc7 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Wed, 28 Oct 2015 15:25:11 -0700
Subject: [PATCH 210/301] added light to whiteboard

---
 examples/painting/whiteboard/whiteboardSpawner.js | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 573432b77a..b08c9bd624 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -79,6 +79,14 @@ var drawingSurface = Entities.addEntity({
 
 });
 
+var lightPosition = Vec3.sum(center, Vec3.multiply(-2, Quat.getFront(rotation)));
+var light = Entities.addEntity({
+    type: 'Light',
+    position: lightPosition,
+    dimensions: {x: 5, y: 5, z: 5},
+    color: {red: 255, green: 255, blue: 255}
+});
+
 var eraseModelPosition = Vec3.sum(center, {x: 0, y: 2, z: 0 });
 scriptURL = Script.resolvePath("eraseBoardEntityScript.js");
 var eraser = Entities.addEntity({
@@ -179,6 +187,7 @@ function cleanup() {
     Entities.deleteEntity(colorIndicatorBorder);
     Entities.deleteEntity(eraser);
     Entities.deleteEntity(colorIndicatorBox);
+    Entities.deleteEntity(light);
     colorBoxes.forEach(function(colorBox) {
         Entities.deleteEntity(colorBox);
     });

From 1b1490bb75403a6f31040d234035c5af67092c76 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Wed, 28 Oct 2015 16:02:15 -0700
Subject: [PATCH 211/301] added blocker so user cant get so close to whiteboard

---
 .../painting/whiteboard/whiteboardSpawner.js  | 21 +++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index b08c9bd624..29183dcc76 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -25,7 +25,7 @@ var rotation = Quat.safeEulerAngles(Camera.getOrientation());
 rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
 var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(rotation)));
 
-var whiteboardDimensions, colorIndicatorBoxDimensions, colorIndicatorBox, eraser;
+var whiteboardDimensions, colorIndicatorBoxDimensions, colorIndicatorBox, eraser, blocker;
 var colorBoxes = [];
 
 var colors = [
@@ -87,12 +87,13 @@ var light = Entities.addEntity({
     color: {red: 255, green: 255, blue: 255}
 });
 
-var eraseModelPosition = Vec3.sum(center, {x: 0, y: 2, z: 0 });
+var eraserPosition = Vec3.sum(center, {x: 0, y: 2.05, z: 0 });
+eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.1, rotation));
 scriptURL = Script.resolvePath("eraseBoardEntityScript.js");
 var eraser = Entities.addEntity({
     type: "Model",
     modelURL: eraserModelURL,
-    position: eraseModelPosition,
+    position: eraserPosition,
     name: "Eraser",
     script: scriptURL,
     rotation: rotation,
@@ -109,6 +110,17 @@ Script.setTimeout(function() {
 
 
 function setUp() {
+    var blockerPosition = Vec3.sum(center, {x: 0, y: -1, z: 0 });
+    blockerPosition = Vec3.sum(blockerPosition, Vec3.multiply(-1, Quat.getFront(rotation)));
+    blocker = Entities.addEntity({
+        type: "Box",
+        rotation: rotation,
+        position: blockerPosition,
+        dimensions: {x: whiteboardDimensions.x, y: 1, z: 0.1},
+        shapeType: "box",
+        visible: false
+    });
+
     var eraseModelDimensions = Entities.getEntityProperties(eraser, "naturalDimensions").naturalDimensions;
     Entities.editEntity(eraser, {dimensions: eraseModelDimensions});
     Entities.editEntity(colorIndicatorBorder, {dimensions: colorIndicatorBorderDimensions});
@@ -187,6 +199,7 @@ function cleanup() {
     Entities.deleteEntity(colorIndicatorBorder);
     Entities.deleteEntity(eraser);
     Entities.deleteEntity(colorIndicatorBox);
+    Entities.deleteEntity(blocker);
     Entities.deleteEntity(light);
     colorBoxes.forEach(function(colorBox) {
         Entities.deleteEntity(colorBox);
@@ -196,4 +209,4 @@ function cleanup() {
 
 
 // Uncomment this line to delete whiteboard and all associated entity on script close
-// Script.scriptEnding.connect(cleanup);
\ No newline at end of file
+Script.scriptEnding.connect(cleanup);
\ No newline at end of file

From d61b3e5790d5ee78d366836ec060fdec310a800d Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 28 Oct 2015 17:41:52 -0700
Subject: [PATCH 212/301] Fixing controller link requirements

---
 tests/controllers/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/controllers/CMakeLists.txt b/tests/controllers/CMakeLists.txt
index d9bef079ff..d1c8464dd5 100644
--- a/tests/controllers/CMakeLists.txt
+++ b/tests/controllers/CMakeLists.txt
@@ -6,7 +6,7 @@ setup_hifi_project(Script Qml)
 set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
 
 # link in the shared libraries
-link_hifi_libraries(shared script-engine plugins input-plugins display-plugins controllers)
+link_hifi_libraries(shared gl script-engine plugins render-utils input-plugins display-plugins controllers)
 
 
 if (WIN32)

From f01b4dcd9060c3c49f74db69fb6f836eb578b86b Mon Sep 17 00:00:00 2001
From: Seth Alves <seth@highfidelity.io>
Date: Thu, 29 Oct 2015 09:23:19 -0700
Subject: [PATCH 213/301] update cmake to work with newer smi runtime

---
 cmake/modules/FindiViewHMD.cmake | 38 +++++---------------------------
 1 file changed, 5 insertions(+), 33 deletions(-)

diff --git a/cmake/modules/FindiViewHMD.cmake b/cmake/modules/FindiViewHMD.cmake
index f7b13f8124..e408c92380 100644
--- a/cmake/modules/FindiViewHMD.cmake
+++ b/cmake/modules/FindiViewHMD.cmake
@@ -21,45 +21,17 @@ if (WIN32)
     hifi_library_search_hints("iViewHMD")
 
     find_path(IVIEWHMD_INCLUDE_DIRS iViewHMDAPI.h PATH_SUFFIXES include HINTS ${IVIEWHMD_SEARCH_DIRS})
-    find_library(IVIEWHMD_LIBRARIES NAMES iViewHMDAPI PATH_SUFFIXES libs HINTS ${IVIEWHMD_SEARCH_DIRS})
-    find_path(IVIEWHMD_API_DLL_PATH iViewHMDAPI.dll PATH_SUFFIXES libs HINTS ${IVIEWHMD_SEARCH_DIRS})
+    find_library(IVIEWHMD_LIBRARIES NAMES iViewHMDAPI PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS})
+    find_path(IVIEWHMD_API_DLL_PATH iViewHMDAPI.dll PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS})
     list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_API_DLL_PATH)
 
-    set(IVIEWHMD_DLLS
-        avcodec-53.dll
-        avformat-53.dll
-        avutil-51.dll
-        libboost_filesystem-mgw45-mt-1_49.dll
-        libboost_system-mgw45-mt-1_49.dll
-        libboost_thread-mgw45-mt-1_49.dll
-        libgcc_s_dw2-1.dll
-        libiViewNG-LibCore.dll
-        libopencv_calib3d244.dll
-        libopencv_core244.dll
-        libopencv_features2d244.dll
-        libopencv_flann244.dll
-        libopencv_highgui244.dll
-        libopencv_imgproc244.dll
-        libopencv_legacy244.dll
-        libopencv_ml244.dll
-        libopencv_video244.dll
-        libstdc++-6.dll
-        opencv_core220.dll
-        opencv_highgui220.dll
-        opencv_imgproc220.dll
-        swscale-2.dll
-    )
-
-    foreach(IVIEWHMD_DLL ${IVIEWHMD_DLLS})
-        find_path(IVIEWHMD_DLL_PATH ${IVIEWHMD_DLL} PATH_SUFFIXES 3rdParty HINTS ${IVIEWHMD_SEARCH_DIRS})
-        list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_DLL_PATH)
-        list(APPEND IVIEWHMD_DLL_PATHS ${IVIEWHMD_DLL_PATH})
-    endforeach()
+    find_path(IVIEWHMD_DLL_PATH_3RD_PARTY libiViewNG.dll PATH_SUFFIXES 3rdParty HINTS ${IVIEWHMD_SEARCH_DIRS})
+    list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_DLL_PATH_3RD_PARTY)
 
     include(FindPackageHandleStandardArgs)
     find_package_handle_standard_args(IVIEWHMD DEFAULT_MSG ${IVIEWHMD_REQUIREMENTS})
 
-    add_paths_to_fixup_libs(${IVIEWHMD_API_DLL_PATH} ${IVIEWHMD_DLL_PATHS})
+    add_paths_to_fixup_libs(${IVIEWHMD_API_DLL_PATH} ${IVIEWHMD_DLL_PATH_3RD_PARTY})
 
     mark_as_advanced(IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_SEARCH_DIRS)
 

From c4e82a85d9f52124353d92d16900f9a39f055725 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 28 Oct 2015 15:40:52 -0700
Subject: [PATCH 214/301] Remove DeviceProxy in favor of InputDevice

---
 interface/src/Application.cpp                 |  17 +-
 interface/src/Application.h                   |   4 +-
 interface/src/Menu.cpp                        |   2 +
 interface/src/devices/3DConnexionClient.cpp   |   3 +
 interface/src/devices/3DConnexionClient.h     |   3 +
 .../controllers/src/controllers/Actions.cpp   | 152 +++++++++---------
 .../controllers/src/controllers/Actions.h     |  13 +-
 .../src/controllers/DeviceProxy.cpp           |  16 --
 .../controllers/src/controllers/DeviceProxy.h |  11 +-
 .../src/controllers/InputDevice.cpp           |  39 ++++-
 .../controllers/src/controllers/InputDevice.h |  34 ++--
 .../src/controllers/ScriptingInterface.cpp    |   6 +-
 .../src/controllers/StandardController.cpp    | 114 +++++++------
 .../src/controllers/StandardController.h      |   8 +-
 .../src/controllers/StandardControls.h        |   2 +
 .../src/controllers/StateController.cpp       |  35 ++--
 .../src/controllers/StateController.h         |   5 +-
 .../src/controllers/UserInputMapper.cpp       |  47 +++---
 .../src/controllers/UserInputMapper.h         |  15 +-
 .../impl/endpoints/InputEndpoint.cpp          |   8 +-
 libraries/input-plugins/CMakeLists.txt        |   2 +-
 .../src/input-plugins/Joystick.cpp            |  97 ++++++-----
 .../src/input-plugins/Joystick.h              |   5 +-
 .../src/input-plugins/KeyboardMouseDevice.cpp |  38 +++--
 .../src/input-plugins/KeyboardMouseDevice.h   |  14 +-
 .../src/input-plugins/SDL2Manager.cpp         |  24 +--
 .../src/input-plugins/SDL2Manager.h           |   2 +-
 .../src/input-plugins/SixenseManager.cpp      |  66 ++++----
 .../src/input-plugins/SixenseManager.h        |   4 +-
 .../input-plugins/ViveControllerManager.cpp   |  87 ++++------
 .../src/input-plugins/ViveControllerManager.h |   4 +-
 tests/controllers/src/main.cpp                |   2 +-
 32 files changed, 421 insertions(+), 458 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 9c4465aa78..4e4b4010f0 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -636,7 +636,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     });
 
     // A new controllerInput device used to reflect current values from the application state
-    _applicationStateDevice = new controller::StateController("Application");
+    _applicationStateDevice = std::make_shared<controller::StateController>();
     auto InHMDLambda = controller::StateController::ReadLambda([]() -> float {
         return (float) qApp->getAvatarUpdater()->isHMDMode();
     });
@@ -719,8 +719,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     // Now that menu is initalized we can sync myAvatar with it's state.
     getMyAvatar()->updateMotionBehaviorFromMenu();
 
+#if 0
     // the 3Dconnexion device wants to be initiliazed after a window is displayed.
     ConnexionClient::getInstance().init();
+#endif
 
     auto& packetReceiver = nodeList->getPacketReceiver();
     packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket");
@@ -808,8 +810,7 @@ void Application::cleanupBeforeQuit() {
     AnimDebugDraw::getInstance().shutdown();
 
     // FIXME: once we move to shared pointer for the INputDevice we shoud remove this naked delete:
-    delete _applicationStateDevice;
-    _applicationStateDevice = nullptr;
+    _applicationStateDevice.reset();
 
     if (_keyboardFocusHighlightID > 0) {
         getOverlays().deleteOverlay(_keyboardFocusHighlightID);
@@ -921,7 +922,10 @@ Application::~Application() {
     
     Leapmotion::destroy();
     RealSense::destroy();
+
+#if 0
     ConnexionClient::getInstance().destroy();
+#endif
 
     qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages
 }
@@ -1024,7 +1028,10 @@ void Application::initializeUi() {
     foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
         QString name = inputPlugin->getName();
         if (name == KeyboardMouseDevice::NAME) {
-            _keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
+            auto kbm = static_cast<KeyboardMouseDevice*>(inputPlugin.data());
+            // FIXME incredibly evil.... _keyboardMouseDevice is now owned by 
+            // both a QSharedPointer and a std::shared_ptr
+            _keyboardMouseDevice = std::shared_ptr<KeyboardMouseDevice>(kbm);
         }
     }
     updateInputModes();
@@ -1824,7 +1831,9 @@ void Application::focusOutEvent(QFocusEvent* event) {
             inputPlugin->pluginFocusOutEvent();
         }
     }
+#if 0
     ConnexionData::getInstance().focusOutEvent();
+#endif
 
     // synthesize events for keys currently pressed, since we may not get their release events
     foreach (int key, _keysPressed) {
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 50a39bd2eb..bf45a0c6ec 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -446,8 +446,8 @@ private:
 
     OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
 
-    controller::StateController* _applicationStateDevice{ nullptr }; // Default ApplicationDevice reflecting the state of different properties of the session
-    KeyboardMouseDevice* _keyboardMouseDevice{ nullptr };   // Default input device, the good old keyboard mouse and maybe touchpad
+    std::shared_ptr<controller::StateController> _applicationStateDevice; // Default ApplicationDevice reflecting the state of different properties of the session
+    std::shared_ptr<KeyboardMouseDevice> _keyboardMouseDevice;   // Default input device, the good old keyboard mouse and maybe touchpad
     AvatarUpdate* _avatarUpdate {nullptr};
     SimpleMovingAverage _avatarSimsPerSecond {10};
     int _avatarSimsPerSecondReport {0};
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index a393ca5316..1565db2905 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -464,11 +464,13 @@ Menu::Menu() {
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::MeshVisible, 0, true,
                                            avatar, SLOT(setEnableMeshVisible(bool)));
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false);
+#if 0
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu,
                                            MenuOption::Connexion,
                                            0, false,
                                            &ConnexionClient::getInstance(),
                                            SLOT(toggleConnexion(bool)));
+#endif
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ComfortMode, 0, true);
 
     MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
diff --git a/interface/src/devices/3DConnexionClient.cpp b/interface/src/devices/3DConnexionClient.cpp
index 7c44e4eed7..38a9b4cb29 100755
--- a/interface/src/devices/3DConnexionClient.cpp
+++ b/interface/src/devices/3DConnexionClient.cpp
@@ -9,8 +9,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
+
 #include "3DConnexionClient.h"
 
+#if 0
 #include <UserActivityLogger.h>
 #include <PathUtils.h>
 
@@ -967,3 +969,4 @@ void MessageHandler(unsigned int connection, unsigned int messageType, void *mes
 #endif // __APPLE__
 
 #endif // HAVE_3DCONNEXIONCLIENT
+#endif
\ No newline at end of file
diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h
index 8489d54913..03a43d4c64 100755
--- a/interface/src/devices/3DConnexionClient.h
+++ b/interface/src/devices/3DConnexionClient.h
@@ -11,6 +11,7 @@
 #ifndef hifi_3DConnexionClient_h
 #define hifi_3DConnexionClient_h
 
+#if 0
 #include <QObject>
 #include <QLibrary>
 #include <controllers/UserInputMapper.h>
@@ -217,4 +218,6 @@ public:
     void handleAxisEvent();
 };
 
+#endif
+
 #endif // defined(hifi_3DConnexionClient_h)
diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp
index a9bd32b1d8..a4a8656fb7 100644
--- a/libraries/controllers/src/controllers/Actions.cpp
+++ b/libraries/controllers/src/controllers/Actions.cpp
@@ -8,7 +8,7 @@
 
 #include "Actions.h"
 
-#include "UserInputMapper.h"
+#include "impl/endpoints/ActionEndpoint.h"
 
 namespace controller {
 
@@ -29,86 +29,80 @@ namespace controller {
         return makePair(ChannelType::POSE, action, name);
     }
 
-    // Device functions
-    void ActionsDevice::buildDeviceProxy(DeviceProxy::Pointer proxy) {
-        proxy->_name = _name;
-        proxy->getButton = [this](const Input& input, int timestamp) -> bool { return false; };
-        proxy->getAxis = [this](const Input& input, int timestamp) -> float { return 0; };
-        proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
-            QVector<Input::NamedPair> availableInputs{
-                makeAxisPair(Action::TRANSLATE_X, "TranslateX"),
-                makeAxisPair(Action::TRANSLATE_Y, "TranslateY"),
-                makeAxisPair(Action::TRANSLATE_Z, "TranslateZ"),
-                makeAxisPair(Action::ROLL, "Roll"),
-                makeAxisPair(Action::PITCH, "Pitch"),
-                makeAxisPair(Action::YAW, "Yaw"),
-                makeAxisPair(Action::STEP_YAW, "StepYaw"),
-                makeAxisPair(Action::STEP_PITCH, "StepPitch"),
-                makeAxisPair(Action::STEP_ROLL, "StepRoll"),
-                makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateX"),
-                makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateY"),
-                makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateZ"),
-
-                makePosePair(Action::LEFT_HAND, "LeftHand"),
-                makePosePair(Action::RIGHT_HAND, "RightHand"),
-
-                makeButtonPair(Action::LEFT_HAND_CLICK, "LeftHandClick"),
-                makeButtonPair(Action::RIGHT_HAND_CLICK, "RightHandClick"),
-
-                makeButtonPair(Action::SHIFT, "Shift"),
-                makeButtonPair(Action::ACTION1, "PrimaryAction"),
-                makeButtonPair(Action::ACTION2, "SecondaryAction"),
-                makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"),
-                makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"),
-
-                // Aliases and bisected versions
-                makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),
-                makeAxisPair(Action::LONGITUDINAL_FORWARD, "Forward"),
-                makeAxisPair(Action::LATERAL_LEFT, "StrafeLeft"),
-                makeAxisPair(Action::LATERAL_RIGHT, "StrafeRight"),
-                makeAxisPair(Action::VERTICAL_DOWN, "Down"),
-                makeAxisPair(Action::VERTICAL_UP, "Up"),
-                makeAxisPair(Action::YAW_LEFT, "YawLeft"),
-                makeAxisPair(Action::YAW_RIGHT, "YawRight"),
-                makeAxisPair(Action::PITCH_DOWN, "PitchDown"),
-                makeAxisPair(Action::PITCH_UP, "PitchUp"),
-                makeAxisPair(Action::BOOM_IN, "BoomIn"),
-                makeAxisPair(Action::BOOM_OUT, "BoomOut"),
-
-                // Deprecated aliases
-                // FIXME remove after we port all scripts
-                makeAxisPair(Action::LONGITUDINAL_BACKWARD, "LONGITUDINAL_BACKWARD"),
-                makeAxisPair(Action::LONGITUDINAL_FORWARD, "LONGITUDINAL_FORWARD"),
-                makeAxisPair(Action::LATERAL_LEFT, "LATERAL_LEFT"),
-                makeAxisPair(Action::LATERAL_RIGHT, "LATERAL_RIGHT"),
-                makeAxisPair(Action::VERTICAL_DOWN, "VERTICAL_DOWN"),
-                makeAxisPair(Action::VERTICAL_UP, "VERTICAL_UP"),
-                makeAxisPair(Action::YAW_LEFT, "YAW_LEFT"),
-                makeAxisPair(Action::YAW_RIGHT, "YAW_RIGHT"),
-                makeAxisPair(Action::PITCH_DOWN, "PITCH_DOWN"),
-                makeAxisPair(Action::PITCH_UP, "PITCH_UP"),
-                makeAxisPair(Action::BOOM_IN, "BOOM_IN"),
-                makeAxisPair(Action::BOOM_OUT, "BOOM_OUT"),
-
-                makePosePair(Action::LEFT_HAND, "LEFT_HAND"),
-                makePosePair(Action::RIGHT_HAND, "RIGHT_HAND"),
-
-                makeButtonPair(Action::LEFT_HAND_CLICK, "LEFT_HAND_CLICK"),
-                makeButtonPair(Action::RIGHT_HAND_CLICK, "RIGHT_HAND_CLICK"),
-
-                makeButtonPair(Action::SHIFT, "SHIFT"),
-                makeButtonPair(Action::ACTION1, "ACTION1"),
-                makeButtonPair(Action::ACTION2, "ACTION2"),
-                makeButtonPair(Action::CONTEXT_MENU, "CONTEXT_MENU"),
-                makeButtonPair(Action::TOGGLE_MUTE, "TOGGLE_MUTE"),
-            };
-            return availableInputs;
-        };
-
+    EndpointPointer ActionsDevice::createEndpoint(const Input& input) const {
+        return std::make_shared<ActionEndpoint>(input);
     }
 
-    QString ActionsDevice::getDefaultMappingConfig() {
-        return QString();
+    // Device functions
+    Input::NamedVector ActionsDevice::getAvailableInputs() const {
+        static Input::NamedVector availableInputs {
+            makeAxisPair(Action::TRANSLATE_X, "TranslateX"),
+            makeAxisPair(Action::TRANSLATE_Y, "TranslateY"),
+            makeAxisPair(Action::TRANSLATE_Z, "TranslateZ"),
+            makeAxisPair(Action::ROLL, "Roll"),
+            makeAxisPair(Action::PITCH, "Pitch"),
+            makeAxisPair(Action::YAW, "Yaw"),
+            makeAxisPair(Action::STEP_YAW, "StepYaw"),
+            makeAxisPair(Action::STEP_PITCH, "StepPitch"),
+            makeAxisPair(Action::STEP_ROLL, "StepRoll"),
+            makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateX"),
+            makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateY"),
+            makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateZ"),
+
+            makePosePair(Action::LEFT_HAND, "LeftHand"),
+            makePosePair(Action::RIGHT_HAND, "RightHand"),
+
+            makeButtonPair(Action::LEFT_HAND_CLICK, "LeftHandClick"),
+            makeButtonPair(Action::RIGHT_HAND_CLICK, "RightHandClick"),
+
+            makeButtonPair(Action::SHIFT, "Shift"),
+            makeButtonPair(Action::ACTION1, "PrimaryAction"),
+            makeButtonPair(Action::ACTION2, "SecondaryAction"),
+            makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"),
+            makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"),
+
+            // Aliases and bisected versions
+            makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),
+            makeAxisPair(Action::LONGITUDINAL_FORWARD, "Forward"),
+            makeAxisPair(Action::LATERAL_LEFT, "StrafeLeft"),
+            makeAxisPair(Action::LATERAL_RIGHT, "StrafeRight"),
+            makeAxisPair(Action::VERTICAL_DOWN, "Down"),
+            makeAxisPair(Action::VERTICAL_UP, "Up"),
+            makeAxisPair(Action::YAW_LEFT, "YawLeft"),
+            makeAxisPair(Action::YAW_RIGHT, "YawRight"),
+            makeAxisPair(Action::PITCH_DOWN, "PitchDown"),
+            makeAxisPair(Action::PITCH_UP, "PitchUp"),
+            makeAxisPair(Action::BOOM_IN, "BoomIn"),
+            makeAxisPair(Action::BOOM_OUT, "BoomOut"),
+
+            // Deprecated aliases
+            // FIXME remove after we port all scripts
+            makeAxisPair(Action::LONGITUDINAL_BACKWARD, "LONGITUDINAL_BACKWARD"),
+            makeAxisPair(Action::LONGITUDINAL_FORWARD, "LONGITUDINAL_FORWARD"),
+            makeAxisPair(Action::LATERAL_LEFT, "LATERAL_LEFT"),
+            makeAxisPair(Action::LATERAL_RIGHT, "LATERAL_RIGHT"),
+            makeAxisPair(Action::VERTICAL_DOWN, "VERTICAL_DOWN"),
+            makeAxisPair(Action::VERTICAL_UP, "VERTICAL_UP"),
+            makeAxisPair(Action::YAW_LEFT, "YAW_LEFT"),
+            makeAxisPair(Action::YAW_RIGHT, "YAW_RIGHT"),
+            makeAxisPair(Action::PITCH_DOWN, "PITCH_DOWN"),
+            makeAxisPair(Action::PITCH_UP, "PITCH_UP"),
+            makeAxisPair(Action::BOOM_IN, "BOOM_IN"),
+            makeAxisPair(Action::BOOM_OUT, "BOOM_OUT"),
+
+            makePosePair(Action::LEFT_HAND, "LEFT_HAND"),
+            makePosePair(Action::RIGHT_HAND, "RIGHT_HAND"),
+
+            makeButtonPair(Action::LEFT_HAND_CLICK, "LEFT_HAND_CLICK"),
+            makeButtonPair(Action::RIGHT_HAND_CLICK, "RIGHT_HAND_CLICK"),
+
+            makeButtonPair(Action::SHIFT, "SHIFT"),
+            makeButtonPair(Action::ACTION1, "ACTION1"),
+            makeButtonPair(Action::ACTION2, "ACTION2"),
+            makeButtonPair(Action::CONTEXT_MENU, "CONTEXT_MENU"),
+            makeButtonPair(Action::TOGGLE_MUTE, "TOGGLE_MUTE"),
+        };
+        return availableInputs;
     }
 
     void ActionsDevice::update(float deltaTime, bool jointsCaptured) {
diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h
index 971da13cf0..36df695032 100644
--- a/libraries/controllers/src/controllers/Actions.h
+++ b/libraries/controllers/src/controllers/Actions.h
@@ -89,11 +89,8 @@ class ActionsDevice : public QObject, public InputDevice {
     Q_PROPERTY(QString name READ getName)
 
 public:
-    const QString& getName() const { return _name; }
-
-    // Device functions
-    virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override;
-    virtual QString getDefaultMappingConfig() override;
+    virtual EndpointPointer createEndpoint(const Input& input) const override;
+    virtual Input::NamedVector getAvailableInputs() const override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
@@ -103,10 +100,4 @@ public:
 
 }
 
-
-
-
-#include "StandardControls.h"
-
-
 #endif // hifi_StandardController_h
diff --git a/libraries/controllers/src/controllers/DeviceProxy.cpp b/libraries/controllers/src/controllers/DeviceProxy.cpp
index 1bd65d4900..f3e9526080 100644
--- a/libraries/controllers/src/controllers/DeviceProxy.cpp
+++ b/libraries/controllers/src/controllers/DeviceProxy.cpp
@@ -10,21 +10,5 @@
 #include "DeviceProxy.h"
 
 namespace controller {
-
-    float DeviceProxy::getValue(const Input& input, int timestamp) const {
-        switch (input.getType()) {
-        case ChannelType::BUTTON:
-            return getButton(input, timestamp) ? 1.0f : 0.0f;
-
-        case ChannelType::AXIS:
-            return getAxis(input, timestamp);
-
-        case ChannelType::POSE:
-            return getPose(input, timestamp).valid ? 1.0f : 0.0f;
-
-        default:
-            return NAN;
-        }
-    }
 }
 
diff --git a/libraries/controllers/src/controllers/DeviceProxy.h b/libraries/controllers/src/controllers/DeviceProxy.h
index 5f94e748f7..83a813d5d5 100644
--- a/libraries/controllers/src/controllers/DeviceProxy.h
+++ b/libraries/controllers/src/controllers/DeviceProxy.h
@@ -20,7 +20,7 @@
 #include "Pose.h"
 
 namespace controller {
-
+    /*
     using Modifiers = std::vector<Input>;
     typedef QPair<Input, QString> InputPair;
     class Endpoint;
@@ -38,17 +38,10 @@ namespace controller {
     class DeviceProxy {
     public:
         using Pointer = std::shared_ptr<DeviceProxy>;
-        const QString& getName() const { return _name; }
-        ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
-        AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; };
-        PoseGetter getPose = [](const Input& input, int timestamp) -> Pose { return Pose(); };
-        AvailableInputGetter getAvailabeInputs = []() -> Input::NamedVector const { return Input::NamedVector(); };
-        float getValue(const Input& input, int timestamp = 0) const;
-        
-        EndpointCreator createEndpoint = [](const Input& input) -> EndpointPtr { return EndpointPtr(); };
 
         QString _name;
     };
+    */
 }
 
 #endif
diff --git a/libraries/controllers/src/controllers/InputDevice.cpp b/libraries/controllers/src/controllers/InputDevice.cpp
index 78e920d4b5..d5044a219f 100644
--- a/libraries/controllers/src/controllers/InputDevice.cpp
+++ b/libraries/controllers/src/controllers/InputDevice.cpp
@@ -11,6 +11,7 @@
 #include "InputDevice.h"
 
 #include "Input.h"
+#include "impl/endpoints/InputEndpoint.h"
 
 namespace controller {
 
@@ -59,29 +60,55 @@ namespace controller {
         }
     }
 
-    Input InputDevice::makeInput(controller::StandardButtonChannel button) {
+    Input InputDevice::makeInput(controller::StandardButtonChannel button) const {
         return Input(_deviceID, button, ChannelType::BUTTON);
     }
 
-    Input InputDevice::makeInput(controller::StandardAxisChannel axis) {
+    Input InputDevice::makeInput(controller::StandardAxisChannel axis) const {
         return Input(_deviceID, axis, ChannelType::AXIS);
     }
 
-    Input InputDevice::makeInput(controller::StandardPoseChannel pose) {
+    Input InputDevice::makeInput(controller::StandardPoseChannel pose) const {
         return Input(_deviceID, pose, ChannelType::POSE);
     }
 
-    Input::NamedPair InputDevice::makePair(controller::StandardButtonChannel button, const QString& name) {
+    Input::NamedPair InputDevice::makePair(controller::StandardButtonChannel button, const QString& name) const {
         return Input::NamedPair(makeInput(button), name);
     }
 
-    Input::NamedPair InputDevice::makePair(controller::StandardAxisChannel axis, const QString& name) {
+    Input::NamedPair InputDevice::makePair(controller::StandardAxisChannel axis, const QString& name) const {
         return Input::NamedPair(makeInput(axis), name);
     }
 
-    Input::NamedPair InputDevice::makePair(controller::StandardPoseChannel pose, const QString& name) {
+    Input::NamedPair InputDevice::makePair(controller::StandardPoseChannel pose, const QString& name) const {
         return Input::NamedPair(makeInput(pose), name);
     }
 
+    float InputDevice::getValue(ChannelType channelType, uint16_t channel) const {
+        switch (channelType) {
+            case ChannelType::AXIS:
+                return getAxis(channel);
+
+            case ChannelType::BUTTON:
+                return getButton(channel);
+
+            case ChannelType::POSE:
+                return getPose(channel).valid ? 1.0f : 0.0f;
+
+            default:
+                break;
+        }
+
+        return 0.0f;
+    }
+
+
+    float InputDevice::getValue(const Input& input) const {
+        return getValue(input.getType(), input.channel);
+    }
+
+    EndpointPointer InputDevice::createEndpoint(const Input& input) const {
+        return std::make_shared<InputEndpoint>(input);
+    }
 
 }
diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h
index e01def2368..fc3477b41a 100644
--- a/libraries/controllers/src/controllers/InputDevice.h
+++ b/libraries/controllers/src/controllers/InputDevice.h
@@ -21,12 +21,16 @@
 #include "StandardControls.h"
 #include "DeviceProxy.h"
 
+
 // Event types for each controller
 const unsigned int CONTROLLER_0_EVENT = 1500U;
 const unsigned int CONTROLLER_1_EVENT = 1501U;
 
 namespace controller {
 
+class Endpoint;
+using EndpointPointer = std::shared_ptr<Endpoint>;
+
 // NOTE: If something inherits from both InputDevice and InputPlugin, InputPlugin must go first.
 // e.g. class Example : public InputPlugin, public InputDevice
 // instead of class Example : public InputDevice, public InputPlugin
@@ -45,8 +49,11 @@ public:
     float getAxis(int channel) const;
     Pose getPose(int channel) const;
 
-    virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) = 0;
-    virtual QString getDefaultMappingConfig() = 0;
+    float getValue(const Input& input) const;
+    float getValue(ChannelType channelType, uint16_t channel) const;
+    Pose getPoseValue(uint16_t channel) const;
+    
+    const QString& getName() const { return _name; }
 
     // Update call MUST be called once per simulation loop
     // It takes care of updating the action states and deltas
@@ -63,20 +70,25 @@ public:
 
     static bool getLowVelocityFilter() { return _lowVelocityFilter; };
 
-    Input makeInput(StandardButtonChannel button);
-    Input makeInput(StandardAxisChannel axis);
-    Input makeInput(StandardPoseChannel pose);
-    Input::NamedPair makePair(StandardButtonChannel button, const QString& name);
-    Input::NamedPair makePair(StandardAxisChannel button, const QString& name);
-    Input::NamedPair makePair(StandardPoseChannel button, const QString& name);
-    public slots:
+    Input makeInput(StandardButtonChannel button) const;
+    Input makeInput(StandardAxisChannel axis) const;
+    Input makeInput(StandardPoseChannel pose) const;
+    Input::NamedPair makePair(StandardButtonChannel button, const QString& name) const;
+    Input::NamedPair makePair(StandardAxisChannel button, const QString& name) const;
+    Input::NamedPair makePair(StandardPoseChannel button, const QString& name) const;
+public slots:
     static void setLowVelocityFilter(bool newLowVelocityFilter) { _lowVelocityFilter = newLowVelocityFilter; };
 
 protected:
     friend class UserInputMapper;
-    uint16_t _deviceID{ Input::INVALID_DEVICE };
 
-    QString _name;
+    virtual Input::NamedVector getAvailableInputs() const = 0;
+    virtual QString getDefaultMappingConfig() const { return QString(); }
+    virtual EndpointPointer createEndpoint(const Input& input) const;
+
+    uint16_t _deviceID { Input::INVALID_DEVICE };
+
+    const QString _name;
 
     ButtonPressedMap _buttonPressedMap;
     AxisStateMap _axisStateMap;
diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index 8d00000c45..e49248e8f0 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -27,10 +27,10 @@
 
 static QRegularExpression SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" };
 
-static QVariantMap createDeviceMap(const controller::DeviceProxy::Pointer device) {
+static QVariantMap createDeviceMap(const controller::InputDevice::Pointer device) {
     auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
     QVariantMap deviceMap;
-    for (const auto& inputMapping : device->getAvailabeInputs()) {
+    for (const auto& inputMapping : userInputMapper->getAvailableInputs(device->getDeviceID())) {
         const auto& input = inputMapping.first;
         const auto inputName = QString(inputMapping.second).remove(SANITIZE_NAME_EXPRESSION);
         qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType()
@@ -179,7 +179,7 @@ namespace controller {
         return DependencyManager::get<UserInputMapper>()->getDeviceName((unsigned short)device);
     }
 
-    QVector<InputPair> ScriptingInterface::getAvailableInputs(unsigned int device) {
+    QVector<Input::NamedPair> ScriptingInterface::getAvailableInputs(unsigned int device) {
         return DependencyManager::get<UserInputMapper>()->getAvailableInputs((unsigned short)device);
     }
 
diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index fc62f85b81..44f1bff1ae 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -13,8 +13,8 @@
 
 #include <PathUtils.h>
 
-#include "DeviceProxy.h"
 #include "UserInputMapper.h"
+#include "impl/endpoints/StandardEndpoint.h"
 
 namespace controller {
 
@@ -33,91 +33,87 @@ void StandardController::focusOutEvent() {
     _buttonPressedMap.clear();
 };
 
-void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
-    proxy->_name = _name;
-    proxy->getButton = [this] (const Input& input, int timestamp) -> bool { return getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const Input& input, int timestamp) -> float { return getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<Input::NamedPair> {
-        QVector<Input::NamedPair> availableInputs;
+Input::NamedVector StandardController::getAvailableInputs() const {
+    static Input::NamedVector availableInputs {
         // Buttons
-        availableInputs.append(makePair(A, "A"));
-        availableInputs.append(makePair(B, "B"));
-        availableInputs.append(makePair(X, "X"));
-        availableInputs.append(makePair(Y, "Y"));
+        makePair(A, "A"),
+        makePair(B, "B"),
+        makePair(X, "X"),
+        makePair(Y, "Y"),
 
         // DPad
-        availableInputs.append(makePair(DU, "DU"));
-        availableInputs.append(makePair(DD, "DD"));
-        availableInputs.append(makePair(DL, "DL"));
-        availableInputs.append(makePair(DR, "DR"));
+        makePair(DU, "DU"),
+        makePair(DD, "DD"),
+        makePair(DL, "DL"),
+        makePair(DR, "DR"),
 
         // Bumpers
-        availableInputs.append(makePair(LB, "LB"));
-        availableInputs.append(makePair(RB, "RB"));
+        makePair(LB, "LB"),
+        makePair(RB, "RB"),
 
         // Stick press
-        availableInputs.append(makePair(LS, "LS"));
-        availableInputs.append(makePair(RS, "RS"));
+        makePair(LS, "LS"),
+        makePair(RS, "RS"),
 
         // Center buttons
-        availableInputs.append(makePair(START, "Start"));
-        availableInputs.append(makePair(BACK, "Back"));
+        makePair(START, "Start"),
+        makePair(BACK, "Back"),
 
         // Analog sticks
-        availableInputs.append(makePair(LY, "LY"));
-        availableInputs.append(makePair(LX, "LX"));
-        availableInputs.append(makePair(RY, "RY"));
-        availableInputs.append(makePair(RX, "RX"));
+        makePair(LY, "LY"),
+        makePair(LX, "LX"),
+        makePair(RY, "RY"),
+        makePair(RX, "RX"),
 
         // Triggers
-        availableInputs.append(makePair(LT, "LT"));
-        availableInputs.append(makePair(RT, "RT"));
+        makePair(LT, "LT"),
+        makePair(RT, "RT"),
 
 
         // Finger abstractions
-        availableInputs.append(makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"));
-        availableInputs.append(makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"));
-        availableInputs.append(makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"));
-        availableInputs.append(makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"));
+        makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"),
+        makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"),
+        makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"),
+        makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"),
 
-        availableInputs.append(makePair(LEFT_PRIMARY_INDEX, "LeftPrimaryIndex"));
-        availableInputs.append(makePair(LEFT_SECONDARY_INDEX, "LeftSecondaryIndex"));
-        availableInputs.append(makePair(RIGHT_PRIMARY_INDEX, "RightPrimaryIndex"));
-        availableInputs.append(makePair(RIGHT_SECONDARY_INDEX, "RightSecondaryIndex"));
+        makePair(LEFT_PRIMARY_INDEX, "LeftPrimaryIndex"),
+        makePair(LEFT_SECONDARY_INDEX, "LeftSecondaryIndex"),
+        makePair(RIGHT_PRIMARY_INDEX, "RightPrimaryIndex"),
+        makePair(RIGHT_SECONDARY_INDEX, "RightSecondaryIndex"),
 
-        availableInputs.append(makePair(LEFT_GRIP, "LeftGrip"));
-        availableInputs.append(makePair(RIGHT_GRIP, "RightGrip"));
+        makePair(LEFT_GRIP, "LeftGrip"),
+        makePair(RIGHT_GRIP, "RightGrip"),
 
         // Poses
-        availableInputs.append(makePair(LEFT_HAND, "LeftHand"));
-        availableInputs.append(makePair(RIGHT_HAND, "RightHand"));
+        makePair(LEFT_HAND, "LeftHand"),
+        makePair(RIGHT_HAND, "RightHand"),
 
 
         // Aliases, PlayStation style names
-        availableInputs.append(makePair(LB, "L1"));
-        availableInputs.append(makePair(RB, "R1"));
-        availableInputs.append(makePair(LT, "L2"));
-        availableInputs.append(makePair(RT, "R2"));
-        availableInputs.append(makePair(LS, "L3"));
-        availableInputs.append(makePair(RS, "R3"));
-        availableInputs.append(makePair(BACK, "Select"));
-        availableInputs.append(makePair(A, "Cross"));
-        availableInputs.append(makePair(B, "Circle"));
-        availableInputs.append(makePair(X, "Square"));
-        availableInputs.append(makePair(Y, "Triangle"));
-        availableInputs.append(makePair(DU, "Up"));
-        availableInputs.append(makePair(DD, "Down"));
-        availableInputs.append(makePair(DL, "Left"));
-        availableInputs.append(makePair(DR, "Right"));
-
-
-
-        return availableInputs;
+        makePair(LB, "L1"),
+        makePair(RB, "R1"),
+        makePair(LT, "L2"),
+        makePair(RT, "R2"),
+        makePair(LS, "L3"),
+        makePair(RS, "R3"),
+        makePair(BACK, "Select"),
+        makePair(A, "Cross"),
+        makePair(B, "Circle"),
+        makePair(X, "Square"),
+        makePair(Y, "Triangle"),
+        makePair(DU, "Up"),
+        makePair(DD, "Down"),
+        makePair(DL, "Left"),
+        makePair(DR, "Right"),
     };
+    return availableInputs;
 }
 
+EndpointPointer StandardController::createEndpoint(const Input& input) const {
+    return std::make_shared<StandardEndpoint>(input);
+}
 
-QString StandardController::getDefaultMappingConfig() {
+QString StandardController::getDefaultMappingConfig() const {
     static const QString DEFAULT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard.json";
     return DEFAULT_MAPPING_JSON;
 }
diff --git a/libraries/controllers/src/controllers/StandardController.h b/libraries/controllers/src/controllers/StandardController.h
index 4aad513553..6c18c76371 100644
--- a/libraries/controllers/src/controllers/StandardController.h
+++ b/libraries/controllers/src/controllers/StandardController.h
@@ -25,11 +25,9 @@ class StandardController : public QObject, public InputDevice {
     Q_PROPERTY(QString name READ getName)
 
 public:
-    const QString& getName() const { return _name; }
-
-    // Device functions
-    virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override;
-    virtual QString getDefaultMappingConfig() override;
+    virtual EndpointPointer createEndpoint(const Input& input) const override;
+    virtual Input::NamedVector getAvailableInputs() const override;
+    virtual QString getDefaultMappingConfig() const override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h
index 066a3e5e60..9c6defb865 100644
--- a/libraries/controllers/src/controllers/StandardControls.h
+++ b/libraries/controllers/src/controllers/StandardControls.h
@@ -58,9 +58,11 @@ namespace controller {
         // Left Analog stick
         LX = 0,
         LY,
+        LZ,
         // Right Analog stick
         RX,
         RY,
+        RZ,
         // Triggers
         LT,
         RT,
diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp
index 29b30bc24e..efe7a064fc 100644
--- a/libraries/controllers/src/controllers/StateController.cpp
+++ b/libraries/controllers/src/controllers/StateController.cpp
@@ -19,7 +19,7 @@
 
 namespace controller {
 
-StateController::StateController(QString name) : InputDevice(name) {
+StateController::StateController() : InputDevice("Application") {
 }
 
 StateController::~StateController() {
@@ -32,30 +32,15 @@ void StateController::focusOutEvent() {}
 void StateController::addInputVariant(QString name, ReadLambda& lambda) {
     _namedReadLambdas.push_back(NamedReadLambda(name, lambda));
 }
-void StateController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
-    proxy->_name = _name;
-    proxy->getButton = [this] (const Input& input, int timestamp) -> bool { return getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const Input& input, int timestamp) -> float { return getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<Input::NamedPair> {
-    
-        
-        QVector<Input::NamedPair> availableInputs;
-        
-        int i = 0;
-        for (auto& pair : _namedReadLambdas) {
-            availableInputs.push_back(Input::NamedPair(Input(_deviceID, i, ChannelType::BUTTON), pair.first));
-            i++;
-        }
-        return availableInputs;
-    };
-    proxy->createEndpoint = [this] (const Input& input) -> Endpoint::Pointer {
-        if (input.getChannel() < _namedReadLambdas.size()) {
-            return std::make_shared<LambdaEndpoint>(_namedReadLambdas[input.getChannel()].second);
-        }
 
-        return Endpoint::Pointer();
-    };
+Input::NamedVector StateController::getAvailableInputs() const {
+    Input::NamedVector availableInputs;
+    int i = 0;
+    for (auto& pair : _namedReadLambdas) {
+        availableInputs.push_back(Input::NamedPair(Input(_deviceID, i, ChannelType::BUTTON), pair.first));
+        i++;
+    }
+    return availableInputs;
 }
 
-
-}
+}
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/StateController.h b/libraries/controllers/src/controllers/StateController.h
index fad3b0abba..d664c6b8d0 100644
--- a/libraries/controllers/src/controllers/StateController.h
+++ b/libraries/controllers/src/controllers/StateController.h
@@ -27,12 +27,11 @@ public:
     const QString& getName() const { return _name; }
 
     // Device functions
-    virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override;
-    virtual QString getDefaultMappingConfig() override { return QString(); }
+    virtual Input::NamedVector getAvailableInputs() const override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
-    StateController(QString name);
+    StateController();
     virtual ~StateController();
 
     using ReadLambda = std::function<float()>;
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 257e4ebe85..64a2a54ef4 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -49,13 +49,13 @@ namespace controller {
 
 // Default contruct allocate the poutput size with the current hardcoded action channels
 controller::UserInputMapper::UserInputMapper() {
-    _standardController = std::make_shared<StandardController>();
-    registerDevice(new ActionsDevice());
-    registerDevice(_standardController.get());
+    registerDevice(std::make_shared<ActionsDevice>());
+    registerDevice(std::make_shared<StandardController>());
 }
 
 namespace controller {
 
+    
 UserInputMapper::~UserInputMapper() {
 }
 
@@ -67,31 +67,24 @@ int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
     return _deviceCounts[deviceName];
 }
 
-void UserInputMapper::registerDevice(InputDevice* device) {
+void UserInputMapper::registerDevice(InputDevice::Pointer device) {
     Locker locker(_lock);
     if (device->_deviceID == Input::INVALID_DEVICE) {
         device->_deviceID = getFreeDeviceID();
     }
     const auto& deviceID = device->_deviceID;
-    DeviceProxy::Pointer proxy = std::make_shared<DeviceProxy>();
-    proxy->_name = device->_name;
-    device->buildDeviceProxy(proxy);
 
-    int numberOfType = recordDeviceOfType(proxy->_name);
-    if (numberOfType > 1) {
-        proxy->_name += QString::number(numberOfType);
-    }
+    int numberOfType = recordDeviceOfType(device->getName());
 
-    qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
-
-    for (const auto& inputMapping : proxy->getAvailabeInputs()) {
+    qCDebug(controllers) << "Registered input device <" << device->getName() << "> deviceID = " << deviceID;
+    for (const auto& inputMapping : device->getAvailableInputs()) {
         const auto& input = inputMapping.first;
         // Ignore aliases
         if (_endpointsByInput.count(input)) {
             continue;
         }
 
-        Endpoint::Pointer endpoint = proxy->createEndpoint(input);
+        Endpoint::Pointer endpoint = device->createEndpoint(input);
         if (!endpoint) {
             if (input.device == STANDARD_DEVICE) {
                 endpoint = std::make_shared<StandardEndpoint>(input);
@@ -105,7 +98,7 @@ void UserInputMapper::registerDevice(InputDevice* device) {
         _endpointsByInput[input] = endpoint;
     }
 
-    _registeredDevices[deviceID] = proxy;
+    _registeredDevices[deviceID] = device;
     auto mapping = loadMapping(device->getDefaultMappingConfig());
     if (mapping) {
         _mappingsByDevice[deviceID] = mapping;
@@ -136,13 +129,13 @@ void UserInputMapper::removeDevice(int deviceID) {
 }
 
 
-DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
+InputDevice::Pointer UserInputMapper::getDevice(const Input& input) {
     Locker locker(_lock);
     auto device = _registeredDevices.find(input.getDevice());
     if (device != _registeredDevices.end()) {
         return (device->second);
     } else {
-        return DeviceProxy::Pointer();
+        return InputDevice::Pointer();
     }
 }
 
@@ -190,8 +183,8 @@ Input UserInputMapper::findDeviceInput(const QString& inputName) const {
 
         int deviceID = findDevice(deviceName);
         if (deviceID != Input::INVALID_DEVICE) {
-            const auto& deviceProxy = _registeredDevices.at(deviceID);
-            auto deviceInputs = deviceProxy->getAvailabeInputs();
+            const auto& device = _registeredDevices.at(deviceID);
+            auto deviceInputs = device->getAvailableInputs();
 
             for (auto input : deviceInputs) {
                 if (input.second == inputName) {
@@ -273,7 +266,7 @@ void UserInputMapper::update(float deltaTime) {
 Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const {
     Locker locker(_lock);
     auto iterator = _registeredDevices.find(deviceID);
-    return iterator->second->getAvailabeInputs();
+    return iterator->second->getAvailableInputs();
 }
 
 QVector<Action> UserInputMapper::getAllActions() const {
@@ -336,7 +329,7 @@ void UserInputMapper::assignDefaulActionScales() {
 
 static int actionMetaTypeId = qRegisterMetaType<Action>();
 static int inputMetaTypeId = qRegisterMetaType<Input>();
-static int inputPairMetaTypeId = qRegisterMetaType<InputPair>();
+static int inputPairMetaTypeId = qRegisterMetaType<Input::NamedPair>();
 static int poseMetaTypeId = qRegisterMetaType<controller::Pose>("Pose");
 
 
@@ -344,8 +337,8 @@ QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input);
 void inputFromScriptValue(const QScriptValue& object, Input& input);
 QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action);
 void actionFromScriptValue(const QScriptValue& object, Action& action);
-QScriptValue inputPairToScriptValue(QScriptEngine* engine, const InputPair& inputPair);
-void inputPairFromScriptValue(const QScriptValue& object, InputPair& inputPair);
+QScriptValue inputPairToScriptValue(QScriptEngine* engine, const Input::NamedPair& inputPair);
+void inputPairFromScriptValue(const QScriptValue& object, Input::NamedPair& inputPair);
 
 QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input) {
     QScriptValue obj = engine->newObject();
@@ -372,21 +365,21 @@ void actionFromScriptValue(const QScriptValue& object, Action& action) {
     action = Action(object.property("action").toVariant().toInt());
 }
 
-QScriptValue inputPairToScriptValue(QScriptEngine* engine, const InputPair& inputPair) {
+QScriptValue inputPairToScriptValue(QScriptEngine* engine, const Input::NamedPair& inputPair) {
     QScriptValue obj = engine->newObject();
     obj.setProperty("input", inputToScriptValue(engine, inputPair.first));
     obj.setProperty("inputName", inputPair.second);
     return obj;
 }
 
-void inputPairFromScriptValue(const QScriptValue& object, InputPair& inputPair) {
+void inputPairFromScriptValue(const QScriptValue& object, Input::NamedPair& inputPair) {
     inputFromScriptValue(object.property("input"), inputPair.first);
     inputPair.second = QString(object.property("inputName").toVariant().toString());
 }
 
 void UserInputMapper::registerControllerTypes(QScriptEngine* engine) {
     qScriptRegisterSequenceMetaType<QVector<Action> >(engine);
-    qScriptRegisterSequenceMetaType<QVector<InputPair> >(engine);
+    qScriptRegisterSequenceMetaType<Input::NamedVector>(engine);
     qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
     qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
     qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index e28fbd740d..884e303fc6 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -42,7 +42,6 @@ namespace controller {
             Q_ENUMS(Action)
 
     public:
-        using InputPair = Input::NamedPair;
         // FIXME move to unordered set / map
         using EndpointToInputMap = std::map<EndpointPointer, Input>;
         using MappingNameMap = std::map<QString, MappingPointer>;
@@ -52,7 +51,7 @@ namespace controller {
         using EndpointSet = std::unordered_set<EndpointPointer>;
         using EndpointPair = std::pair<EndpointPointer, EndpointPointer>;
         using EndpointPairMap = std::map<EndpointPair, EndpointPointer>;
-        using DevicesMap = std::map<int, DeviceProxy::Pointer>;
+        using DevicesMap = std::map<int, InputDevice::Pointer>;
         using uint16 = uint16_t;
         using uint32 = uint32_t;
 
@@ -65,9 +64,8 @@ namespace controller {
 
         static void registerControllerTypes(QScriptEngine* engine);
 
-
-        void registerDevice(InputDevice* device);
-        DeviceProxy::Pointer getDeviceProxy(const Input& input);
+        void registerDevice(InputDevice::Pointer device);
+        InputDevice::Pointer getDevice(const Input& input);
         QString getDeviceName(uint16 deviceID);
 
         Input::NamedVector getAvailableInputs(uint16 deviceID) const;
@@ -104,7 +102,7 @@ namespace controller {
 
         DevicesMap getDevices() { return _registeredDevices; }
         uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
-        DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
+        InputDevice::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
 
         MappingPointer newMapping(const QString& mappingName);
         MappingPointer parseMapping(const QString& json);
@@ -122,7 +120,6 @@ namespace controller {
     protected:
         // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
         uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
-        InputDevice::Pointer _standardController;
         DevicesMap _registeredDevices;
         uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
 
@@ -184,9 +181,9 @@ namespace controller {
 
 }
 
-Q_DECLARE_METATYPE(controller::UserInputMapper::InputPair)
+Q_DECLARE_METATYPE(controller::Input::NamedPair)
 Q_DECLARE_METATYPE(controller::Pose)
-Q_DECLARE_METATYPE(QVector<controller::UserInputMapper::InputPair>)
+Q_DECLARE_METATYPE(QVector<controller::Input::NamedPair>)
 Q_DECLARE_METATYPE(controller::Input)
 Q_DECLARE_METATYPE(controller::Action)
 Q_DECLARE_METATYPE(QVector<controller::Action>)
diff --git a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp
index 32cd5b65e0..bb1f6df191 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp
@@ -19,11 +19,11 @@ float InputEndpoint::value(){
         return pose().valid ? 1.0f : 0.0f;
     }
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    auto deviceProxy = userInputMapper->getDeviceProxy(_input);
+    auto deviceProxy = userInputMapper->getDevice(_input);
     if (!deviceProxy) {
         return 0.0f;
     }
-    return deviceProxy->getValue(_input, 0);
+    return deviceProxy->getValue(_input);
 }
 
 Pose InputEndpoint::pose() {
@@ -32,10 +32,10 @@ Pose InputEndpoint::pose() {
         return Pose();
     }
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
-    auto deviceProxy = userInputMapper->getDeviceProxy(_input);
+    auto deviceProxy = userInputMapper->getDevice(_input);
     if (!deviceProxy) {
         return Pose();
     }
-    return deviceProxy->getPose(_input, 0);
+    return deviceProxy->getPose(_input.channel);
 }
 
diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt
index 4c33b2517a..d994a1f5aa 100644
--- a/libraries/input-plugins/CMakeLists.txt
+++ b/libraries/input-plugins/CMakeLists.txt
@@ -1,6 +1,6 @@
 set(TARGET_NAME input-plugins)
 setup_hifi_library()
-link_hifi_libraries(shared plugins controllers)
+link_hifi_libraries(shared plugins controllers render-utils)
 
 GroupSources("src/input-plugins")
 
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index 30074b37d3..b7d69b9406 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -71,63 +71,58 @@ void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
 
 #endif
 
-void Joystick::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
+controller::Input::NamedVector Joystick::getAvailableInputs() const {
     using namespace controller;
-    proxy->_name = _name;
-    proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this](const Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
-        QVector<Input::NamedPair> availableInputs{
-            makePair(A, "A"),
-            makePair(B, "B"),
-            makePair(X, "X"),
-            makePair(Y, "Y"),
-            // DPad
-            makePair(DU, "DU"),
-            makePair(DD, "DD"),
-            makePair(DL, "DL"),
-            makePair(DR, "DR"),
-            // Bumpers
-            makePair(LB, "LB"),
-            makePair(RB, "RB"),
-            // Stick press
-            makePair(LS, "LS"),
-            makePair(RS, "RS"),
-            // Center buttons
-            makePair(START, "Start"),
-            makePair(BACK, "Back"),
-            // Analog sticks
-            makePair(LX, "LX"),
-            makePair(LY, "LY"),
-            makePair(RX, "RX"),
-            makePair(RY, "RY"),
+    static const Input::NamedVector availableInputs{
+        makePair(A, "A"),
+        makePair(B, "B"),
+        makePair(X, "X"),
+        makePair(Y, "Y"),
+        // DPad
+        makePair(DU, "DU"),
+        makePair(DD, "DD"),
+        makePair(DL, "DL"),
+        makePair(DR, "DR"),
+        // Bumpers
+        makePair(LB, "LB"),
+        makePair(RB, "RB"),
+        // Stick press
+        makePair(LS, "LS"),
+        makePair(RS, "RS"),
+        // Center buttons
+        makePair(START, "Start"),
+        makePair(BACK, "Back"),
+        // Analog sticks
+        makePair(LX, "LX"),
+        makePair(LY, "LY"),
+        makePair(RX, "RX"),
+        makePair(RY, "RY"),
  
-            // Triggers
-            makePair(LT, "LT"),
-            makePair(RT, "RT"),
+        // Triggers
+        makePair(LT, "LT"),
+        makePair(RT, "RT"),
 
-            // Aliases, PlayStation style names
-            makePair(LB, "L1"),
-            makePair(RB, "R1"),
-            makePair(LT, "L2"),
-            makePair(RT, "R2"),
-            makePair(LS, "L3"),
-            makePair(RS, "R3"),
-            makePair(BACK, "Select"),
-            makePair(A, "Cross"),
-            makePair(B, "Circle"),
-            makePair(X, "Square"),
-            makePair(Y, "Triangle"),
-            makePair(DU, "Up"),
-            makePair(DD, "Down"),
-            makePair(DL, "Left"),
-            makePair(DR, "Right"),
-        };
-        return availableInputs;
+        // Aliases, PlayStation style names
+        makePair(LB, "L1"),
+        makePair(RB, "R1"),
+        makePair(LT, "L2"),
+        makePair(RT, "R2"),
+        makePair(LS, "L3"),
+        makePair(RS, "R3"),
+        makePair(BACK, "Select"),
+        makePair(A, "Cross"),
+        makePair(B, "Circle"),
+        makePair(X, "Square"),
+        makePair(Y, "Triangle"),
+        makePair(DU, "Up"),
+        makePair(DD, "Down"),
+        makePair(DL, "Left"),
+        makePair(DR, "Right"),
     };
+    return availableInputs;
 }
 
-QString Joystick::getDefaultMappingConfig() {
+QString Joystick::getDefaultMappingConfig() const {
     static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/xbox.json";
     return MAPPING_JSON;
 }
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h
index a9ed18607c..fa50f8eab6 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.h
+++ b/libraries/input-plugins/src/input-plugins/Joystick.h
@@ -32,12 +32,13 @@ class Joystick : public QObject, public controller::InputDevice {
 #endif
     
 public:
+    using Pointer = std::shared_ptr<Joystick>;
 
     const QString& getName() const { return _name; }
 
     // Device functions
-    virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
-    virtual QString getDefaultMappingConfig() override;
+    virtual controller::Input::NamedVector getAvailableInputs() const override;
+    virtual QString getDefaultMappingConfig() const override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
     
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
index ff6c0ce2de..a0481dfaa0 100755
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
@@ -130,7 +130,7 @@ void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) {
     _lastTouch = currentPos;
 }
 
-controller::Input KeyboardMouseDevice::makeInput(Qt::Key code) {
+controller::Input KeyboardMouseDevice::makeInput(Qt::Key code) const {
     auto shortCode = (uint16_t)(code & KEYBOARD_MASK);
     if (shortCode != code) {
        shortCode |= 0x0800; // add this bit instead of the way Qt::Key add a bit on the 3rd byte for some keys
@@ -138,7 +138,7 @@ controller::Input KeyboardMouseDevice::makeInput(Qt::Key code) {
     return controller::Input(_deviceID, shortCode, controller::ChannelType::BUTTON);
 }
 
-controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) {
+controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) const {
     switch (code) {
         case Qt::LeftButton:
             return controller::Input(_deviceID, MOUSE_BUTTON_LEFT, controller::ChannelType::BUTTON);
@@ -151,31 +151,30 @@ controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) {
     };
 }
 
-controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) {
+controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) const {
     return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
 }
 
-controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) {
+controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) const {
     return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
 }
 
-controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) {
+controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) const {
     return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);
 }
 
-void KeyboardMouseDevice::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
+controller::Input::NamedVector KeyboardMouseDevice::getAvailableInputs() const {
     using namespace controller;
-    proxy->getButton = [this] (const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this] (const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getAvailabeInputs = [this] () -> QVector<Input::NamedPair> {
-        QVector<Input::NamedPair> availableInputs;
-        for (int i = (int) Qt::Key_0; i <= (int) Qt::Key_9; i++) {
+    static QVector<Input::NamedPair> availableInputs;
+    static std::once_flag once;
+    std::call_once(once, [&] {
+        for (int i = (int)Qt::Key_0; i <= (int)Qt::Key_9; i++) {
             availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
         }
-        for (int i = (int) Qt::Key_A; i <= (int) Qt::Key_Z; i++) {
+        for (int i = (int)Qt::Key_A; i <= (int)Qt::Key_Z; i++) {
             availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
         }
-        for (int i = (int) Qt::Key_Left; i <= (int) Qt::Key_Down; i++) {
+        for (int i = (int)Qt::Key_Left; i <= (int)Qt::Key_Down; i++) {
             availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
         }
         availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Space), QKeySequence(Qt::Key_Space).toString()));
@@ -186,27 +185,26 @@ void KeyboardMouseDevice::buildDeviceProxy(controller::DeviceProxy::Pointer prox
         availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "LeftMouseClick"));
         availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "MiddleMouseClick"));
         availableInputs.append(Input::NamedPair(makeInput(Qt::RightButton), "RightMouseClick"));
-        
+
         availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_POS), "MouseMoveRight"));
         availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_NEG), "MouseMoveLeft"));
         availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_POS), "MouseMoveUp"));
         availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_NEG), "MouseMoveDown"));
-        
+
         availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "MouseWheelRight"));
         availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "MouseWheelLeft"));
         availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "MouseWheelUp"));
         availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_NEG), "MouseWheelDown"));
-        
+
         availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_POS), "TouchpadRight"));
         availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_NEG), "TouchpadLeft"));
         availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_POS), "TouchpadUp"));
         availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_NEG), "TouchpadDown"));
-
-        return availableInputs;
-    };
+    });
+    return availableInputs;
 }
 
-QString KeyboardMouseDevice::getDefaultMappingConfig() {
+QString KeyboardMouseDevice::getDefaultMappingConfig() const {
     static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/keyboardMouse.json";
     return MAPPING_JSON;
 }
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
index f89d877dcd..1ff77d2dce 100644
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
@@ -72,8 +72,8 @@ public:
     virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
 
     // Device functions
-    virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
-    virtual QString getDefaultMappingConfig() override;
+    virtual controller::Input::NamedVector getAvailableInputs() const override;
+    virtual QString getDefaultMappingConfig() const override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
  
@@ -91,11 +91,11 @@ public:
     void wheelEvent(QWheelEvent* event);
     
     // Let's make it easy for Qt because we assume we love Qt forever
-    controller::Input makeInput(Qt::Key code);
-    controller::Input makeInput(Qt::MouseButton code);
-    controller::Input makeInput(MouseAxisChannel axis);
-    controller::Input makeInput(TouchAxisChannel axis);
-    controller::Input makeInput(TouchButtonChannel button);
+    controller::Input makeInput(Qt::Key code) const;
+    controller::Input makeInput(Qt::MouseButton code) const;
+    controller::Input makeInput(MouseAxisChannel axis) const;
+    controller::Input makeInput(TouchAxisChannel axis) const;
+    controller::Input makeInput(TouchButtonChannel button) const;
 
     static const QString NAME;
 
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
index 54197b1a70..d021e35a54 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
@@ -49,11 +49,11 @@ void SDL2Manager::init() {
                 SDL_JoystickID id = getInstanceId(controller);
                 if (!_openJoysticks.contains(id)) {
                     //Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
-                    Joystick* joystick = new Joystick(id, controller);
+                    Joystick::Pointer joystick  = std::make_shared<Joystick>(id, controller);
                     _openJoysticks[id] = joystick;
                     auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
                     userInputMapper->registerDevice(joystick);
-                    emit joystickAdded(joystick);
+                    emit joystickAdded(joystick.get());
                 }
             }
         }
@@ -68,7 +68,7 @@ void SDL2Manager::init() {
 
 void SDL2Manager::deinit() {
 #ifdef HAVE_SDL2
-    qDeleteAll(_openJoysticks);
+    _openJoysticks.clear();
 
     SDL_Quit();
 #endif
@@ -103,12 +103,12 @@ void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) {
         SDL_Event event;
         while (SDL_PollEvent(&event)) {
             if (event.type == SDL_CONTROLLERAXISMOTION) {
-                Joystick* joystick = _openJoysticks[event.caxis.which];
+                Joystick::Pointer joystick = _openJoysticks[event.caxis.which];
                 if (joystick) {
                     joystick->handleAxisEvent(event.caxis);
                 }
             } else if (event.type == SDL_CONTROLLERBUTTONDOWN || event.type == SDL_CONTROLLERBUTTONUP) {
-                Joystick* joystick = _openJoysticks[event.cbutton.which];
+                Joystick::Pointer joystick = _openJoysticks[event.cbutton.which];
                 if (joystick) {
                     joystick->handleButtonEvent(event.cbutton);
                 }
@@ -128,16 +128,18 @@ void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) {
                 SDL_JoystickID id = getInstanceId(controller);
                 if (!_openJoysticks.contains(id)) {
                     // Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
-                    Joystick* joystick = new Joystick(id, controller);
+                    Joystick::Pointer joystick = std::make_shared<Joystick>(id, controller);
                     _openJoysticks[id] = joystick;
                     userInputMapper->registerDevice(joystick);
-                    emit joystickAdded(joystick);
+                    emit joystickAdded(joystick.get());
                 }
             } else if (event.type == SDL_CONTROLLERDEVICEREMOVED) {
-                Joystick* joystick = _openJoysticks[event.cdevice.which];
-                _openJoysticks.remove(event.cdevice.which);
-                userInputMapper->removeDevice(joystick->getDeviceID());
-                emit joystickRemoved(joystick);
+                if (_openJoysticks.contains(event.cdevice.which)) {
+                    Joystick::Pointer joystick = _openJoysticks[event.cdevice.which];
+                    _openJoysticks.remove(event.cdevice.which);
+                    userInputMapper->removeDevice(joystick->getDeviceID());
+                    emit joystickRemoved(joystick.get());
+                }
             }
         }
     }
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.h b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
index fec6972591..4cf9cd33d8 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.h
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
@@ -76,7 +76,7 @@ private:
     int buttonPressed() const { return SDL_PRESSED; }
     int buttonRelease() const { return SDL_RELEASED; }
 
-    QMap<SDL_JoystickID, Joystick*> _openJoysticks;
+    QMap<SDL_JoystickID, Joystick::Pointer> _openJoysticks;
 #endif
     bool _isInitialized;
     static const QString NAME;
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index d5ff4c93a8..9ef1599099 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -64,11 +64,12 @@ const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
 const QString TOGGLE_SMOOTH = "Smooth Sixense Movement";
 const float DEFAULT_REACH_LENGTH = 1.5f;
 
-
+static std::shared_ptr<SixenseManager> instance;
 SixenseManager::SixenseManager() :
     InputDevice("Hydra"),
     _reachLength(DEFAULT_REACH_LENGTH) 
 {
+    instance = std::shared_ptr<SixenseManager>(this);
 }
 
 bool SixenseManager::isSupported() const {
@@ -91,7 +92,7 @@ void SixenseManager::activate() {
                            true, true);
 
     auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
-    userInputMapper->registerDevice(this);
+    userInputMapper->registerDevice(instance);
 
 #ifdef __APPLE__
 
@@ -512,42 +513,37 @@ static const auto R4 = controller::Y;
 
 using namespace controller;
 
-void SixenseManager::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
-    proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this](const Input& input, int timestamp) -> float { 
-        return this->getAxis(input.getChannel()); 
+controller::Input::NamedVector SixenseManager::getAvailableInputs() const {
+    using namespace controller;
+    static const Input::NamedVector availableInputs {
+        makePair(L0, "L0"),
+        makePair(L1, "L1"),
+        makePair(L2, "L2"),
+        makePair(L3, "L3"),
+        makePair(L4, "L4"),
+        makePair(LB, "LB"),
+        makePair(LS, "LS"),
+        makePair(LX, "LX"),
+        makePair(LY, "LY"),
+        makePair(LT, "LT"),
+        makePair(R0, "R0"),
+        makePair(R1, "R1"),
+        makePair(R2, "R2"),
+        makePair(R3, "R3"),
+        makePair(R4, "R4"),
+        makePair(RB, "RB"),
+        makePair(RS, "RS"),
+        makePair(RX, "RX"),
+        makePair(RY, "RY"),
+        makePair(RT, "RT"),
+        makePair(LEFT_HAND, "LeftHand"),
+        makePair(RIGHT_HAND, "RightHand"),
     };
-    proxy->getPose = [this](const Input& input, int timestamp) -> Pose { return this->getPose(input.getChannel()); };
-    proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
-        QVector<Input::NamedPair> availableInputs;
-        availableInputs.append(Input::NamedPair(makeInput(L0), "L0"));
-        availableInputs.append(Input::NamedPair(makeInput(L1), "L1"));
-        availableInputs.append(Input::NamedPair(makeInput(L2), "L2"));
-        availableInputs.append(Input::NamedPair(makeInput(L3), "L3"));
-        availableInputs.append(Input::NamedPair(makeInput(L4), "L4"));
-        availableInputs.append(Input::NamedPair(makeInput(LB), "LB"));
-        availableInputs.append(Input::NamedPair(makeInput(LS), "LS"));
-        availableInputs.append(Input::NamedPair(makeInput(LX), "LX"));
-        availableInputs.append(Input::NamedPair(makeInput(LY), "LY"));
-        availableInputs.append(Input::NamedPair(makeInput(LT), "LT"));
-        availableInputs.append(Input::NamedPair(makeInput(R0), "R0"));
-        availableInputs.append(Input::NamedPair(makeInput(R1), "R1"));
-        availableInputs.append(Input::NamedPair(makeInput(R2), "R2"));
-        availableInputs.append(Input::NamedPair(makeInput(R3), "R3"));
-        availableInputs.append(Input::NamedPair(makeInput(R4), "R4"));
-        availableInputs.append(Input::NamedPair(makeInput(RB), "RB"));
-        availableInputs.append(Input::NamedPair(makeInput(RS), "RS"));
-        availableInputs.append(Input::NamedPair(makeInput(RX), "RX"));
-        availableInputs.append(Input::NamedPair(makeInput(RY), "RY"));
-        availableInputs.append(Input::NamedPair(makeInput(RT), "RT"));
-        availableInputs.append(Input::NamedPair(makeInput(LEFT_HAND), "LeftHand"));
-        availableInputs.append(Input::NamedPair(makeInput(RIGHT_HAND), "RightHand"));
-        return availableInputs;
-    };
-}
+    return availableInputs;
+};
 
 
-QString SixenseManager::getDefaultMappingConfig() {
+QString SixenseManager::getDefaultMappingConfig() const {
     static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/hydra.json";
     return MAPPING_JSON;
 }
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index a44f527238..5b5cb7ccfa 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -62,8 +62,8 @@ public:
     virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
 
     // Device functions
-    virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
-    virtual QString getDefaultMappingConfig() override;
+    virtual controller::Input::NamedVector getAvailableInputs() const override;
+    virtual QString getDefaultMappingConfig() const override;
 
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index 8dd3d21a07..02d27d7e05 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -44,6 +44,8 @@ const QString MENU_NAME = "Vive Controllers";
 const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
 const QString RENDER_CONTROLLERS = "Render Hand Controllers";
 
+static std::shared_ptr<ViveControllerManager> instance;
+
 ViveControllerManager::ViveControllerManager() :
         InputDevice("Vive"),
     _trackedControllers(0),
@@ -52,7 +54,7 @@ ViveControllerManager::ViveControllerManager() :
     _rightHandRenderID(0),
     _renderControllers(false)
 {
-    
+    instance = std::shared_ptr<ViveControllerManager>(this);
 }
 
 bool ViveControllerManager::isSupported() const {
@@ -278,7 +280,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
     }
         
     if (_trackedControllers == 0 && numTrackedControllers > 0) {
-        userInputMapper->registerDevice(this);
+        userInputMapper->registerDevice(instance);
         UserActivityLogger::getInstance().connectedDevice("spatial_controller", "steamVR");
     }
         
@@ -392,62 +394,43 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) {
     _poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = controller::Pose(position, rotation);
 }
 
-void ViveControllerManager::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
+controller::Input::NamedVector ViveControllerManager::getAvailableInputs() const {
     using namespace controller;
-    proxy->_name = _name;
-    proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
-    proxy->getAxis = [this](const Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
-    proxy->getPose = [this](const Input& input, int timestamp) -> Pose { return this->getPose(input.getChannel()); };
-    proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
-        QVector<Input::NamedPair> availableInputs{
-            // Trackpad analogs
-            makePair(LX, "LX"),
-            makePair(LY, "LY"),
-            makePair(RX, "RX"),
-            makePair(RY, "RY"),
-            // trigger analogs
-            makePair(LT, "LT"),
-            makePair(RT, "RT"),
+    QVector<Input::NamedPair> availableInputs{
+        // Trackpad analogs
+        makePair(LX, "LX"),
+        makePair(LY, "LY"),
+        makePair(RX, "RX"),
+        makePair(RY, "RY"),
+        // trigger analogs
+        makePair(LT, "LT"),
+        makePair(RT, "RT"),
 
-            makePair(LB, "LB"),
-            makePair(RB, "RB"),
+        makePair(LB, "LB"),
+        makePair(RB, "RB"),
 
-            makePair(LS, "LS"),
-            makePair(RS, "RS"),
-            makePair(LEFT_HAND, "LeftHand"),
-            makePair(RIGHT_HAND, "RightHand"),
-        };
-
-        //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 0), "Left Button A"));
-        //availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button"));
-        //availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button"));
-        //availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 0), "Left Trigger Button"));
-
-        //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_POS, 0), "Left Trackpad Up"));
-        //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_NEG, 0), "Left Trackpad Down"));
-        //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_POS, 0), "Left Trackpad Right"));
-        //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_NEG, 0), "Left Trackpad Left"));
-        //availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 0), "Left Back Trigger"));
-
-
-        //availableInputs.append(Input::NamedPair(makeInput(RIGHT_HAND), "Right Hand"));
-
-        //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 1), "Right Button A"));
-        //availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 1), "Right Grip Button"));
-        //availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 1), "Right Trackpad Button"));
-        //availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 1), "Right Trigger Button"));
-
-        //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_POS, 1), "Right Trackpad Up"));
-        //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_NEG, 1), "Right Trackpad Down"));
-        //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_POS, 1), "Right Trackpad Right"));
-        //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_NEG, 1), "Right Trackpad Left"));
-        //availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 1), "Right Back Trigger"));
-
-        return availableInputs;
+        makePair(LS, "LS"),
+        makePair(RS, "RS"),
+        makePair(LEFT_HAND, "LeftHand"),
+        makePair(RIGHT_HAND, "RightHand"),
     };
+
+    //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 0), "Left Button A"));
+    //availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button"));
+    //availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button"));
+    //availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 0), "Left Trigger Button"));
+    //availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 0), "Left Back Trigger"));
+    //availableInputs.append(Input::NamedPair(makeInput(RIGHT_HAND), "Right Hand"));
+    //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 1), "Right Button A"));
+    //availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 1), "Right Grip Button"));
+    //availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 1), "Right Trackpad Button"));
+    //availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 1), "Right Trigger Button"));
+    //availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 1), "Right Back Trigger"));
+
+    return availableInputs;
 }
 
-QString ViveControllerManager::getDefaultMappingConfig() {
+QString ViveControllerManager::getDefaultMappingConfig() const {
     static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
     return MAPPING_JSON;
 }
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
index 67ad75c9e8..dc04398b20 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
@@ -41,8 +41,8 @@ public:
     virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
 
     // Device functions
-    virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
-    virtual QString getDefaultMappingConfig() override;
+    virtual controller::Input::NamedVector getAvailableInputs() const override;
+    virtual QString getDefaultMappingConfig() const override;
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index bc0ad179ef..a7b1be15ca 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -136,7 +136,7 @@ int main(int argc, char** argv) {
             auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
             if (name == KeyboardMouseDevice::NAME) {
                 auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
-                userInputMapper->registerDevice(keyboardMouseDevice);
+                userInputMapper->registerDevice(std::shared_ptr<InputDevice>(keyboardMouseDevice));
             }
             inputPlugin->pluginUpdate(0, false);
         }

From a3cd032a41b39d38a26460acfec39561fde2ba6e Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 29 Oct 2015 10:06:21 -0700
Subject: [PATCH 215/301] register/remove devices when the input plugins are
 activated/deactivated

---
 examples/controllers/controllerMappings.js      |  8 +++++++-
 .../src/input-plugins/SDL2Manager.cpp           | 17 +++++++++++++++++
 .../src/input-plugins/SDL2Manager.h             |  7 ++++++-
 .../src/input-plugins/SixenseManager.cpp        |  4 +++-
 .../src/input-plugins/ViveControllerManager.cpp | 15 +++++++++++++--
 .../src/input-plugins/ViveControllerManager.h   |  3 +++
 6 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js
index 42494816f4..3848f62096 100644
--- a/examples/controllers/controllerMappings.js
+++ b/examples/controllers/controllerMappings.js
@@ -91,5 +91,11 @@ Object.keys(Controller.Actions).forEach(function (actionName) {
 
 
 Controller.hardwareChanged.connect(function () {
-    print("hardwareChanged");
+    print("hardwareChanged ---------------------------------------------------");
+    Object.keys(Controller.Hardware).forEach(function (deviceName) {
+        Object.keys(Controller.Hardware[deviceName]).forEach(function (input) {
+            print("Controller.Hardware." + deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]);
+        });
+    });
+    print("-------------------------------------------------------------------");
 });
\ No newline at end of file
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
index 54197b1a70..554b0bac95 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
@@ -74,6 +74,23 @@ void SDL2Manager::deinit() {
 #endif
 }
 
+void SDL2Manager::activate() {
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+    for (auto joystick : _openJoysticks) {
+        userInputMapper->registerDevice(joystick);
+        emit joystickAdded(joystick);
+    }
+}
+
+void SDL2Manager::deactivate() {
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+    for (auto joystick : _openJoysticks) {
+        userInputMapper->removeDevice(joystick->getDeviceID());
+        emit joystickRemoved(joystick);
+    }
+}
+
+
 bool SDL2Manager::isSupported() const {
 #ifdef HAVE_SDL2
     return true;
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.h b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
index fec6972591..ed543d4265 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.h
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
@@ -34,7 +34,12 @@ public:
 
     virtual void init() override;
     virtual void deinit() override;
-    
+
+    /// Called when a plugin is being activated for use.  May be called multiple times.
+    virtual void activate() override;
+    /// Called when a plugin is no longer being used.  May be called multiple times.
+    virtual void deactivate() override;
+
     virtual void pluginFocusOutEvent() override;
     virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override;
     
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index d5ff4c93a8..60138929e9 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -92,6 +92,8 @@ void SixenseManager::activate() {
 
     auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
     userInputMapper->registerDevice(this);
+    qDebug() << "just called registerDevice hydra id:" << _deviceID;
+
 
 #ifdef __APPLE__
 
@@ -125,6 +127,7 @@ void SixenseManager::activate() {
 
 void SixenseManager::deactivate() {
     InputPlugin::deactivate();
+
 #ifdef HAVE_SIXENSE
     CONTAINER->removeMenuItem(MENU_NAME, TOGGLE_SMOOTH);
     CONTAINER->removeMenu(MENU_PATH);
@@ -135,7 +138,6 @@ void SixenseManager::deactivate() {
     if (_deviceID != controller::Input::INVALID_DEVICE) {
         auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
         userInputMapper->removeDevice(_deviceID);
-        _deviceID = controller::Input::INVALID_DEVICE;
     }
 
 #ifdef __APPLE__
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index 8dd3d21a07..dc3e062417 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -133,6 +133,11 @@ void ViveControllerManager::activate() {
         _renderControllers = true;
     }
 #endif
+
+    // unregister with UserInputMapper
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+    userInputMapper->registerDevice(this);
+    _registeredWithInputMapper = true;
 }
 
 void ViveControllerManager::deactivate() {
@@ -150,6 +155,11 @@ void ViveControllerManager::deactivate() {
     }
     _poseStateMap.clear();
 #endif
+
+    // unregister with UserInputMapper
+    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
+    userInputMapper->removeDevice(_deviceID);
+    _registeredWithInputMapper = false;
 }
 
 void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges) {
@@ -270,15 +280,16 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
     auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
         
     if (numTrackedControllers == 0) {
-        if (_deviceID != 0) {
+        if (_registeredWithInputMapper) {
             userInputMapper->removeDevice(_deviceID);
-            _deviceID = 0;
+            _registeredWithInputMapper = false;
             _poseStateMap.clear();
         }
     }
         
     if (_trackedControllers == 0 && numTrackedControllers > 0) {
         userInputMapper->registerDevice(this);
+        _registeredWithInputMapper = true;
         UserActivityLogger::getInstance().connectedDevice("spatial_controller", "steamVR");
     }
         
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
index 67ad75c9e8..6984734c21 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
@@ -69,6 +69,9 @@ private:
     bool _renderControllers;
 
     static const QString NAME;
+
+    bool _registeredWithInputMapper { false };
+
 };
 
 #endif // hifi__ViveControllerManager

From 49877c2dffba35b6902e3c92dfd9568615dcab78 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Thu, 29 Oct 2015 10:19:18 -0700
Subject: [PATCH 216/301] Move _hasOutgoingChanges in onSubStep to previous
 location

---
 libraries/physics/src/PhysicsEngine.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp
index 1e87fc9a5d..7af1c12917 100644
--- a/libraries/physics/src/PhysicsEngine.cpp
+++ b/libraries/physics/src/PhysicsEngine.cpp
@@ -253,7 +253,6 @@ void PhysicsEngine::stepSimulation() {
 
     auto onSubStep = [this]() {
         updateContactMap();
-        _hasOutgoingChanges = true;
     };
 
     int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, PHYSICS_ENGINE_MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP, onSubStep);
@@ -265,6 +264,8 @@ void PhysicsEngine::stepSimulation() {
         if (_characterController) {
             _characterController->postSimulation();
         }
+
+        _hasOutgoingChanges = true;
     }
 }
 

From 4083c5c71b848d300ef73709003a119e06dbe4a1 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 10:31:36 -0700
Subject: [PATCH 217/301] Handle wrapping of very long-lived sessions.

---
 libraries/animation/src/Rig.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index de2d3c54ad..b51907ea4a 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -580,18 +580,20 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
 // Allow script to add/remove handlers and report results, from within their thread.
 QScriptValue Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { // called in script thread
     QMutexLocker locker(&_stateMutex);
-    int identifier = ++_nextStateHandlerId; // 0 is unused
-    StateHandler& data = _stateHandlers[identifier];
+    while (!_nextStateHandlerId || _stateHandlers.contains(_nextStateHandlerId)) { // 0 is unused, and don't reuse existing after wrap.
+      _nextStateHandlerId++;
+    }
+    StateHandler& data = _stateHandlers[_nextStateHandlerId];
     data.function = handler;
     data.useNames = propertiesList.isArray();
     if (data.useNames) {
         data.propertyNames = propertiesList.toVariant().toStringList();
     }
-    return QScriptValue(identifier); // suitable for giving to removeAnimationStateHandler
+    return QScriptValue(_nextStateHandlerId); // suitable for giving to removeAnimationStateHandler
 }
 void Rig::removeAnimationStateHandler(QScriptValue identifier) { // called in script thread
     QMutexLocker locker(&_stateMutex);
-    _stateHandlers.remove(identifier.isNumber() ? identifier.toInt32() : 0); // silently continues if handler not present
+    _stateHandlers.remove(identifier.isNumber() ? identifier.toInt32() : 0); // silently continues if handler not present. 0 is unused
 }
 void Rig::animationStateHandlerResult(int identifier, QScriptValue result) { // called synchronously from script
     QMutexLocker locker(&_stateMutex);

From ed87ae3d5a4461dacdef532188af3763293c205e Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 29 Oct 2015 10:57:30 -0700
Subject: [PATCH 218/301] remove some debugging

---
 libraries/input-plugins/src/input-plugins/SixenseManager.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 31a7f50d5c..2527da9e03 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -81,7 +81,6 @@ bool SixenseManager::isSupported() const {
 }
 
 void SixenseManager::activate() {
-    qDebug() << "SixenseManager::activate()...";
     InputPlugin::activate();
 #ifdef HAVE_SIXENSE
     _calibrationState = CALIBRATION_STATE_IDLE;
@@ -126,7 +125,6 @@ void SixenseManager::activate() {
 }
 
 void SixenseManager::deactivate() {
-    qDebug() << "SixenseManager::deactivate()...";
     InputPlugin::deactivate();
 
 #ifdef HAVE_SIXENSE

From 3c6d4f9c221ac19c8f3b12070ee396c52f72bec1 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 11:02:24 -0700
Subject: [PATCH 219/301] Thread safety per #6154.

---
 interface/src/avatar/AvatarManager.cpp | 10 ++++++++++
 interface/src/avatar/AvatarManager.h   |  6 ++----
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index 9783590b05..fbfbbad2de 100644
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -248,6 +248,16 @@ QVector<AvatarManager::LocalLight> AvatarManager::getLocalLights() const {
     return _localLights;
 }
 
+QVector<QUuid> AvatarManager::getAvatarIdentifiers() {
+    QReadLocker locker(&_hashLock);
+    return _avatarHash.keys().toVector();
+}
+AvatarData* AvatarManager::getAvatar(QUuid avatarID) {
+    QReadLocker locker(&_hashLock);
+    return _avatarHash[avatarID].get();  // Non-obvious: A bogus avatarID answers your own avatar.
+}
+
+
 void AvatarManager::getObjectsToDelete(VectorOfMotionStates& result) {
     result.clear();
     result.swap(_motionStatesToDelete);
diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h
index ffc7cc8f92..fa0593368b 100644
--- a/interface/src/avatar/AvatarManager.h
+++ b/interface/src/avatar/AvatarManager.h
@@ -53,10 +53,8 @@ public:
     Q_INVOKABLE void setLocalLights(const QVector<AvatarManager::LocalLight>& localLights);
     Q_INVOKABLE QVector<AvatarManager::LocalLight> getLocalLights() const;
     // Currently, your own avatar will be included as the null avatar id.
-    Q_INVOKABLE QVector<QUuid> getAvatarIdentifiers() const { return _avatarHash.keys().toVector(); } // FIXME: see #6154
-    Q_INVOKABLE QVector<QUuid> getAvatars() const { return getAvatarIdentifiers(); } // FIXME: remove before merge. Compatability for testing scripts.
-    // Minor Bug: A bogus avatarID answers your own avatar.
-    Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID) const { return _avatarHash[avatarID].get(); } // FIXME: see #6154
+    Q_INVOKABLE QVector<QUuid> getAvatarIdentifiers();
+    Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID);
 
 
     void getObjectsToDelete(VectorOfMotionStates& motionStates);

From 3d37a1d2497dba09d1a03bf54a1c5d8d5fc6e170 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 29 Oct 2015 11:06:20 -0700
Subject: [PATCH 220/301] fix Controller.Hardware when input plugins are
 deactived

---
 .../controllers/src/controllers/ScriptingInterface.cpp   | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp
index e49248e8f0..a62172a730 100644
--- a/libraries/controllers/src/controllers/ScriptingInterface.cpp
+++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp
@@ -204,25 +204,24 @@ namespace controller {
     }
 
     void ScriptingInterface::updateMaps() {
+        QVariantMap newHardware;
         auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
         auto devices = userInputMapper->getDevices();
-        QSet<QString> foundDevices;
         for (const auto& deviceMapping : devices) {
             auto deviceID = deviceMapping.first;
             if (deviceID != userInputMapper->getStandardDeviceID()) {
                 auto device = deviceMapping.second;
                 auto deviceName = QString(device->getName()).remove(SANITIZE_NAME_EXPRESSION);
                 qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
-                foundDevices.insert(device->getName());
-                if (_hardware.contains(deviceName)) {
+                if (newHardware.contains(deviceName)) {
                     continue;
                 }
 
                 // Expose the IDs to JS
-                _hardware.insert(deviceName, createDeviceMap(device));
+                newHardware.insert(deviceName, createDeviceMap(device));
             }
-
         }
+        _hardware = newHardware;
     }
 
 

From 851460b2bd973e42d8c1f46b3346000c36013ce5 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 29 Oct 2015 11:26:11 -0700
Subject: [PATCH 221/301] fix build buster for SDL2 missing builds

---
 libraries/input-plugins/src/input-plugins/SDL2Manager.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
index f41b724c11..600dc5c56f 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
@@ -75,19 +75,23 @@ void SDL2Manager::deinit() {
 }
 
 void SDL2Manager::activate() {
+#ifdef HAVE_SDL2
     auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
     for (auto joystick : _openJoysticks) {
         userInputMapper->registerDevice(joystick);
         emit joystickAdded(joystick.get());
     }
+#endif
 }
 
 void SDL2Manager::deactivate() {
+#ifdef HAVE_SDL2
     auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
     for (auto joystick : _openJoysticks) {
         userInputMapper->removeDevice(joystick->getDeviceID());
         emit joystickRemoved(joystick.get());
     }
+#endif
 }
 
 

From 8f908f987779a33a7f13b6d7e32d8892567fa03f Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 29 Oct 2015 12:08:11 -0700
Subject: [PATCH 222/301] Adding the stepYaw to the Standard mapping

---
 interface/resources/controllers/standard.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 8ba9056076..4fe6dba923 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -3,6 +3,7 @@
     "channels": [
         { "from": "Standard.LY", "to": "Actions.TranslateZ" },
         { "from": "Standard.LX", "to": "Actions.TranslateX" },
+        { "from": "Standard.RX", "when": "Application.InHMD", "to": "Actions.StepYaw" },
         { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
 

From 143b9c663f2e6cb530133aadf19e6f27d49ebe2d Mon Sep 17 00:00:00 2001
From: Ken Cooke <ken@highfidelity.io>
Date: Thu, 29 Oct 2015 12:21:28 -0700
Subject: [PATCH 223/301] Quick fix for audio having channels swapped under Qt
 5.5.1.

---
 libraries/audio-client/src/AudioClient.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index b528b67745..c321a32211 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -313,7 +313,9 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
 bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
                                   const QAudioFormat& desiredAudioFormat,
                                   QAudioFormat& adjustedAudioFormat) {
-    if (!audioDevice.isFormatSupported(desiredAudioFormat)) {
+    // FIXME: direcly using 24khz has a bug somewhere that causes channels to be swapped.
+    // Continue using our internal resampler, for now.
+    if (false && !audioDevice.isFormatSupported(desiredAudioFormat)) {
         qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat;
         qCDebug(audioclient, "The desired audio format is not supported by this device");
 

From 4d576d7aaff7284d4d5d10640d1ab97c27b4405c Mon Sep 17 00:00:00 2001
From: Ken Cooke <ken@highfidelity.io>
Date: Thu, 29 Oct 2015 12:23:36 -0700
Subject: [PATCH 224/301] Fix typo

---
 libraries/audio-client/src/AudioClient.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index c321a32211..a67ab460d1 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -313,7 +313,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
 bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
                                   const QAudioFormat& desiredAudioFormat,
                                   QAudioFormat& adjustedAudioFormat) {
-    // FIXME: direcly using 24khz has a bug somewhere that causes channels to be swapped.
+    // FIXME: directly using 24khz has a bug somewhere that causes channels to be swapped.
     // Continue using our internal resampler, for now.
     if (false && !audioDevice.isFormatSupported(desiredAudioFormat)) {
         qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat;

From 1c2973f17d9b292c699a5899385d392ae8cb779a Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 29 Oct 2015 12:34:24 -0700
Subject: [PATCH 225/301] removed old metavoxel example, since the api is no
 longer available

---
 examples/example/metavoxels/metavoxels.js | 41 -----------------------
 1 file changed, 41 deletions(-)
 delete mode 100644 examples/example/metavoxels/metavoxels.js

diff --git a/examples/example/metavoxels/metavoxels.js b/examples/example/metavoxels/metavoxels.js
deleted file mode 100644
index 32177cdcba..0000000000
--- a/examples/example/metavoxels/metavoxels.js
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-//  metavoxels.js
-//  examples
-//
-//  Copyright 2014 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-Script.setInterval(function() {
-    var spanner;
-    if (Math.random() < 0.5) {
-        spanner = new Sphere();
-    } else {
-        spanner = new Cuboid();
-        spanner.aspectX = 0.1 + Math.random() * 1.9;
-        spanner.aspectY = 0.1 + Math.random() * 1.9;
-    }
-    spanner.scale = 0.1 + Math.random() * 1.9;
-    spanner.rotation = Quat.fromPitchYawRollDegrees(Math.random() * 360.0, Math.random() * 360.0, Math.random() * 360.0);
-    spanner.translation = { x: 10.0 + Math.random() * 10.0, y: 10.0 + Math.random() * 10.0, z: 10.0 + Math.random() * 10.0 };
-    
-    if (Math.random() < 0.5) {
-        var material = new MaterialObject();
-        if (Math.random() < 0.5) {
-            material.diffuse = "http://www.fungibleinsight.com/faces/grass.jpg";
-        } else {
-            material.diffuse = "http://www.fungibleinsight.com/faces/soil.jpg";
-        }
-        Metavoxels.setVoxelMaterial(spanner, material);
-    
-    } else if (Math.random() < 0.5) {
-        Metavoxels.setVoxelColor(spanner, { red: Math.random() * 255.0, green: Math.random() * 255.0,
-            blue: Math.random() * 255.0 });
-    
-    } else {
-        Metavoxels.setVoxelColor(spanner, { red: 0, green: 0, blue: 0, alpha: 0 });
-    }
-}, 1000);
-

From fb55f0becbbb1a0ae589224f4f26906d939ed191 Mon Sep 17 00:00:00 2001
From: Stephen Birarda <commit@birarda.com>
Date: Thu, 29 Oct 2015 12:50:34 -0700
Subject: [PATCH 226/301] guard timeElapsed for simulateKinematicMotion to max
 1s

---
 libraries/entities/src/EntityItem.cpp | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index f012ba6eee..cce3045049 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -736,18 +736,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
         // is sending us data with a known "last simulated" time. That time is likely in the past, and therefore
         // this "new" data is actually slightly out of date. We calculate the time we need to skip forward and
         // use our simulation helper routine to get a best estimate of where the entity should be.
-        const float MIN_TIME_SKIP = 0.0f;
-        const float MAX_TIME_SKIP = 1.0f; // in seconds
-        float skipTimeForward = glm::clamp((float)(now - lastSimulatedFromBufferAdjusted) / (float)(USECS_PER_SECOND),
-                MIN_TIME_SKIP, MAX_TIME_SKIP);
-        if (skipTimeForward > 0.0f) {
-            #ifdef WANT_DEBUG
-                qCDebug(entities) << "skipTimeForward:" << skipTimeForward;
-            #endif
-            // we want to extrapolate the motion forward to compensate for packet travel time, but
-            // we don't want the side effect of flag setting.
-            simulateKinematicMotion(skipTimeForward, false);
-        }
+        float skipTimeForward = (float)(now - lastSimulatedFromBufferAdjusted) / (float)(USECS_PER_SECOND);
+        
+        // we want to extrapolate the motion forward to compensate for packet travel time, but
+        // we don't want the side effect of flag setting.
+        simulateKinematicMotion(skipTimeForward, false);
     }
 
     if (overwriteLocalData) {
@@ -887,6 +880,15 @@ void EntityItem::simulate(const quint64& now) {
 }
 
 void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) {
+#ifdef WANT_DEBUG
+    qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed;
+#endif
+    
+    const float MIN_TIME_SKIP = 0.0f;
+    const float MAX_TIME_SKIP = 1.0f; // in seconds
+    
+    timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP);
+    
     if (hasActions()) {
         return;
     }

From 1eabb924f1ce844332bc9e7f001bf50a6bc9fb27 Mon Sep 17 00:00:00 2001
From: Ken Cooke <ken@highfidelity.io>
Date: Thu, 29 Oct 2015 12:53:47 -0700
Subject: [PATCH 227/301] Fixed the logic to be correct

---
 libraries/audio-client/src/AudioClient.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index a67ab460d1..d4980596dd 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -315,7 +315,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
                                   QAudioFormat& adjustedAudioFormat) {
     // FIXME: directly using 24khz has a bug somewhere that causes channels to be swapped.
     // Continue using our internal resampler, for now.
-    if (false && !audioDevice.isFormatSupported(desiredAudioFormat)) {
+    if (true || !audioDevice.isFormatSupported(desiredAudioFormat)) {
         qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat;
         qCDebug(audioclient, "The desired audio format is not supported by this device");
 
@@ -323,7 +323,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
             adjustedAudioFormat = desiredAudioFormat;
             adjustedAudioFormat.setChannelCount(2);
 
-            if (audioDevice.isFormatSupported(adjustedAudioFormat)) {
+            if (false && audioDevice.isFormatSupported(adjustedAudioFormat)) {
                 return true;
             } else {
                 adjustedAudioFormat.setChannelCount(1);

From e902e5e97a725f569ab7cc344373c8197b5d8ca2 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 29 Oct 2015 13:05:29 -0700
Subject: [PATCH 228/301] Introduce the concept of loading the default Mapping

---
 interface/src/Application.cpp                 |  2 ++
 .../src/controllers/UserInputMapper.cpp       | 23 +++++++++++++++++++
 .../src/controllers/UserInputMapper.h         |  1 +
 3 files changed, 26 insertions(+)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 4e4b4010f0..7d2929d31e 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -648,6 +648,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     userInputMapper->registerDevice(_keyboardMouseDevice);
 
 
+    userInputMapper->loadDefaultMapping(userInputMapper->getStandardDeviceID());
+
     // check first run...
     if (_firstRun.get()) {
         qCDebug(interfaceapp) << "This is a first run...";
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 64a2a54ef4..736fa30d37 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -129,6 +129,27 @@ void UserInputMapper::removeDevice(int deviceID) {
 }
 
 
+void UserInputMapper::loadDefaultMapping(uint16 deviceID) {
+    Locker locker(_lock);
+    auto proxyEntry = _registeredDevices.find(deviceID);
+    if (_registeredDevices.end() == proxyEntry) {
+        qCWarning(controllers) << "Unknown deviceID " << deviceID;
+        return;
+    }
+
+
+    auto mapping = loadMapping(proxyEntry->second->getDefaultMappingConfig());
+    if (mapping) {
+        auto prevMapping = _mappingsByDevice[deviceID];
+        disableMapping(prevMapping);
+
+        _mappingsByDevice[deviceID] = mapping;
+        enableMapping(mapping);
+    }
+
+    emit hardwareChanged();
+}
+
 InputDevice::Pointer UserInputMapper::getDevice(const Input& input) {
     Locker locker(_lock);
     auto device = _registeredDevices.find(input.getDevice());
@@ -711,6 +732,8 @@ Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) {
     return parseMapping(json);
 }
 
+
+
 static const QString JSON_NAME = QStringLiteral("name");
 static const QString JSON_CHANNELS = QStringLiteral("channels");
 static const QString JSON_CHANNEL_FROM = QStringLiteral("from");
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 884e303fc6..a32c3f3649 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -108,6 +108,7 @@ namespace controller {
         MappingPointer parseMapping(const QString& json);
         MappingPointer loadMapping(const QString& jsonFile);
 
+        void loadDefaultMapping(uint16 deviceID);
         void enableMapping(const QString& mappingName, bool enable = true);
         float getValue(const Input& input) const;
         Pose getPose(const Input& input) const;

From ffd2b39874d1c40447ab89bc5d5c95e1839f1c62 Mon Sep 17 00:00:00 2001
From: AlessandroSigna <alesigna92@gmail.com>
Date: Thu, 29 Oct 2015 13:18:37 -0700
Subject: [PATCH 229/301] Fix vive controller - update to new input plugin
 register

---
 interface/resources/controllers/vive.json                    | 5 ++++-
 .../src/input-plugins/ViveControllerManager.cpp              | 5 +++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json
index f51f908813..bcf4943ff8 100644
--- a/interface/resources/controllers/vive.json
+++ b/interface/resources/controllers/vive.json
@@ -17,6 +17,9 @@
         { "from": "Vive.Start", "to": "Standard.Start" }, 
         
         { "from": "Vive.A", "to": "Standard.A" }, 
-        { "from": "Vive.B", "to": "Standard.B" }
+        { "from": "Vive.B", "to": "Standard.B" },
+
+        { "from": "Vive.LeftHand", "to": "Standard.LeftHand" },
+        { "from": "Vive.RightHand", "to": "Standard.RightHand" }
     ]
 }
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index 6d1534958a..c63d47b681 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -424,6 +424,11 @@ controller::Input::NamedVector ViveControllerManager::getAvailableInputs() const
         makePair(RS, "RS"),
         makePair(LEFT_HAND, "LeftHand"),
         makePair(RIGHT_HAND, "RightHand"),
+
+        makePair(A, "A"),
+        makePair(B, "B"),
+        makePair(BACK, "Back"),
+        makePair(START, "Start"),
     };
 
     //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 0), "Left Button A"));

From d73eafddd1a0e2511446463fc7e0190349c0e8bd Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 29 Oct 2015 13:48:16 -0700
Subject: [PATCH 230/301] COmfort mode working with the COntroller system
 observing the menu state

---
 interface/resources/controllers/standard.json         |  2 +-
 interface/src/Application.cpp                         | 11 +++++++----
 .../controllers/src/controllers/StateController.cpp   |  4 ++++
 .../controllers/src/controllers/StateController.h     |  3 +++
 4 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 4fe6dba923..5483da925d 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -3,7 +3,7 @@
     "channels": [
         { "from": "Standard.LY", "to": "Actions.TranslateZ" },
         { "from": "Standard.LX", "to": "Actions.TranslateX" },
-        { "from": "Standard.RX", "when": "Application.InHMD", "to": "Actions.StepYaw" },
+        { "from": "Standard.RX", "when": [ "Application.InHMD", "Application.ComfortMode" ], "to": "Actions.StepYaw" },
         { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
 
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 7d2929d31e..118d34230c 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -637,10 +637,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
 
     // A new controllerInput device used to reflect current values from the application state
     _applicationStateDevice = std::make_shared<controller::StateController>();
-    auto InHMDLambda = controller::StateController::ReadLambda([]() -> float {
-        return (float) qApp->getAvatarUpdater()->isHMDMode();
-    });
-    _applicationStateDevice->addInputVariant("InHMD", InHMDLambda);
+
+    _applicationStateDevice->addInputVariant("InHMD", controller::StateController::ReadLambda([]() -> float {
+        return (float)qApp->getAvatarUpdater()->isHMDMode();
+    }));
+    _applicationStateDevice->addInputVariant("ComfortMode", controller::StateController::ReadLambda([]() -> float {
+        return (float)Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode);
+    }));
 
     userInputMapper->registerDevice(_applicationStateDevice);
     
diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp
index efe7a064fc..9d2f3baf86 100644
--- a/libraries/controllers/src/controllers/StateController.cpp
+++ b/libraries/controllers/src/controllers/StateController.cpp
@@ -43,4 +43,8 @@ Input::NamedVector StateController::getAvailableInputs() const {
     return availableInputs;
 }
 
+EndpointPointer StateController::createEndpoint(const Input& input) const {
+    return std::make_shared<LambdaEndpoint>(_namedReadLambdas[input.getChannel()].second);
+}
+
 }
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/StateController.h b/libraries/controllers/src/controllers/StateController.h
index d664c6b8d0..7a4c386c5e 100644
--- a/libraries/controllers/src/controllers/StateController.h
+++ b/libraries/controllers/src/controllers/StateController.h
@@ -39,6 +39,9 @@ public:
 
     void addInputVariant(QString name, ReadLambda& lambda);
 
+    virtual EndpointPointer createEndpoint(const Input& input) const override;
+
+
 protected:
     QVector<NamedReadLambda> _namedReadLambdas;
 };

From 904326cd1c15911a307b5beebb382afdd13578fe Mon Sep 17 00:00:00 2001
From: Atlante45 <clement.brisset@gmail.com>
Date: Thu, 29 Oct 2015 14:11:27 -0700
Subject: [PATCH 231/301] edit.js fix

---
 examples/html/entityProperties.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html
index b3d7a5f6b6..fe40311b5f 100644
--- a/examples/html/entityProperties.html
+++ b/examples/html/entityProperties.html
@@ -1520,7 +1520,7 @@
         <div class="zone-section keyLight-section property">
             <div class="label">Ambient URL</div>
             <div class="value">
-                <input type="text" id="property-zone-skybox-url" class="url">
+                <input type="text" id="property-zone-key-ambient-url" class="url">
             </div>
         </div>
 

From 020566b76a996c931aece545e98782124f329397 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Thu, 29 Oct 2015 14:14:15 -0700
Subject: [PATCH 232/301] no deleting

---
 examples/painting/whiteboard/whiteboardEntityScript.js | 2 +-
 examples/painting/whiteboard/whiteboardSpawner.js      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js
index ce0e8a82b1..c10a8c23fe 100644
--- a/examples/painting/whiteboard/whiteboardEntityScript.js
+++ b/examples/painting/whiteboard/whiteboardEntityScript.js
@@ -243,7 +243,7 @@
         unload: function() {
 
             Overlays.deleteOverlay(this.laserPointer);
-            this.eraseBoard();
+            // this.eraseBoard();
         }
     };
 
diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index 29183dcc76..b2156dc898 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -209,4 +209,4 @@ function cleanup() {
 
 
 // Uncomment this line to delete whiteboard and all associated entity on script close
-Script.scriptEnding.connect(cleanup);
\ No newline at end of file
+// Script.scriptEnding.connect(cleanup);
\ No newline at end of file

From f72146c35d224bffedea7a6d28195966173d14a1 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 29 Oct 2015 14:17:52 -0700
Subject: [PATCH 233/301] FIxing the mac build

---
 interface/src/Application.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 118d34230c..7f4b5a3c3d 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -638,10 +638,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     // A new controllerInput device used to reflect current values from the application state
     _applicationStateDevice = std::make_shared<controller::StateController>();
 
-    _applicationStateDevice->addInputVariant("InHMD", controller::StateController::ReadLambda([]() -> float {
+    _applicationStateDevice->addInputVariant(QString("InHMD"), controller::StateController::ReadLambda([]() -> float {
         return (float)qApp->getAvatarUpdater()->isHMDMode();
     }));
-    _applicationStateDevice->addInputVariant("ComfortMode", controller::StateController::ReadLambda([]() -> float {
+    _applicationStateDevice->addInputVariant(QString("ComfortMode"), controller::StateController::ReadLambda([]() -> float {
         return (float)Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode);
     }));
 

From c1e00ca08c81fb1e3391e10f3e4e670dd6645680 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 29 Oct 2015 14:30:51 -0700
Subject: [PATCH 234/301] FIxing the mac build again ?

---
 libraries/controllers/src/controllers/StateController.cpp | 2 +-
 libraries/controllers/src/controllers/StateController.h   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp
index 9d2f3baf86..6f89c6365c 100644
--- a/libraries/controllers/src/controllers/StateController.cpp
+++ b/libraries/controllers/src/controllers/StateController.cpp
@@ -29,7 +29,7 @@ void StateController::update(float deltaTime, bool jointsCaptured) {}
 
 void StateController::focusOutEvent() {}
 
-void StateController::addInputVariant(QString name, ReadLambda& lambda) {
+void StateController::addInputVariant(QString name, ReadLambda lambda) {
     _namedReadLambdas.push_back(NamedReadLambda(name, lambda));
 }
 
diff --git a/libraries/controllers/src/controllers/StateController.h b/libraries/controllers/src/controllers/StateController.h
index 7a4c386c5e..12f3e8b2f1 100644
--- a/libraries/controllers/src/controllers/StateController.h
+++ b/libraries/controllers/src/controllers/StateController.h
@@ -37,7 +37,7 @@ public:
     using ReadLambda = std::function<float()>;
     using NamedReadLambda = QPair<QString, ReadLambda>;
 
-    void addInputVariant(QString name, ReadLambda& lambda);
+    void addInputVariant(QString name, ReadLambda lambda);
 
     virtual EndpointPointer createEndpoint(const Input& input) const override;
 

From c237072195288e18c8c643c07c35d3e5a5544c72 Mon Sep 17 00:00:00 2001
From: Atlante45 <clement.brisset@gmail.com>
Date: Thu, 29 Oct 2015 15:29:12 -0700
Subject: [PATCH 235/301] edit.js fix

---
 examples/edit.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/edit.js b/examples/edit.js
index c45e66986a..447455e999 100644
--- a/examples/edit.js
+++ b/examples/edit.js
@@ -1510,7 +1510,7 @@ PropertiesTool = function(opts) {
             if (entity.properties.rotation !== undefined) {
                 entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation);
             }
-            if (entity.properties.keyLight.direction !== undefined) {
+            if (entity.properties.type === "Zone" && entity.properties.keyLight.direction !== undefined) {
                 entity.properties.keyLight.direction = Vec3.multiply(RADIANS_TO_DEGREES, Vec3.toPolar(entity.properties.keyLight.direction));
                 entity.properties.keyLight.direction.z = 0.0;
             }
@@ -1541,7 +1541,7 @@ PropertiesTool = function(opts) {
                     var rotation = data.properties.rotation;
                     data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
                 }
-                if (data.properties.keyLight.direction !== undefined) {
+                if (entity.properties.type === "Zone" && data.properties.keyLight.direction !== undefined) {
                     data.properties.keyLight.direction = Vec3.fromPolar(
                         data.properties.keyLight.direction.x * DEGREES_TO_RADIANS, data.properties.keyLight.direction.y * DEGREES_TO_RADIANS);
                 }

From b070306c2c002bd08662fcc4c7c3b860bd5fc4cc Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 29 Oct 2015 15:53:17 -0700
Subject: [PATCH 236/301] tweak comfort mode filters

---
 .../resources/controllers/keyboardMouse.json  | 42 +++++++++++++++++++
 interface/resources/controllers/standard.json | 16 ++++++-
 2 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
index 6ea1c42b1e..fba55ffebd 100644
--- a/interface/resources/controllers/keyboardMouse.json
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -1,6 +1,47 @@
 {
     "name": "Keyboard/Mouse to Actions",
     "channels": [
+
+        { "from": ["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"],
+          "when": [ "Application.InHMD", "Application.ComfortMode" ],
+          "to": "Actions.StepYaw",
+          "filters":
+            [
+                { "type": "pulse", "interval": 0.5 },
+                { "type": "scale", "scale": -15 }
+            ]
+        },
+
+        { "from": ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"],
+          "when": [ "Application.InHMD", "Application.ComfortMode" ],
+          "to": "Actions.StepYaw",
+          "filters":
+            [
+                { "type": "pulse", "interval": 0.5 },
+                { "type": "scale", "scale": 15 }
+            ]
+        },
+
+        { "from": "Keyboard.MouseMoveLeft",
+          "when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseClick" ],
+          "to": "Actions.StepYaw",
+          "filters":
+            [
+                { "type": "pulse", "interval": 0.5 },
+                { "type": "scale", "scale": -15 }
+            ]
+        },
+
+        { "from": "Keyboard.MouseMoveRight",
+          "when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseClick" ],
+          "to": "Actions.StepYaw",
+          "filters":
+            [
+                { "type": "pulse", "interval": 0.5 },
+                { "type": "scale", "scale": 15 }
+            ]
+        },
+
         { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
         { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
         { "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
@@ -28,6 +69,7 @@
         { "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" },
         { "from": "Keyboard.Left", "to": "Actions.YAW_LEFT" },
         { "from": "Keyboard.Right", "to": "Actions.YAW_RIGHT" },
+
         { "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
         { "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },
 
diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 5483da925d..871374b85b 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -3,10 +3,22 @@
     "channels": [
         { "from": "Standard.LY", "to": "Actions.TranslateZ" },
         { "from": "Standard.LX", "to": "Actions.TranslateX" },
-        { "from": "Standard.RX", "when": [ "Application.InHMD", "Application.ComfortMode" ], "to": "Actions.StepYaw" },
+
+        { "from": "Standard.RX",
+          "when": [ "Application.InHMD", "Application.ComfortMode" ],
+          "to": "Actions.StepYaw",
+          "filters":
+            [
+                { "type": "pulse", "interval": 0.5 },
+                { "type": "scale", "scale": 15 }
+            ]
+        },
+
+
         { "from": "Standard.RX", "to": "Actions.Yaw" },
         { "from": "Standard.RY", "to": "Actions.Pitch" },
 
+
         { "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
         { "from": "Standard.Back", "to": "Standard.LeftSecondaryThumb" },
 
@@ -20,3 +32,5 @@
         { "from": "Standard.RightHand", "to": "Actions.RightHand" }
     ]
 }
+
+

From 047614b2eb70fc7e60faef1486de3b515078344b Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Thu, 29 Oct 2015 16:18:15 -0700
Subject: [PATCH 237/301] New left and right grab animations.

---
 .../defaultAvatar_full/avatar-animation.json     | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json
index 682e0be1bf..515f6e96fe 100644
--- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json
+++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json
@@ -197,7 +197,7 @@
                                                 "id": "rightHandOpen",
                                                 "type": "clip",
                                                 "data": {
-                                                    "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx",
+                                                    "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx",
                                                     "startFrame": 0.0,
                                                     "endFrame": 0.0,
                                                     "timeScale": 1.0,
@@ -209,9 +209,9 @@
                                                 "id": "rightHandClose",
                                                 "type": "clip",
                                                 "data": {
-                                                    "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/right_hand_anim.fbx",
-                                                    "startFrame": 15.0,
-                                                    "endFrame": 15.0,
+                                                    "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx",
+                                                    "startFrame": 10.0,
+                                                    "endFrame": 10.0,
                                                     "timeScale": 1.0,
                                                     "loopFlag": true
                                                 },
@@ -346,7 +346,7 @@
                                                         "id": "leftHandOpen",
                                                         "type": "clip",
                                                         "data": {
-                                                            "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx",
+                                                            "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx",
                                                             "startFrame": 0.0,
                                                             "endFrame": 0.0,
                                                             "timeScale": 1.0,
@@ -358,9 +358,9 @@
                                                         "id": "leftHandClose",
                                                         "type": "clip",
                                                         "data": {
-                                                            "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/left_hand_anim.fbx",
-                                                            "startFrame": 15.0,
-                                                            "endFrame": 15.0,
+                                                            "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx",
+                                                            "startFrame": 10.0,
+                                                            "endFrame": 10.0,
                                                             "timeScale": 1.0,
                                                             "loopFlag": true
                                                         },

From 303491817bd14dd17e2ab6eaa95674145c125bca Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 16:35:59 -0700
Subject: [PATCH 238/301] assert to get hard error in dev, warning and no-op in
 release.

---
 libraries/animation/src/AnimVariantMap.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
index 0c808bd404..fc474c0cbd 100644
--- a/libraries/animation/src/AnimVariantMap.cpp
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -18,6 +18,7 @@
 QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine, const QStringList& names, bool useNames) const {
     if (QThread::currentThread() != engine->thread()) {
         qCWarning(animation) << "Cannot create Javacript object from non-script thread" << QThread::currentThread();
+        Q_ASSERT(false);
         return QScriptValue();
     }
     QScriptValue target = engine->newObject();
@@ -69,6 +70,7 @@ void AnimVariantMap::copyVariantsFrom(const AnimVariantMap& other) {
 void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) {
     if (QThread::currentThread() != source.engine()->thread()) {
         qCWarning(animation) << "Cannot examine Javacript object from non-script thread" << QThread::currentThread();
+        Q_ASSERT(false);
         return;
     }
     // POTENTIAL OPTIMIZATION: cache the types we've seen. I.e, keep a dictionary mapping property names to an enumeration of types.

From b6b71e7e7693aa92962ff080f562909e82238dec Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Thu, 29 Oct 2015 16:40:50 -0700
Subject: [PATCH 239/301] increased range and intensity of light

---
 examples/painting/whiteboard/whiteboardSpawner.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index b2156dc898..fa5040ed4b 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -79,11 +79,13 @@ var drawingSurface = Entities.addEntity({
 
 });
 
-var lightPosition = Vec3.sum(center, Vec3.multiply(-2, Quat.getFront(rotation)));
+var lightPosition = Vec3.sum(center, Vec3.multiply(-4, Quat.getFront(rotation)));
 var light = Entities.addEntity({
     type: 'Light',
+    name: 'whiteboard light',
     position: lightPosition,
-    dimensions: {x: 5, y: 5, z: 5},
+    dimensions: {x: 10, y: 10, z: 10},
+    intensity: 2,
     color: {red: 255, green: 255, blue: 255}
 });
 

From 8b46ed7dff4e54bf9817bf0ee3df69ba62997bb2 Mon Sep 17 00:00:00 2001
From: Atlante45 <clement.brisset@gmail.com>
Date: Thu, 29 Oct 2015 16:42:48 -0700
Subject: [PATCH 240/301] Check keyLight is defined

---
 examples/edit.js                    | 4 ++--
 examples/html/entityProperties.html | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/examples/edit.js b/examples/edit.js
index 447455e999..7a16030afc 100644
--- a/examples/edit.js
+++ b/examples/edit.js
@@ -1510,7 +1510,7 @@ PropertiesTool = function(opts) {
             if (entity.properties.rotation !== undefined) {
                 entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation);
             }
-            if (entity.properties.type === "Zone" && entity.properties.keyLight.direction !== undefined) {
+            if (entity.properties.keyLight !== undefined && entity.properties.keyLight.direction !== undefined) {
                 entity.properties.keyLight.direction = Vec3.multiply(RADIANS_TO_DEGREES, Vec3.toPolar(entity.properties.keyLight.direction));
                 entity.properties.keyLight.direction.z = 0.0;
             }
@@ -1541,7 +1541,7 @@ PropertiesTool = function(opts) {
                     var rotation = data.properties.rotation;
                     data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
                 }
-                if (entity.properties.type === "Zone" && data.properties.keyLight.direction !== undefined) {
+                if (data.properties.keyLight !== undefined && data.properties.keyLight.direction !== undefined) {
                     data.properties.keyLight.direction = Vec3.fromPolar(
                         data.properties.keyLight.direction.x * DEGREES_TO_RADIANS, data.properties.keyLight.direction.y * DEGREES_TO_RADIANS);
                 }
diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html
index fe40311b5f..412b413b2b 100644
--- a/examples/html/entityProperties.html
+++ b/examples/html/entityProperties.html
@@ -830,7 +830,7 @@
             elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
             elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction);
             elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction);
-            elZoneKeyLightIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('intensity','keyLight'));
+            elZoneKeyLightIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight','intensity'));
             elZoneKeyLightAmbientIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight','ambientIntensity'));
             var zoneKeyLightDirectionChangeFunction = createEmitGroupVec3PropertyUpdateFunction('keyLight','direction', elZoneKeyLightDirectionX, elZoneKeyLightDirectionY, elZoneKeyLightDirectionZ);
             elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction);

From 502cc7f580c90483b65d10638f2e622a40c8c702 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 16:44:01 -0700
Subject: [PATCH 241/301] Don't copy while converting.

---
 libraries/animation/src/AnimVariantMap.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
index fc474c0cbd..2d9291db2d 100644
--- a/libraries/animation/src/AnimVariantMap.cpp
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -22,7 +22,7 @@ QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine,
         return QScriptValue();
     }
     QScriptValue target = engine->newObject();
-    auto setOne = [&] (QString name, AnimVariant value) {
+    auto setOne = [&] (const QString& name, const AnimVariant& value) {
         switch (value.getType()) {
             case AnimVariant::Type::Bool:
                 target.setProperty(name, value.getBool());

From 6bdf66534f323d1710878bcc5f6d48f32e9a1992 Mon Sep 17 00:00:00 2001
From: ericrius1 <ericrius1>
Date: Thu, 29 Oct 2015 16:53:03 -0700
Subject: [PATCH 242/301] light tweak

---
 examples/painting/whiteboard/whiteboardSpawner.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js
index fa5040ed4b..701112e1a8 100644
--- a/examples/painting/whiteboard/whiteboardSpawner.js
+++ b/examples/painting/whiteboard/whiteboardSpawner.js
@@ -79,7 +79,7 @@ var drawingSurface = Entities.addEntity({
 
 });
 
-var lightPosition = Vec3.sum(center, Vec3.multiply(-4, Quat.getFront(rotation)));
+var lightPosition = Vec3.sum(center, Vec3.multiply(-3, Quat.getFront(rotation)));
 var light = Entities.addEntity({
     type: 'Light',
     name: 'whiteboard light',

From 35e03d662d392af02b95969138b3d5cc84cdba37 Mon Sep 17 00:00:00 2001
From: Thijs Wenker <me@thoys.nl>
Date: Fri, 30 Oct 2015 00:58:32 +0100
Subject: [PATCH 243/301] fix the constants of Vec3 ,  const glm::vec3&
 UNIT_***() weren't accessible in javascript. Solved it by making them
 properties that are CONSTANT. Also added function to multiply a vec3 by a
 vec3 called multiplyVbyV since overloading it over multiply gave me some
 problems

---
 libraries/script-engine/src/Vec3.h | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h
index b05e729a49..17a5afd09a 100644
--- a/libraries/script-engine/src/Vec3.h
+++ b/libraries/script-engine/src/Vec3.h
@@ -23,6 +23,25 @@
 /// Scriptable interface a Vec3ernion helper class object. Used exclusively in the JavaScript API
 class Vec3 : public QObject {
     Q_OBJECT
+    Q_PROPERTY(glm::vec3 UNIT_X READ UNIT_X CONSTANT)
+    Q_PROPERTY(glm::vec3 UNIT_Y READ UNIT_Y CONSTANT)
+    Q_PROPERTY(glm::vec3 UNIT_Z READ UNIT_Z CONSTANT)
+    Q_PROPERTY(glm::vec3 UNIT_NEG_X READ UNIT_NEG_X CONSTANT)
+    Q_PROPERTY(glm::vec3 UNIT_NEG_Y READ UNIT_NEG_Y CONSTANT)
+    Q_PROPERTY(glm::vec3 UNIT_NEG_Z READ UNIT_NEG_Z CONSTANT)
+    Q_PROPERTY(glm::vec3 UNIT_XY READ UNIT_XY CONSTANT)
+    Q_PROPERTY(glm::vec3 UNIT_XZ READ UNIT_XZ CONSTANT)
+    Q_PROPERTY(glm::vec3 UNIT_YZ READ UNIT_YZ CONSTANT)
+    Q_PROPERTY(glm::vec3 UNIT_XYZ READ UNIT_XYZ CONSTANT)
+    Q_PROPERTY(glm::vec3 FLOAT_MAX READ FLOAT_MAX CONSTANT)
+    Q_PROPERTY(glm::vec3 FLOAT_MIN READ FLOAT_MIN CONSTANT)
+    Q_PROPERTY(glm::vec3 ZERO READ ZERO CONSTANT)
+    Q_PROPERTY(glm::vec3 ONE READ ONE CONSTANT)
+    Q_PROPERTY(glm::vec3 TWO READ TWO CONSTANT)
+    Q_PROPERTY(glm::vec3 HALF READ HALF CONSTANT)
+    Q_PROPERTY(glm::vec3 RIGHT READ RIGHT CONSTANT)
+    Q_PROPERTY(glm::vec3 UP READ UP CONSTANT)
+    Q_PROPERTY(glm::vec3 FRONT READ FRONT CONSTANT)
 
 public slots:
     glm::vec3 reflect(const glm::vec3& v1, const glm::vec3& v2) { return glm::reflect(v1, v2); }
@@ -30,6 +49,7 @@ public slots:
     float dot(const glm::vec3& v1, const glm::vec3& v2) { return glm::dot(v1, v2); }
     glm::vec3 multiply(const glm::vec3& v1, float f) { return v1 * f; }
     glm::vec3 multiply(float f, const glm::vec3& v1) { return v1 * f; }
+    glm::vec3 multiplyVbyV(const glm::vec3& v1, const glm::vec3& v2) { return v1 * v2; }
     glm::vec3 multiplyQbyV(const glm::quat& q, const glm::vec3& v) { return q * v; }
     glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2) { return v1 + v2; }
     glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2) { return v1 - v2; }
@@ -45,6 +65,8 @@ public slots:
     glm::vec3 toPolar(const glm::vec3& v);
     glm::vec3 fromPolar(const glm::vec3& polar);
     glm::vec3 fromPolar(float elevation, float azimuth);
+
+private:
     const glm::vec3& UNIT_X() { return Vectors::UNIT_X; }
     const glm::vec3& UNIT_Y() { return Vectors::UNIT_Y; }
     const glm::vec3& UNIT_Z() { return Vectors::UNIT_Z; }

From b56c49a182154c66dd20720825e0ea55e7d3713f Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 29 Oct 2015 17:33:30 -0700
Subject: [PATCH 244/301] add makeAxis support to JSON parsing

---
 .../src/controllers/UserInputMapper.cpp       | 43 ++++++++++++++++++-
 .../src/controllers/UserInputMapper.h         |  2 +
 2 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 736fa30d37..d7f57d91e3 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -747,7 +747,15 @@ Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) {
     if (value.isString()) {
         auto input = findDeviceInput(value.toString());
         result = endpointFor(input);
+    } else if (value.isArray()) {
+        return parseAny(value);
     } else if (value.isObject()) {
+        auto axisEndpoint = parseAxis(value);
+        if (axisEndpoint) {
+            return axisEndpoint;
+        }
+        // if we have other types of endpoints that are objects, follow the axisEndpoint example, and place them here
+
         // Endpoint is defined as an object, we expect a js function then
         return Endpoint::Pointer();
     }
@@ -881,7 +889,28 @@ Endpoint::Pointer UserInputMapper::parseDestination(const QJsonValue& value) {
     return parseEndpoint(value);
 }
 
-Endpoint::Pointer UserInputMapper::parseSource(const QJsonValue& value) {
+Endpoint::Pointer UserInputMapper::parseAxis(const QJsonValue& value) {
+    if (value.isObject()) {
+        auto object = value.toObject();
+        if (object.contains("makeAxis")) {
+            auto axisValue = object.value("makeAxis");
+            if (axisValue.isArray()) {
+                auto axisArray = axisValue.toArray();
+                static const int AXIS_ARRAY_SIZE = 2; // axis can only have 2 children
+                if (axisArray.size() == AXIS_ARRAY_SIZE) {
+                    Endpoint::Pointer first = parseEndpoint(axisArray.first());
+                    Endpoint::Pointer second = parseEndpoint(axisArray.last());
+                    if (first && second) {
+                        return std::make_shared<CompositeEndpoint>(first, second);
+                    }
+                }
+            }
+        }
+    }
+    return Endpoint::Pointer();
+}
+
+Endpoint::Pointer UserInputMapper::parseAny(const QJsonValue& value) {
     if (value.isArray()) {
         Endpoint::List children;
         for (auto arrayItem : value.toArray()) {
@@ -893,7 +922,19 @@ Endpoint::Pointer UserInputMapper::parseSource(const QJsonValue& value) {
         }
         return std::make_shared<AnyEndpoint>(children);
     }
+    return Endpoint::Pointer();
+}
 
+Endpoint::Pointer UserInputMapper::parseSource(const QJsonValue& value) {
+    if (value.isObject()) {
+        auto axisEndpoint = parseAxis(value);
+        if (axisEndpoint) {
+            return axisEndpoint;
+        }
+        // if we have other types of endpoints that are objects, follow the axisEndpoint example, and place them here
+    } else if (value.isArray()) {
+        return parseAny(value);
+    }
     return parseEndpoint(value);
 }
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index a32c3f3649..7684ecb7c5 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -159,6 +159,8 @@ namespace controller {
         RoutePointer parseRoute(const QJsonValue& value);
         EndpointPointer parseDestination(const QJsonValue& value);
         EndpointPointer parseSource(const QJsonValue& value);
+        EndpointPointer parseAxis(const QJsonValue& value);
+        EndpointPointer parseAny(const QJsonValue& value);
         EndpointPointer parseEndpoint(const QJsonValue& value);
         ConditionalPointer parseConditional(const QJsonValue& value);
 

From 01d3805148a0655a050d1cfebc2037a85ed3f9cb Mon Sep 17 00:00:00 2001
From: AlessandroSigna <alesigna92@gmail.com>
Date: Thu, 29 Oct 2015 18:44:43 -0700
Subject: [PATCH 245/301] ViveController - mapping of buttons

---
 interface/resources/controllers/vive.json     | 27 ++++++++++---------
 .../input-plugins/ViveControllerManager.cpp   | 20 ++++++++------
 2 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json
index bcf4943ff8..6a3c562e44 100644
--- a/interface/resources/controllers/vive.json
+++ b/interface/resources/controllers/vive.json
@@ -1,23 +1,24 @@
 {
-    "name": "XBox to Standard",
+    "name": "Vive to Standard",
     "channels": [
-        { "from": "Vive.LY", "to": "Standard.LY" }, 
-        { "from": "Vive.LX", "to": "Standard.LX" },
-        { "from": "Vive.LT", "to": "Standard.LT" }, 
-        { "from": "Vive.LB", "to": "Standard.LB" }, 
+        { "from": "Vive.LY", "filters": [ "invert", { "type": "deadZone", "min": 0.7 } ], "to": "Standard.LY" },
+        { "from": "Vive.LX", "filters": { "type": "deadZone", "min": 0.7 }, "to": "Standard.LX" },
+
+        { "from": "Vive.LT", "to": "Standard.LT" },
+        { "from": "Vive.LB", "to": "Standard.LB" },
         { "from": "Vive.LS", "to": "Standard.LS" },
 
-        { "from": "Vive.RY", "to": "Standard.RY" }, 
+        { "from": "Vive.RY", "filters": "invert", "to": "Standard.RY" },
         { "from": "Vive.RX", "to": "Standard.RX" },
-        { "from": "Vive.RT", "to": "Standard.RT" }, 
-        { "from": "Vive.RB", "to": "Standard.RB" }, 
+
+        { "from": "Vive.RT", "to": "Standard.RT" },
+        { "from": "Vive.RB", "to": "Standard.RB" },
         { "from": "Vive.RS", "to": "Standard.RS" },
 
-        { "from": "Vive.Back", "to": "Standard.Back" }, 
-        { "from": "Vive.Start", "to": "Standard.Start" }, 
-        
-        { "from": "Vive.A", "to": "Standard.A" }, 
-        { "from": "Vive.B", "to": "Standard.B" },
+        { "from": "Vive.LeftPrimaryThumb", "to": "Standard.LeftPrimaryThumb" },
+        { "from": "Vive.RightPrimaryThumb", "to": "Standard.RightPrimaryThumb" },
+        { "from": "Vive.LeftSecondaryThumb", "to": "Standard.LeftSecondaryThumb" },
+        { "from": "Vive.RightSecondaryThumb", "to": "Standard.RightSecondaryThumb" },
 
         { "from": "Vive.LeftHand", "to": "Standard.LeftHand" },
         { "from": "Vive.RightHand", "to": "Standard.RightHand" }
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index c63d47b681..69303bb079 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -307,11 +307,13 @@ void ViveControllerManager::focusOutEvent() {
 // These functions do translation from the Steam IDs to the standard controller IDs
 void ViveControllerManager::handleAxisEvent(uint32_t axis, float x, float y, bool left) {
 #ifdef Q_OS_WIN
+    axis += vr::k_EButton_Axis0;
     using namespace controller;
     if (axis == vr::k_EButton_SteamVR_Touchpad) {
         _axisStateMap[left ? LX : RX] = x;
         _axisStateMap[left ? LY : RY] = y;
     } else if (axis == vr::k_EButton_SteamVR_Trigger) {
+        //FIX ME: Seems that enters here everytime
         _axisStateMap[left ? LT : RT] = x;
     }
 #endif
@@ -325,15 +327,17 @@ void ViveControllerManager::handleButtonEvent(uint32_t button, bool pressed, boo
     }
 
     if (button == vr::k_EButton_ApplicationMenu) {
-        // FIXME?
-        _buttonPressedMap.insert(left ? controller::B : controller::A);
+        _buttonPressedMap.insert(left ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB);
     } else if (button == vr::k_EButton_Grip) {
         // Tony says these are harder to reach, so make them the meta buttons
-        _buttonPressedMap.insert(left ? controller::BACK : controller::START);
-    } else if (button == vr::k_EButton_SteamVR_Trigger) {
         _buttonPressedMap.insert(left ? controller::LB : controller::RB);
+    } else if (button == vr::k_EButton_SteamVR_Trigger) {
+        _buttonPressedMap.insert(left ? controller::LT : controller::RT);
     } else if (button == vr::k_EButton_SteamVR_Touchpad) {
         _buttonPressedMap.insert(left ? controller::LS : controller::RS);
+    } else if (button == vr::k_EButton_System) {
+        //FIX ME: not able to ovrewrite the behaviour of this button
+        _buttonPressedMap.insert(left ? controller::LEFT_SECONDARY_THUMB : controller::RIGHT_SECONDARY_THUMB);
     }
 #endif
 }
@@ -425,10 +429,10 @@ controller::Input::NamedVector ViveControllerManager::getAvailableInputs() const
         makePair(LEFT_HAND, "LeftHand"),
         makePair(RIGHT_HAND, "RightHand"),
 
-        makePair(A, "A"),
-        makePair(B, "B"),
-        makePair(BACK, "Back"),
-        makePair(START, "Start"),
+        makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"),
+        makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"),
+        makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"),
+        makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"),
     };
 
     //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 0), "Left Button A"));

From ada32dd260528ab62efd9ce85eaa2062900040dc Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 19:17:52 -0700
Subject: [PATCH 246/301] typo

---
 libraries/script-engine/src/ScriptEngine.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 46dbe7576c..79df1c3bb8 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -780,9 +780,9 @@ void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantM
                                   Q_ARG(AnimVariantResultHandler, resultHandler));
         return;
     }
-    QScriptValue javascriptParametgers = parameters.animVariantMapToScriptValue(this, names, useNames);
+    QScriptValue javascriptParameters = parameters.animVariantMapToScriptValue(this, names, useNames);
     QScriptValueList callingArguments;
-    callingArguments << javascriptParametgers;
+    callingArguments << javascriptParameters;
     QScriptValue result = callback.call(QScriptValue(), callingArguments);
     resultHandler(result);
 }

From 5d1ba90f1ebd7f652485bf3f01b9b23a23ef2c37 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 19:18:34 -0700
Subject: [PATCH 247/301] More readable code.

---
 libraries/animation/src/AnimVariantMap.cpp | 37 +++++++++++-----------
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
index 2d9291db2d..c3e452fa1e 100644
--- a/libraries/animation/src/AnimVariantMap.cpp
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -67,6 +67,7 @@ void AnimVariantMap::copyVariantsFrom(const AnimVariantMap& other) {
         _map[pair.first] = pair.second;
     }
 }
+
 void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) {
     if (QThread::currentThread() != source.engine()->thread()) {
         qCWarning(animation) << "Cannot examine Javacript object from non-script thread" << QThread::currentThread();
@@ -84,10 +85,8 @@ void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) {
         QScriptValue value = property.value();
         if (value.isBool()) {
             set(property.name(), value.toBool());
-            continue;
         } else if (value.isString()) {
             set(property.name(), value.toString());
-            continue;
         } else if (value.isNumber()) {
             int asInteger = value.toInt32();
             float asFloat = value.toNumber();
@@ -96,25 +95,27 @@ void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) {
             } else {
                 set(property.name(), asFloat);
             }
-            continue;
-        } else if (value.isObject()) {
-            QScriptValue x = value.property("x");
-            if (x.isNumber()) {
-                QScriptValue y = value.property("y");
-                if (y.isNumber()) {
-                    QScriptValue z = value.property("z");
-                    if (z.isNumber()) {
-                        QScriptValue w = value.property("w");
-                        if (w.isNumber()) {
-                            set(property.name(), glm::quat(x.toNumber(), y.toNumber(), z.toNumber(), w.toNumber()));
-                        } else {
-                            set(property.name(), glm::vec3(x.toNumber(), y.toNumber(), z.toNumber()));
+        } else { // Try to get x,y,z and possibly w
+            if (value.isObject()) {
+                QScriptValue x = value.property("x");
+                if (x.isNumber()) {
+                    QScriptValue y = value.property("y");
+                    if (y.isNumber()) {
+                        QScriptValue z = value.property("z");
+                        if (z.isNumber()) {
+                            QScriptValue w = value.property("w");
+                            if (w.isNumber()) {
+                                set(property.name(), glm::quat(x.toNumber(), y.toNumber(), z.toNumber(), w.toNumber()));
+                            } else {
+                                set(property.name(), glm::vec3(x.toNumber(), y.toNumber(), z.toNumber()));
+                            }
+                            continue; // we got either a vector or quaternion object, so don't fall through to warning
                         }
-                        continue;
                     }
                 }
             }
+            qCWarning(animation) << "Ignoring unrecognized data" << value.toString() << "for animation property" << property.name();
+            Q_ASSERT(false);
         }
-        qCWarning(animation) << "Ignoring unrecognized data" << value.toString() << "for animation property" << property.name();
-     }
+    }
 }

From dcc173c93a5da52364666e78f85081a884055a4b Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 19:21:24 -0700
Subject: [PATCH 248/301] comment.

---
 libraries/animation/src/Rig.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index b51907ea4a..ed5e07696d 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -615,7 +615,7 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
         int identifier = data.key();
         StateHandler& value = data.value();
         QScriptValue& function = value.function;
-        auto handleResult = [this, identifier](QScriptValue result) {
+        auto handleResult = [this, identifier](QScriptValue result) { // called in script thread to get the result back to us.
             animationStateHandlerResult(identifier, result);
         };
         // invokeMethod makes a copy of the args, and copies of AnimVariantMap do copy the underlying map, so this will correctly capture

From f7d558a2528e036b6869f4fa528002444f7878c1 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 19:26:54 -0700
Subject: [PATCH 249/301] comment

---
 libraries/animation/src/Rig.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index ed5e07696d..4ddae07375 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -580,6 +580,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
 // Allow script to add/remove handlers and report results, from within their thread.
 QScriptValue Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { // called in script thread
     QMutexLocker locker(&_stateMutex);
+    // Find a safe id, even if there are lots of many scripts add and remove handlers repeatedly.
     while (!_nextStateHandlerId || _stateHandlers.contains(_nextStateHandlerId)) { // 0 is unused, and don't reuse existing after wrap.
       _nextStateHandlerId++;
     }

From 1918f1835cfc44ee995ff2d0f64274d7cae66f5e Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 19:37:13 -0700
Subject: [PATCH 250/301] Tolerate AnimVars that are float when we want int,
 and vice versa.

---
 libraries/animation/src/AnimVariant.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h
index bd96dda77d..0d7c657058 100644
--- a/libraries/animation/src/AnimVariant.h
+++ b/libraries/animation/src/AnimVariant.h
@@ -61,8 +61,9 @@ public:
     void setString(const QString& value) { assert(_type == Type::String); _stringVal = value; }
 
     bool getBool() const { assert(_type == Type::Bool); return _val.boolVal; }
-    int getInt() const { assert(_type == Type::Int); return _val.intVal; }
-    float getFloat() const { assert(_type == Type::Float); return _val.floats[0]; }
+    int getInt() const { assert(_type == Type::Int || _type == Type::Float); return _type == Type::Float ? (int)_val.floats[0] : _val.intVal; }
+    float getFloat() const { assert(_type == Type::Float || _type == Type::Int); return _type == Type::Int ? (float)_val.intVal : _val.floats[0]; }
+
     const glm::vec3& getVec3() const { assert(_type == Type::Vec3); return *reinterpret_cast<const glm::vec3*>(&_val); }
     const glm::quat& getQuat() const { assert(_type == Type::Quat); return *reinterpret_cast<const glm::quat*>(&_val); }
     const glm::mat4& getMat4() const { assert(_type == Type::Mat4); return *reinterpret_cast<const glm::mat4*>(&_val); }

From d491ddc3d61a9fac53ac0efcb487eff6342967ad Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 19:43:57 -0700
Subject: [PATCH 251/301] comment.

---
 libraries/animation/src/AnimVariantMap.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariantMap.cpp
index c3e452fa1e..8d320195dd 100644
--- a/libraries/animation/src/AnimVariantMap.cpp
+++ b/libraries/animation/src/AnimVariantMap.cpp
@@ -13,7 +13,7 @@
 #include <QScriptValueIterator>
 #include <QThread>
 #include <RegisteredMetaTypes.h>
-#include "AnimVariant.h"
+#include "AnimVariant.h" // which has AnimVariant/AnimVariantMap
 
 QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine, const QStringList& names, bool useNames) const {
     if (QThread::currentThread() != engine->thread()) {

From eb9e54de41eb7add77d5cc91cf85eb0164375106 Mon Sep 17 00:00:00 2001
From: Howard Stearns <howard@highfidelity.io>
Date: Thu, 29 Oct 2015 19:45:23 -0700
Subject: [PATCH 252/301] Make AnimVariantXXX.xxx consistent.

---
 libraries/animation/src/{AnimVariantMap.cpp => AnimVariant.cpp} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename libraries/animation/src/{AnimVariantMap.cpp => AnimVariant.cpp} (100%)

diff --git a/libraries/animation/src/AnimVariantMap.cpp b/libraries/animation/src/AnimVariant.cpp
similarity index 100%
rename from libraries/animation/src/AnimVariantMap.cpp
rename to libraries/animation/src/AnimVariant.cpp

From 8a03383adc237f77105edb984d48a036b82584af Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 29 Oct 2015 22:19:33 -0700
Subject: [PATCH 253/301] use makeAxis for some keyboard support

---
 .../resources/controllers/keyboardMouse.json  | 46 ++++++-------------
 .../src/controllers/UserInputMapper.cpp       |  6 ++-
 2 files changed, 20 insertions(+), 32 deletions(-)

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
index fba55ffebd..e5abad761a 100644
--- a/interface/resources/controllers/keyboardMouse.json
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -2,17 +2,24 @@
     "name": "Keyboard/Mouse to Actions",
     "channels": [
 
-        { "from": ["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"],
-          "when": [ "Application.InHMD", "Application.ComfortMode" ],
+        
+        { "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
+          "when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseClick" ],
           "to": "Actions.StepYaw",
           "filters":
             [
+                "constrainToInteger",
                 { "type": "pulse", "interval": 0.5 },
-                { "type": "scale", "scale": -15 }
+                { "type": "scale", "scale": 15 }
             ]
         },
 
-        { "from": ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"],
+        { "from": { "makeAxis" : [
+                ["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"],
+                ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"]
+            ]
+          },
+
           "when": [ "Application.InHMD", "Application.ComfortMode" ],
           "to": "Actions.StepYaw",
           "filters":
@@ -22,25 +29,10 @@
             ]
         },
 
-        { "from": "Keyboard.MouseMoveLeft",
-          "when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseClick" ],
-          "to": "Actions.StepYaw",
-          "filters":
-            [
-                { "type": "pulse", "interval": 0.5 },
-                { "type": "scale", "scale": -15 }
-            ]
-        },
-
-        { "from": "Keyboard.MouseMoveRight",
-          "when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseClick" ],
-          "to": "Actions.StepYaw",
-          "filters":
-            [
-                { "type": "pulse", "interval": 0.5 },
-                { "type": "scale", "scale": 15 }
-            ]
-        },
+        { "from": ["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"], "to": "Actions.YAW_LEFT" },
+        { "from": ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"], "to": "Actions.YAW_RIGHT" },
+        { "from": "Keyboard.MouseMoveLeft", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_LEFT" },
+        { "from": "Keyboard.MouseMoveRight", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_RIGHT" },
 
         { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
         { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
@@ -53,8 +45,6 @@
 
         { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
         { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
-        { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" },
-        { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" },
         { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
         { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
 
@@ -67,21 +57,15 @@
 
         { "from": "Keyboard.Up", "to": "Actions.LONGITUDINAL_FORWARD" },
         { "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" },
-        { "from": "Keyboard.Left", "to": "Actions.YAW_LEFT" },
-        { "from": "Keyboard.Right", "to": "Actions.YAW_RIGHT" },
 
         { "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
         { "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },
 
-        { "from": "Keyboard.MouseMoveLeft", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_LEFT" },
-        { "from": "Keyboard.MouseMoveRight", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_RIGHT" },
         { "from": "Keyboard.MouseMoveUp", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_UP" },
         { "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_DOWN" },
 
         { "from": "Keyboard.TouchpadDown", "to": "Actions.PITCH_DOWN" },
         { "from": "Keyboard.TouchpadUp", "to": "Actions.PITCH_UP" },
-        { "from": "Keyboard.TouchpadLeft", "to": "Actions.YAW_LEFT" },
-        { "from": "Keyboard.TouchpadRight", "to": "Actions.YAW_RIGHT" },
 
         { "from": "Keyboard.MouseWheelUp", "to": "Actions.LATERAL_RIGHT" },
         { "from": "Keyboard.MouseWheelDown", "to": "Actions.LATERAL_LEFT" },
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index d7f57d91e3..d33e215797 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -489,7 +489,11 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
 
     // If the source hasn't been written yet, defer processing of this route
     auto source = route->source;
-    if (!force && source->writeable()) {
+    auto sourceInput = source->getInput();
+    if (sourceInput.device == STANDARD_DEVICE && !force && source->writeable()) {
+        if (debugRoutes && route->debug) {
+            qCDebug(controllers) << "Source not yet written, deferring";
+        }
         return false;
     }
 

From 70f31563284c06f7f58c2ce8f2f2794cc392f1bd Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Thu, 29 Oct 2015 22:37:12 -0700
Subject: [PATCH 254/301] make sure CompositeEndpoints properly report
 readability more axis based keyboard inputs

---
 .../resources/controllers/keyboardMouse.json    | 17 ++++++++++++-----
 .../impl/endpoints/CompositeEndpoint.cpp        |  4 ++++
 .../impl/endpoints/CompositeEndpoint.h          |  2 ++
 3 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
index e5abad761a..096cdb35d3 100644
--- a/interface/resources/controllers/keyboardMouse.json
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -19,7 +19,6 @@
                 ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"]
             ]
           },
-
           "when": [ "Application.InHMD", "Application.ComfortMode" ],
           "to": "Actions.StepYaw",
           "filters":
@@ -29,10 +28,18 @@
             ]
         },
 
-        { "from": ["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"], "to": "Actions.YAW_LEFT" },
-        { "from": ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"], "to": "Actions.YAW_RIGHT" },
-        { "from": "Keyboard.MouseMoveLeft", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_LEFT" },
-        { "from": "Keyboard.MouseMoveRight", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_RIGHT" },
+        { "from": { "makeAxis" : [
+                ["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"],
+                ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"]
+            ]
+          },
+          "to": "Actions.Yaw"
+        },
+
+        { "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
+          "when": "Keyboard.RightMouseClick",
+          "to": "Actions.Yaw",
+        },
 
         { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
         { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
diff --git a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
index e5088ef72c..913bf0136b 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
@@ -20,6 +20,10 @@ CompositeEndpoint::CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer
     }
 }
 
+bool CompositeEndpoint::readable() const {
+    return first->readable() && second->readable();
+}
+
 float CompositeEndpoint::value() {
     float result = first->value() * -1.0f + second->value();
     return result;
diff --git a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
index ab8b97aa50..c6ec90b7c8 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
@@ -19,6 +19,8 @@ namespace controller {
 
         virtual float value() override;
         virtual void apply(float newValue, const Pointer& source) override;
+        virtual bool readable() const override;
+
     };
 
 }

From a149a2dd60bcf1abfeb85f80ee02dea3d220c635 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 30 Oct 2015 00:19:14 -0700
Subject: [PATCH 255/301] fix some warnings

---
 libraries/gl/src/gl/GlWindow.cpp              | 3 +--
 libraries/physics/src/CharacterController.cpp | 4 ++--
 libraries/ui/src/VrMenu.cpp                   | 4 ++++
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/libraries/gl/src/gl/GlWindow.cpp b/libraries/gl/src/gl/GlWindow.cpp
index 7e43b29e73..40a5bedf7e 100644
--- a/libraries/gl/src/gl/GlWindow.cpp
+++ b/libraries/gl/src/gl/GlWindow.cpp
@@ -44,8 +44,7 @@ bool GlWindow::makeCurrent() {
         qDebug() << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER));
     });
     
-    QOpenGLContext * currentContext = QOpenGLContext::currentContext();
-    Q_ASSERT(_context == currentContext);
+    Q_ASSERT(_context == QOpenGLContext::currentContext());
     
     return makeCurrentResult;
 }
diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp
index aadf9b16ea..8da9541387 100644
--- a/libraries/physics/src/CharacterController.cpp
+++ b/libraries/physics/src/CharacterController.cpp
@@ -14,11 +14,11 @@
 #include "PhysicsCollisionGroups.h"
 
 bool CharacterController::needsRemoval() const {
-    return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION);
+    return ((_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION) == PENDING_FLAG_REMOVE_FROM_SIMULATION);
 }
 
 bool CharacterController::needsAddition() const {
-    return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION);
+    return ((_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION) == PENDING_FLAG_ADD_TO_SIMULATION);
 }
 
 void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp
index 57df4d5306..211e0e0f72 100644
--- a/libraries/ui/src/VrMenu.cpp
+++ b/libraries/ui/src/VrMenu.cpp
@@ -113,6 +113,7 @@ void VrMenu::addMenu(QMenu* menu) {
                                                   Q_ARG(QVariant, QVariant::fromValue(qmlParent)),
                                                   Q_ARG(QVariant, QVariant::fromValue(menu->title())));
     Q_ASSERT(invokeResult);
+    Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x
     QObject* result = returnedValue.value<QObject*>();
     Q_ASSERT(result);
 
@@ -153,6 +154,7 @@ void VrMenu::addAction(QMenu* menu, QAction* action) {
                                                   Q_ARG(QVariant, QVariant::fromValue(menuQml)),
                                                   Q_ARG(QVariant, QVariant::fromValue(action->text())));
     Q_ASSERT(invokeResult);
+    Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x
     QObject* result = returnedValue.value<QObject*>();
     Q_ASSERT(result);
     // Bind the QML and Widget together
@@ -174,6 +176,7 @@ void VrMenu::insertAction(QAction* before, QAction* action) {
                                                   Q_ARG(QVariant, QVariant::fromValue(beforeQml)),
                                                   Q_ARG(QVariant, QVariant::fromValue(action->text())));
     Q_ASSERT(invokeResult);
+    Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x
     QObject* result = returnedValue.value<QObject*>();
     Q_ASSERT(result);
     bindActionToQmlAction(result, action);
@@ -192,4 +195,5 @@ void VrMenu::removeAction(QAction* action) {
         Q_ARG(QVariant, QVariant::fromValue(menu)),
         Q_ARG(QVariant, QVariant::fromValue(item)));
     Q_ASSERT(invokeResult);
+    Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x
 }

From fcfab0fc513a96ae166318f613581cf083916e6e Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 29 Oct 2015 12:31:34 -0700
Subject: [PATCH 256/301] Moving SDL2, Sixense and Faceshift to external
 projects

---
 CMakeLists.txt                                | 25 ++++-----
 cmake/externals/faceshift/CMakeLists.txt      | 30 +++++++++++
 cmake/externals/sdl2/CMakeLists.txt           | 30 ++++-------
 cmake/externals/sixense/CMakeLists.txt        | 36 ++++---------
 .../AddDependencyExternalProjects.cmake       |  2 +-
 cmake/macros/TargetFaceshift.cmake            | 14 +++++
 cmake/macros/TargetSDL2.cmake                 | 14 +++++
 cmake/macros/TargetSixense.cmake              | 14 +++++
 cmake/modules/FindFaceshift.cmake             | 23 --------
 cmake/modules/FindSixense.cmake               | 45 +---------------
 interface/CMakeLists.txt                      | 13 +++--
 interface/external/faceshift/readme.txt       | 26 ---------
 interface/external/sdl2/readme.txt            | 13 -----
 interface/external/sixense/readme.txt         | 10 ----
 libraries/input-plugins/CMakeLists.txt        | 54 +------------------
 15 files changed, 119 insertions(+), 230 deletions(-)
 create mode 100644 cmake/externals/faceshift/CMakeLists.txt
 create mode 100644 cmake/macros/TargetFaceshift.cmake
 create mode 100644 cmake/macros/TargetSDL2.cmake
 create mode 100644 cmake/macros/TargetSixense.cmake
 delete mode 100644 interface/external/faceshift/readme.txt
 delete mode 100644 interface/external/sdl2/readme.txt
 delete mode 100644 interface/external/sixense/readme.txt

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 79d8a0c0e0..d69b8c4c77 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -186,21 +186,22 @@ set_property(DIRECTORY PROPERTY EP_PREFIX ${EXTERNAL_PROJECT_PREFIX})
 setup_externals_binary_dir()
 
 # setup options to grab external project dependencies
-option(GET_BULLET "Get Bullet library automatically as external project" 1)
-option(GET_GLM "Get GLM library automatically as external project" 1)
-option(GET_GVERB "Get Gverb library automatically as external project" 1)
-option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1)
-option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
-option(GET_VHACD "Get V-HACD library automatically as external project" 1)
-option(GET_POLYVOX "Get polyvox library automatically as external project" 1)
-option(GET_OPENVR "Get OpenVR library automatically as external project" 1)
-option(GET_BOOSTCONFIG "Get Boost-config library automatically as external project" 1)
-option(GET_OGLPLUS "Get OGLplus library automatically as external project" 1)
-option(GET_GLEW "Get GLEW library automatically as external project" 1)
+#option(GET_BULLET "Get Bullet library automatically as external project" 1)
+#option(GET_GLM "Get GLM library automatically as external project" 1)
+#option(GET_GVERB "Get Gverb library automatically as external project" 1)
+#option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1)
+#option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
+#option(GET_VHACD "Get V-HACD library automatically as external project" 1)
+#option(GET_POLYVOX "Get polyvox library automatically as external project" 1)
+#option(GET_OPENVR "Get OpenVR library automatically as external project" 1)
+#option(GET_BOOSTCONFIG "Get Boost-config library automatically as external project" 1)
+#option(GET_OGLPLUS "Get OGLplus library automatically as external project" 1)
+#option(GET_GLEW "Get GLEW library automatically as external project" 1)
+#option(GET_SDL2 "Get SDL2 library automatically as external project" 1)
+#option(GET_SIXENSE "Get Sixense library automatically as external project" 1)
 
 option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
 
-option(GET_SDL2 "Get SDL2 library automatically as external project" 0)
 
 if (WIN32)
   add_paths_to_fixup_libs("${QT_DIR}/bin")
diff --git a/cmake/externals/faceshift/CMakeLists.txt b/cmake/externals/faceshift/CMakeLists.txt
new file mode 100644
index 0000000000..b18b861912
--- /dev/null
+++ b/cmake/externals/faceshift/CMakeLists.txt
@@ -0,0 +1,30 @@
+set(EXTERNAL_NAME faceshift)
+
+include(ExternalProject)
+ExternalProject_Add(
+  ${EXTERNAL_NAME}
+  URL https://hifi-public.s3.amazonaws.com/dependencies/faceshift.zip
+  CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+  BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
+  LOG_DOWNLOAD 1
+  LOG_CONFIGURE 1
+  LOG_BUILD 1
+)
+
+#  URL_MD5 1bdcb8a0b8d5b1ede434cc41efade41d
+
+# Hide this external target (for ide users)
+set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
+
+ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
+
+string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
+set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to Faceshift include directory")
+
+if (WIN32)
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/faceshift.lib CACHE FILEPATH "Faceshift libraries")
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/faceshift.lib CACHE FILEPATH "Faceshift libraries")
+elseif (APPLE)
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/libfaceshift.a CACHE FILEPATH "Faceshift libraries")
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/libfaceshift.a CACHE FILEPATH "Faceshift libraries")
+endif()
diff --git a/cmake/externals/sdl2/CMakeLists.txt b/cmake/externals/sdl2/CMakeLists.txt
index e6c80cf6ef..0f44f28610 100644
--- a/cmake/externals/sdl2/CMakeLists.txt
+++ b/cmake/externals/sdl2/CMakeLists.txt
@@ -47,25 +47,13 @@ if (APPLE)
   ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
   set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/SDL2.framework/Headers CACHE PATH "Location of SDL2 include directory")
   set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/SDL2.framework/SDL2 CACHE STRING "Path to SDL2 library")
+elseif (WIN32)
+  ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
+  set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/include CACHE PATH "Location of SDL2 include directory")
+  set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/lib/x86/SDL2.lib CACHE FILEPATH "Path to SDL2 library")
+  set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/lib/x86 CACHE PATH "Location of SDL2 DLL")
 else ()
-  if (WIN32)
-    ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
-    set(_ROOT_DIR ${SOURCE_DIR})
-    set(_INCLUDE_DIR ${_ROOT_DIR}/include)
-    set(_LIB_DIR "${SOURCE_DIR}/lib/x86")
-    set(_LIB_EXT "lib")
-  
-    set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${_LIB_DIR} CACHE PATH "Location of SDL2 DLL")
-  else ()
-    ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
-    set(_ROOT_DIR ${INSTALL_DIR})
-    set(_INCLUDE_DIR ${_ROOT_DIR}/include/SDL2)
-  
-    set(_LIB_DIR ${INSTALL_DIR}/lib)
-    set(_LIB_EXT "so")
-    set(_LIB_PREFIX "lib")
-  endif ()
-
-  set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${_INCLUDE_DIR} CACHE PATH "Location of SDL2 include directory")
-  set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${_LIB_DIR}/${_LIB_PREFIX}SDL2.${_LIB_EXT} CACHE FILEPATH "Path to SDL2 library")
-endif ()
\ No newline at end of file
+  ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
+  set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include/SDL2 CACHE PATH "Location of SDL2 include directory")
+  set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${INSTALL_DIR}/lib/libSDL2.so CACHE FILEPATH "Path to SDL2 library")
+endif ()
diff --git a/cmake/externals/sixense/CMakeLists.txt b/cmake/externals/sixense/CMakeLists.txt
index f6646e2272..72de4a7e15 100644
--- a/cmake/externals/sixense/CMakeLists.txt
+++ b/cmake/externals/sixense/CMakeLists.txt
@@ -1,30 +1,20 @@
 include(ExternalProject)
-include(SelectLibraryConfigurations)
 
-set(EXTERNAL_NAME Sixense)
+set(EXTERNAL_NAME sixense)
 
 string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
 
 ExternalProject_Add(
   ${EXTERNAL_NAME}
-  URL ./SixenseSDK_062612.zip
-  URL_MD5 10cc8dc470d2ac1244a88cf04bc549cc
+  URL http://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_071615.zip
+  URL_MD5 752a3901f334124e9cffc2ba4136ef7d
   CONFIGURE_COMMAND ""
   BUILD_COMMAND ""
   INSTALL_COMMAND ""
   LOG_DOWNLOAD 1
 )
 
-if (APPLE)
-  find_library(SIXENSE_LIBRARY_RELEASE lib/osx_x64/release_dll/libsixense_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS})
-  find_library(SIXENSE_LIBRARY_DEBUG lib/osx_x64/debug_dll/libsixensed_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS})
-elseif (UNIX)
-  find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
-  # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
-elseif (WIN32)
-endif ()
-
-
+set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
 
 ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
 
@@ -39,22 +29,18 @@ if (WIN32)
         set(ARCH_DIR "Win32")
         set(ARCH_SUFFIX "")
     endif()
-
-  # FIXME need to account for different architectures 
-  set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${SOURCE_DIR}/lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL)
-  add_paths_to_fixup_libs(${SOURCE_DIR}/bin/win32)
+    
+    set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${SOURCE_DIR}/lib/${ARCH_DIR}/VS2013/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL)
+    add_paths_to_fixup_libs("${SOURCE_DIR}/bin/${ARCH_DIR}/VS2013/release_dll")
 
 elseif(APPLE)
 
-  # FIXME need to account for different architectures 
-  set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
-  add_paths_to_fixup_libs(${SOURCE_DIR}/bin/osx32)
+    set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
 
 elseif(NOT ANDROID)
 
-  # FIXME need to account for different architectures 
-  set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux_x64/release/libsixense_x64.so CACHE TYPE INTERNAL)
-  add_paths_to_fixup_libs(${SOURCE_DIR}/bin/linux32)
-  
+    # FIXME need to account for different architectures 
+    set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux_x64/release/libsixense_x64.so CACHE TYPE INTERNAL)
+
 endif()
 
diff --git a/cmake/macros/AddDependencyExternalProjects.cmake b/cmake/macros/AddDependencyExternalProjects.cmake
index e859ef2db5..e8292c3198 100644
--- a/cmake/macros/AddDependencyExternalProjects.cmake
+++ b/cmake/macros/AddDependencyExternalProjects.cmake
@@ -16,7 +16,7 @@ macro(ADD_DEPENDENCY_EXTERNAL_PROJECTS)
     string(TOUPPER ${_PROJ_NAME} _PROJ_NAME_UPPER)
     
     # has the user told us they specific don't want this as an external project?
-    if (GET_${_PROJ_NAME_UPPER})
+    if (NOT DISABLE_${_PROJ_NAME_UPPER})
       # have we already detected we can't have this as external project on this OS?
       if (NOT DEFINED ${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT OR ${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT)
         # have we already setup the target?
diff --git a/cmake/macros/TargetFaceshift.cmake b/cmake/macros/TargetFaceshift.cmake
new file mode 100644
index 0000000000..99f65d942a
--- /dev/null
+++ b/cmake/macros/TargetFaceshift.cmake
@@ -0,0 +1,14 @@
+# 
+#  Copyright 2015 High Fidelity, Inc.
+#  Created by Bradley Austin Davis on 2015/10/10
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+# 
+macro(TARGET_FACESHIFT)
+    add_dependency_external_projects(faceshift)
+    find_package(Faceshift REQUIRED)
+    target_include_directories(${TARGET_NAME} PRIVATE ${FACESHIFT_INCLUDE_DIRS})
+    target_link_libraries(${TARGET_NAME} ${FACESHIFT_LIBRARIES})
+    add_definitions(-DHAVE_FACESHIFT)
+endmacro()
\ No newline at end of file
diff --git a/cmake/macros/TargetSDL2.cmake b/cmake/macros/TargetSDL2.cmake
new file mode 100644
index 0000000000..ee2328dfff
--- /dev/null
+++ b/cmake/macros/TargetSDL2.cmake
@@ -0,0 +1,14 @@
+# 
+#  Copyright 2015 High Fidelity, Inc.
+#  Created by Bradley Austin Davis on 2015/10/10
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+# 
+macro(TARGET_SDL2)
+    add_dependency_external_projects(sdl2)
+    find_package(SDL2 REQUIRED)
+    target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SDL2_INCLUDE_DIR})
+    target_link_libraries(${TARGET_NAME} ${SDL2_LIBRARY})
+    add_definitions(-DHAVE_SDL2)
+endmacro()
\ No newline at end of file
diff --git a/cmake/macros/TargetSixense.cmake b/cmake/macros/TargetSixense.cmake
new file mode 100644
index 0000000000..b52af9cdd2
--- /dev/null
+++ b/cmake/macros/TargetSixense.cmake
@@ -0,0 +1,14 @@
+# 
+#  Copyright 2015 High Fidelity, Inc.
+#  Created by Bradley Austin Davis on 2015/10/10
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+# 
+macro(TARGET_SIXENSE)
+    add_dependency_external_projects(sixense)
+    find_package(Sixense REQUIRED)
+    target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS})
+    target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES})
+    add_definitions(-DHAVE_SIXENSE)
+endmacro()
\ No newline at end of file
diff --git a/cmake/modules/FindFaceshift.cmake b/cmake/modules/FindFaceshift.cmake
index 1f8b7b19fe..bd77951273 100644
--- a/cmake/modules/FindFaceshift.cmake
+++ b/cmake/modules/FindFaceshift.cmake
@@ -18,32 +18,9 @@
 #  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 # 
 
-include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
-hifi_library_search_hints("faceshift")
-
-find_path(FACESHIFT_INCLUDE_DIRS fsbinarystream.h PATH_SUFFIXES include HINTS ${FACESHIFT_SEARCH_DIRS})
-
-if (APPLE)
-  set(ARCH_DIR "MacOS")
-elseif (UNIX)
-  set(ARCH_DIR "UNIX")
-elseif (WIN32)
-  if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
-    set(ARCH_DIR "x64")
-  else()
-    set(ARCH_DIR "Win32")
-  endif()
-endif ()
-
-find_library(FACESHIFT_LIBRARY_RELEASE NAME faceshift PATH_SUFFIXES lib/${ARCH_DIR} HINTS ${FACESHIFT_SEARCH_DIRS})
-find_library(FACESHIFT_LIBRARY_DEBUG NAME faceshiftd PATH_SUFFIXES lib/${ARCH_DIR} HINTS ${FACESHIFT_SEARCH_DIRS})
-
 include(SelectLibraryConfigurations)
 select_library_configurations(FACESHIFT)
 
-set(FACESHIFT_LIBRARIES ${FACESHIFT_LIBRARY})
-
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Faceshift DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES)
-
 mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES FACESHIFT_SEARCH_DIRS)
\ No newline at end of file
diff --git a/cmake/modules/FindSixense.cmake b/cmake/modules/FindSixense.cmake
index 98b37d5410..9abacac136 100644
--- a/cmake/modules/FindSixense.cmake
+++ b/cmake/modules/FindSixense.cmake
@@ -18,49 +18,6 @@
 #  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 # 
 
-include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
-hifi_library_search_hints("sixense")
-
-find_path(SIXENSE_INCLUDE_DIRS sixense.h PATH_SUFFIXES include HINTS ${SIXENSE_SEARCH_DIRS})
-
-if (APPLE)
-  find_library(SIXENSE_LIBRARY_RELEASE lib/osx_x64/release_dll/libsixense_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS})
-  find_library(SIXENSE_LIBRARY_DEBUG lib/osx_x64/debug_dll/libsixensed_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS})
-elseif (UNIX)
-  find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
-  # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
-elseif (WIN32)
-    if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
-        set(ARCH_DIR "x64")
-        set(ARCH_SUFFIX "_x64")
-    else()
-        set(ARCH_DIR "Win32")
-        set(ARCH_SUFFIX "")
-    endif()
-
-  find_library(SIXENSE_LIBRARY_RELEASE "lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" HINTS ${SIXENSE_SEARCH_DIRS})
-  find_library(SIXENSE_LIBRARY_DEBUG "lib/${ARCH_DIR}/debug_dll/sixensed.lib" HINTS ${SIXENSE_SEARCH_DIRS})
-  
-  find_path(SIXENSE_DEBUG_DLL_PATH "sixensed${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/debug_dll HINTS ${SIXENSE_SEARCH_DIRS})
-  find_path(SIXENSE_RELEASE_DLL_PATH "sixense${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/release_dll HINTS ${SIXENSE_SEARCH_DIRS})
-  find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/${ARCH_DIR}/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS})
-endif ()
-
-include(SelectLibraryConfigurations)
-select_library_configurations(SIXENSE)
-
-set(SIXENSE_REQUIREMENTS SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
-if (WIN32)
-  list(APPEND SIXENSE_REQUIREMENTS SIXENSE_DEBUG_DLL_PATH SIXENSE_RELEASE_DLL_PATH SIXENSE_DEVICE_DLL_PATH)
-endif ()
-
-set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}")
-
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Sixense DEFAULT_MSG ${SIXENSE_REQUIREMENTS})
-
-if (WIN32)
-  add_paths_to_fixup_libs(${SIXENSE_DEBUG_DLL_PATH} ${SIXENSE_RELEASE_DLL_PATH} ${SIXENSE_DEVICE_DLL_PATH})
-endif ()
-
+find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
 mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)
diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index f9c92c59e7..f04fa88910 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -2,7 +2,12 @@ set(TARGET_NAME interface)
 project(${TARGET_NAME})
 
 # set a default root dir for each of our optional externals if it was not passed
-set(OPTIONAL_EXTERNALS "Faceshift" "LeapMotion" "RtMidi" "RSSDK" "3DConnexionClient" "iViewHMD")
+set(OPTIONAL_EXTERNALS "LeapMotion" "RtMidi" "RSSDK" "iViewHMD")
+
+if(WIN32)
+    list(APPEND OPTIONAL_EXTERNALS "3DConnexionClient")
+endif()
+
 foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
   string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
   if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
@@ -102,12 +107,14 @@ link_hifi_libraries(shared octree environment gpu gl procedural model render
                     render-utils entities-renderer ui auto-updater 
                     plugins display-plugins input-plugins)
 
+#fixme find a way to express faceshift as a plugin
 target_bullet()
 target_glew()
 target_opengl()
 
-
-add_dependency_external_projects(sdl2)
+if (WIN32 OR APPLE)
+    target_faceshift()
+endif()
 
 # perform standard include and linking for found externals
 foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
diff --git a/interface/external/faceshift/readme.txt b/interface/external/faceshift/readme.txt
deleted file mode 100644
index 4208711632..0000000000
--- a/interface/external/faceshift/readme.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-
-Instructions for adding the Faceshift library to Interface
-Stephen Birarda, July 18th, 2014
-
-OS X users: You can also use homebrew to get the Faceshift library by tapping our repo - highfidelity/homebrew-formulas
-and then calling 'brew install highfidelity/formulas/faceshift'.
-
-You can download the Faceshift SDK from http://download.faceshift.com/faceshift-network.zip.
-
-Create a ‘faceshift’ folder under interface/externals.    
-   
-You may optionally choose to place this folder in a location outside the repository (so you can re-use with different checkouts and different projects). 
-
-If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder ‘faceshift’ that contains the lib and include folders. 
-
-1. Build a Faceshift static library from the fsbinarystream.cpp file.
-    Windows: Win32 console application; no precompiled header or SDL checks; no ATL or MFC headers; Project Properties, Configuration Type = Static Library (.lib).
-
-2. Copy the library files to the ‘lib’ folder in your Faceshift folder.
-    OSX: If you build a release version call it libfaceshift.a. The debug version should be called libfaceshiftd.a.
-    Windows: The release and debug versions should be called faceshift.lib and faceshiftd.lib, respectively. Copy them into a ‘Win32’ folder in your ‘lib’ folder.
-
-3. Copy the fsbinarystream.h header file from the Faceshift SDK into the ‘include’ folder in your Faceshift folder.
-
-4. Clear your build directory, run cmake and build, and you should be all set.
-
diff --git a/interface/external/sdl2/readme.txt b/interface/external/sdl2/readme.txt
deleted file mode 100644
index 9f3bd40e15..0000000000
--- a/interface/external/sdl2/readme.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-
-Instructions for adding the SDL library (SDL2) to Interface
-David Rowe, 11 Jan 2015
-
-You can download the SDL development library from https://www.libsdl.org/. Interface has been tested with version 2.0.3.
-
-1. Copy the include and lib folders into the interface/externals/sdl2 folder.
-   This readme.txt should be there as well.
-   
-   You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects). 
-   If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'sdl2' that contains the two folders mentioned above.
-
-2. Clear your build directory, run cmake and build, and you should be all set.
diff --git a/interface/external/sixense/readme.txt b/interface/external/sixense/readme.txt
deleted file mode 100644
index a4790caa5e..0000000000
--- a/interface/external/sixense/readme.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-
-Instructions for adding the Sixense driver to Interface
-Andrzej Kapolka, November 18, 2013
-
-1. Copy the Sixense sdk folders (bin, include, lib, and samples) into the interface/external/Sixense folder. This readme.txt should be there as well.
-    
-   You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects).
-   If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'sixense' that contains the folders mentioned above.
-
-3. Delete your build directory, run cmake and build, and you should be all set.
diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt
index 094a697012..c26e14e756 100644
--- a/libraries/input-plugins/CMakeLists.txt
+++ b/libraries/input-plugins/CMakeLists.txt
@@ -11,55 +11,5 @@ if (WIN32)
     target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
 endif()
 
-#add_dependency_external_projects(Sixense)
-#find_package(Sixense REQUIRED)
-#target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS})
-#target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES})
-
-# set a default root dir for each of our optional externals if it was not passed
-set(OPTIONAL_EXTERNALS "SDL2" "Sixense")
-foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
-  string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
-  if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
-    string(TOLOWER ${EXTERNAL} ${EXTERNAL}_LOWERCASE)
-    set(${${EXTERNAL}_UPPERCASE}_ROOT_DIR "${CMAKE_SOURCE_DIR}/interface/external/${${EXTERNAL}_LOWERCASE}")
-  endif ()
-endforeach()
-
-# perform standard include and linking for found externals
-foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
-  
-  if (${${EXTERNAL}_UPPERCASE}_REQUIRED)
-    find_package(${EXTERNAL} REQUIRED)
-  else ()
-    find_package(${EXTERNAL})
-  endif ()
-  
-  if (${${EXTERNAL}_UPPERCASE}_FOUND AND NOT DISABLE_${${EXTERNAL}_UPPERCASE})
-    add_definitions(-DHAVE_${${EXTERNAL}_UPPERCASE})
-    
-    # include the library directories (ignoring warnings)
-    if (NOT ${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS)
-      set(${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIR})
-    endif ()
-    
-    include_directories(SYSTEM ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
-    
-    # perform the system include hack for OS X to ignore warnings
-    if (APPLE)
-      foreach(EXTERNAL_INCLUDE_DIR  ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
-        SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}")
-      endforeach()
-    endif ()
-    
-    if (NOT ${${EXTERNAL}_UPPERCASE}_LIBRARIES)
-      set(${${EXTERNAL}_UPPERCASE}_LIBRARIES ${${${EXTERNAL}_UPPERCASE}_LIBRARY})
-    endif ()
-    
-    if (NOT APPLE OR NOT ${${EXTERNAL}_UPPERCASE} MATCHES "SIXENSE")
-      target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES})
-    elseif (APPLE AND NOT INSTALLER_BUILD)
-      add_definitions(-DSIXENSE_LIB_FILENAME=\"${${${EXTERNAL}_UPPERCASE}_LIBRARY_RELEASE}\")
-    endif ()
-  endif ()
-endforeach()
+target_sdl2()
+target_sixense()

From e12ddf86f6b3fb90c3f51f3e63b322760ac5af84 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 30 Oct 2015 08:33:29 -0700
Subject: [PATCH 257/301] add back optional externals

---
 CMakeLists.txt | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d69b8c4c77..11ef4752f5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -186,19 +186,19 @@ set_property(DIRECTORY PROPERTY EP_PREFIX ${EXTERNAL_PROJECT_PREFIX})
 setup_externals_binary_dir()
 
 # setup options to grab external project dependencies
-#option(GET_BULLET "Get Bullet library automatically as external project" 1)
-#option(GET_GLM "Get GLM library automatically as external project" 1)
-#option(GET_GVERB "Get Gverb library automatically as external project" 1)
-#option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1)
-#option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
-#option(GET_VHACD "Get V-HACD library automatically as external project" 1)
-#option(GET_POLYVOX "Get polyvox library automatically as external project" 1)
-#option(GET_OPENVR "Get OpenVR library automatically as external project" 1)
-#option(GET_BOOSTCONFIG "Get Boost-config library automatically as external project" 1)
-#option(GET_OGLPLUS "Get OGLplus library automatically as external project" 1)
-#option(GET_GLEW "Get GLEW library automatically as external project" 1)
-#option(GET_SDL2 "Get SDL2 library automatically as external project" 1)
-#option(GET_SIXENSE "Get Sixense library automatically as external project" 1)
+option(GET_BULLET "Get Bullet library automatically as external project" 1)
+option(GET_GLM "Get GLM library automatically as external project" 1)
+option(GET_GVERB "Get Gverb library automatically as external project" 1)
+option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1)
+option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
+option(GET_VHACD "Get V-HACD library automatically as external project" 1)
+option(GET_POLYVOX "Get polyvox library automatically as external project" 1)
+option(GET_OPENVR "Get OpenVR library automatically as external project" 1)
+option(GET_BOOSTCONFIG "Get Boost-config library automatically as external project" 1)
+option(GET_OGLPLUS "Get OGLplus library automatically as external project" 1)
+option(GET_GLEW "Get GLEW library automatically as external project" 1)
+option(GET_SDL2 "Get SDL2 library automatically as external project" 1)
+option(GET_SIXENSE "Get Sixense library automatically as external project" 1)
 
 option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
 

From fb3bf163913a2fa7cb79a8c85354c22950cf0274 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 30 Oct 2015 09:01:42 -0700
Subject: [PATCH 258/301] improvement to cmake to explicitly use local external
 dependency

---
 CMakeLists.txt                                   | 15 ---------------
 cmake/macros/AddDependencyExternalProjects.cmake |  2 +-
 2 files changed, 1 insertion(+), 16 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 11ef4752f5..efe99b550b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -185,21 +185,6 @@ set(EXTERNAL_PROJECT_PREFIX "project")
 set_property(DIRECTORY PROPERTY EP_PREFIX ${EXTERNAL_PROJECT_PREFIX})
 setup_externals_binary_dir()
 
-# setup options to grab external project dependencies
-option(GET_BULLET "Get Bullet library automatically as external project" 1)
-option(GET_GLM "Get GLM library automatically as external project" 1)
-option(GET_GVERB "Get Gverb library automatically as external project" 1)
-option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1)
-option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
-option(GET_VHACD "Get V-HACD library automatically as external project" 1)
-option(GET_POLYVOX "Get polyvox library automatically as external project" 1)
-option(GET_OPENVR "Get OpenVR library automatically as external project" 1)
-option(GET_BOOSTCONFIG "Get Boost-config library automatically as external project" 1)
-option(GET_OGLPLUS "Get OGLplus library automatically as external project" 1)
-option(GET_GLEW "Get GLEW library automatically as external project" 1)
-option(GET_SDL2 "Get SDL2 library automatically as external project" 1)
-option(GET_SIXENSE "Get Sixense library automatically as external project" 1)
-
 option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
 
 
diff --git a/cmake/macros/AddDependencyExternalProjects.cmake b/cmake/macros/AddDependencyExternalProjects.cmake
index e8292c3198..e35ca98959 100644
--- a/cmake/macros/AddDependencyExternalProjects.cmake
+++ b/cmake/macros/AddDependencyExternalProjects.cmake
@@ -16,7 +16,7 @@ macro(ADD_DEPENDENCY_EXTERNAL_PROJECTS)
     string(TOUPPER ${_PROJ_NAME} _PROJ_NAME_UPPER)
     
     # has the user told us they specific don't want this as an external project?
-    if (NOT DISABLE_${_PROJ_NAME_UPPER})
+    if (NOT USE_LOCAL_${_PROJ_NAME_UPPER})
       # have we already detected we can't have this as external project on this OS?
       if (NOT DEFINED ${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT OR ${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT)
         # have we already setup the target?

From 7a4787a79cec2d33471ae86ebbb27f511705e2d8 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Fri, 30 Oct 2015 09:21:13 -0700
Subject: [PATCH 259/301] Rename stepSimulation to
 stepSimulationWithSubstepCallback to fix warning

---
 libraries/physics/src/PhysicsEngine.cpp           | 7 ++++---
 libraries/physics/src/ThreadSafeDynamicsWorld.cpp | 5 +++--
 libraries/physics/src/ThreadSafeDynamicsWorld.h   | 5 +++--
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp
index 6773cecb14..2abe4317d7 100644
--- a/libraries/physics/src/PhysicsEngine.cpp
+++ b/libraries/physics/src/PhysicsEngine.cpp
@@ -228,7 +228,7 @@ void PhysicsEngine::removeContacts(ObjectMotionState* motionState) {
 
 void PhysicsEngine::stepSimulation() {
     CProfileManager::Reset();
-    BT_PROFILE("stepSimulation");
+    BT_PROFILE("stepSimulationWithSubstepCallback");
     // NOTE: the grand order of operations is:
     // (1) pull incoming changes
     // (2) step simulation
@@ -241,7 +241,7 @@ void PhysicsEngine::stepSimulation() {
     float timeStep = btMin(dt, MAX_TIMESTEP);
 
     if (_myAvatarController) {
-        // ADEBUG TODO: move this stuff outside and in front of stepSimulation, because 
+        // ADEBUG TODO: move this stuff outside and in front of stepSimulationWithSubstepCallback, because
         // the updateShapeIfNecessary() call needs info from MyAvatar and should
         // be done on the main thread during the pre-simulation stuff
         if (_myAvatarController->needsRemoval()) {
@@ -263,7 +263,8 @@ void PhysicsEngine::stepSimulation() {
         updateContactMap();
     };
 
-    int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, PHYSICS_ENGINE_MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP, onSubStep);
+    int numSubsteps = _dynamicsWorld->stepSimulationWithSubstepCallback(timeStep, PHYSICS_ENGINE_MAX_NUM_SUBSTEPS,
+                                                                        PHYSICS_ENGINE_FIXED_SUBSTEP, onSubStep);
     if (numSubsteps > 0) {
         BT_PROFILE("postSimulation");
         _numSubsteps += (uint32_t)numSubsteps;
diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
index 8bf7cdab20..94d6315705 100644
--- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
+++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
@@ -27,8 +27,9 @@ ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
     :   btDiscreteDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration) {
 }
 
-int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep, SubStepCallback onSubStep) {
-    BT_PROFILE("stepSimulation");
+int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep, int maxSubSteps,
+                                                               btScalar fixedTimeStep, SubStepCallback onSubStep) {
+    BT_PROFILE("stepSimulationWithSubstepCallback");
     int subSteps = 0;
     if (maxSubSteps) {
         //fixed timestep with interpolation
diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h
index 1f6ce09d0c..26954832cf 100644
--- a/libraries/physics/src/ThreadSafeDynamicsWorld.h
+++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h
@@ -37,8 +37,9 @@ public:
             btConstraintSolver* constraintSolver,
             btCollisionConfiguration* collisionConfiguration);
 
-    // virtual overrides from btDiscreteDynamicsWorld
-    int stepSimulation( btScalar timeStep, int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.), SubStepCallback onSubStep = []() { });
+    int stepSimulationWithSubstepCallback(btScalar timeStep, int maxSubSteps = 1,
+                                          btScalar fixedTimeStep = btScalar(1.)/btScalar(60.),
+                                          SubStepCallback onSubStep = []() { });
     void synchronizeMotionStates();
 
     // btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated

From 84869c512b44ac1ca27b2e6cadd2616ac0ea865c Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Fri, 30 Oct 2015 09:30:22 -0700
Subject: [PATCH 260/301] Fix mis-renamed method names

---
 libraries/physics/src/PhysicsEngine.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp
index 2abe4317d7..1e652b75c4 100644
--- a/libraries/physics/src/PhysicsEngine.cpp
+++ b/libraries/physics/src/PhysicsEngine.cpp
@@ -228,7 +228,7 @@ void PhysicsEngine::removeContacts(ObjectMotionState* motionState) {
 
 void PhysicsEngine::stepSimulation() {
     CProfileManager::Reset();
-    BT_PROFILE("stepSimulationWithSubstepCallback");
+    BT_PROFILE("stepSimulation");
     // NOTE: the grand order of operations is:
     // (1) pull incoming changes
     // (2) step simulation
@@ -241,7 +241,7 @@ void PhysicsEngine::stepSimulation() {
     float timeStep = btMin(dt, MAX_TIMESTEP);
 
     if (_myAvatarController) {
-        // ADEBUG TODO: move this stuff outside and in front of stepSimulationWithSubstepCallback, because
+        // ADEBUG TODO: move this stuff outside and in front of stepSimulation, because
         // the updateShapeIfNecessary() call needs info from MyAvatar and should
         // be done on the main thread during the pre-simulation stuff
         if (_myAvatarController->needsRemoval()) {

From 9607812116aac4a02a0efe50a7ac72ec2aa9243d Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 30 Oct 2015 10:18:51 -0700
Subject: [PATCH 261/301] Fixing input plugin dependencies

---
 libraries/input-plugins/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt
index cd3fae8e6a..0e21d4a40c 100644
--- a/libraries/input-plugins/CMakeLists.txt
+++ b/libraries/input-plugins/CMakeLists.txt
@@ -1,6 +1,6 @@
 set(TARGET_NAME input-plugins)
 setup_hifi_library()
-link_hifi_libraries(shared plugins controllers render-utils)
+link_hifi_libraries(shared plugins controllers script-engine render-utils)
 
 GroupSources("src/input-plugins")
 

From 93503d0a216019cff88a2b08441f88539881932f Mon Sep 17 00:00:00 2001
From: Seth Alves <seth@highfidelity.io>
Date: Fri, 30 Oct 2015 11:03:13 -0700
Subject: [PATCH 262/301] make kinematic grab set entities kinematic in bullet
 and update entity position

---
 examples/controllers/handControllerGrab.js | 24 ++++++++++++++++------
 interface/src/avatar/AvatarActionHold.cpp  |  5 +++++
 libraries/physics/src/ObjectAction.cpp     | 15 +++++++++++++-
 libraries/physics/src/ObjectMotionState.h  |  9 ++++++++
 4 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index cb445a0960..9ee9ed1e04 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -55,6 +55,7 @@ var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held
 var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected
 var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
 var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object
+var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed
 
 /////////////////////////////////////////////////////////////////
 //
@@ -404,8 +405,9 @@ function MyController(hand, triggerAction) {
 
         var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
         var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
-        var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation",
-                                                                                  "gravity", "ignoreForCollisions"]);
+        var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation", "gravity",
+                                                                                  "ignoreForCollisions",
+                                                                                  "collisionsWillMove"]);
         var now = Date.now();
 
         // add the action and initialize some variables
@@ -549,8 +551,14 @@ function MyController(hand, triggerAction) {
         this.lineOff();
 
         var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
-                                                             ["position", "rotation", "gravity", "ignoreForCollisions"]);
+                                                             ["position", "rotation", "gravity",
+                                                              "ignoreForCollisions", "collisionsWillMove"]);
         this.activateEntity(this.grabbedEntity, grabbedProperties);
+        if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) {
+            Entities.editEntity(this.grabbedEntity, {
+                collisionsWillMove: false
+            });
+        }
 
         var handRotation = this.getHandRotation();
         var handPosition = this.getHandPosition();
@@ -579,7 +587,8 @@ function MyController(hand, triggerAction) {
             timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
             relativePosition: this.offsetPosition,
             relativeRotation: this.offsetRotation,
-            ttl: ACTION_TTL
+            ttl: ACTION_TTL,
+            kinematic: NEAR_GRABBING_KINEMATIC
         });
         if (this.actionID === NULL_ACTION_ID) {
             this.actionID = null;
@@ -631,7 +640,8 @@ function MyController(hand, triggerAction) {
                 timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
                 relativePosition: this.offsetPosition,
                 relativeRotation: this.offsetRotation,
-                ttl: ACTION_TTL
+                ttl: ACTION_TTL,
+                kinematic: NEAR_GRABBING_KINEMATIC
             });
             this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
         }
@@ -828,6 +838,7 @@ function MyController(hand, triggerAction) {
         if (data["refCount"] == 1) {
             data["gravity"] = grabbedProperties.gravity;
             data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
+            data["collisionsWillMove"] = grabbedProperties.collisionsWillMove;
             var whileHeldProperties = {gravity: {x:0, y:0, z:0}};
             if (invertSolidWhileHeld) {
                 whileHeldProperties["ignoreForCollisions"] = ! grabbedProperties.ignoreForCollisions;
@@ -845,7 +856,8 @@ function MyController(hand, triggerAction) {
             if (data["refCount"] < 1) {
                 Entities.editEntity(entityID, {
                     gravity: data["gravity"],
-                    ignoreForCollisions: data["ignoreForCollisions"]
+                    ignoreForCollisions: data["ignoreForCollisions"],
+                    collisionsWillMove: data["collisionsWillMove"]
                 });
                 data = null;
             }
diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp
index 238e48d2fd..59bfd88be6 100644
--- a/interface/src/avatar/AvatarActionHold.cpp
+++ b/interface/src/avatar/AvatarActionHold.cpp
@@ -119,6 +119,9 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
         worldTrans.setRotation(glmToBullet(_rotationalTarget));
         rigidBody->setWorldTransform(worldTrans);
 
+        ownerEntity->setPosition(_positionalTarget);
+        ownerEntity->setRotation(_rotationalTarget);
+
         _previousPositionalTarget = _positionalTarget;
         _previousRotationalTarget = _rotationalTarget;
         _previousSet = true;
@@ -224,6 +227,8 @@ QVariantMap AvatarActionHold::getArguments() {
         arguments["relativeRotation"] = glmToQMap(_relativeRotation);
         arguments["timeScale"] = _linearTimeScale;
         arguments["hand"] = _hand;
+        arguments["kinematic"] = _kinematic;
+        arguments["kinematicSetVelocity"] = _kinematicSetVelocity;
     });
     return arguments;
 }
diff --git a/libraries/physics/src/ObjectAction.cpp b/libraries/physics/src/ObjectAction.cpp
index ff8382a143..d44ebc30b1 100644
--- a/libraries/physics/src/ObjectAction.cpp
+++ b/libraries/physics/src/ObjectAction.cpp
@@ -35,7 +35,9 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
     if (ownerEntityExpired) {
         qDebug() << "warning -- action with no entity removing self from btCollisionWorld.";
         btDynamicsWorld* dynamicsWorld = static_cast<btDynamicsWorld*>(collisionWorld);
-        dynamicsWorld->removeAction(this);
+        if (dynamicsWorld) {
+            dynamicsWorld->removeAction(this);
+        }
         return;
     }
 
@@ -120,6 +122,17 @@ QVariantMap ObjectAction::getArguments() {
             arguments["ttl"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
         }
         arguments["tag"] = _tag;
+
+        EntityItemPointer entity = _ownerEntity.lock();
+        if (entity) {
+            ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
+            if (motionState) {
+                arguments["::active"] = motionState->isActive();
+                arguments["::motion-type"] = motionTypeToString(motionState->getMotionType());
+            } else {
+                arguments["::no-motion-state"] = true;
+            }
+        }
     });
     return arguments;
 }
diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h
index 450ac34a90..22f0e9dcb0 100644
--- a/libraries/physics/src/ObjectMotionState.h
+++ b/libraries/physics/src/ObjectMotionState.h
@@ -29,6 +29,15 @@ enum MotionType {
     MOTION_TYPE_KINEMATIC   // keyframed motion
 };
 
+inline QString motionTypeToString(MotionType motionType) {
+    switch(motionType) {
+        case MOTION_TYPE_STATIC: return QString("static");
+        case MOTION_TYPE_DYNAMIC: return QString("dynamic");
+        case MOTION_TYPE_KINEMATIC: return QString("kinematic");
+    }
+    return QString("unknown");
+}
+
 enum MotionStateType {
     MOTIONSTATE_TYPE_INVALID,
     MOTIONSTATE_TYPE_ENTITY,

From f887bbd45c1a954a3f34cb29d430407541c507c3 Mon Sep 17 00:00:00 2001
From: EdgarPironti <pacepiro@hotmail.it>
Date: Fri, 30 Oct 2015 11:06:20 -0700
Subject: [PATCH 263/301] Fixed controllerExample parse error

---
 examples/example/avatarcontrol/controllerExample.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/example/avatarcontrol/controllerExample.js b/examples/example/avatarcontrol/controllerExample.js
index fe23ce0e8e..8d7996b02b 100644
--- a/examples/example/avatarcontrol/controllerExample.js
+++ b/examples/example/avatarcontrol/controllerExample.js
@@ -22,7 +22,7 @@ triggers[1] = Controller.Standard.RT;
 function checkController(deltaTime) {
     var triggerToggled = false;
 	for (var t = 0; t < NUMBER_OF_TRIGGERS; t++) {
-            var triggerValue = Controller.getValue(triggers[t]]);
+            var triggerValue = Controller.getValue(triggers[t]);
             if (triggerPulled[t]) {
                 // must release to at least 0.1
                 if (triggerValue < 0.1) {

From 393f6a4c763df19b220fe077179c2d1f66f5e956 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 30 Oct 2015 11:35:50 -0700
Subject: [PATCH 264/301] Fixing a bad field ID for keyLight.AmbientURL and
 bumping the domain version

---
 libraries/entities/src/EntityPropertyFlags.h   | 2 +-
 libraries/networking/src/udt/PacketHeaders.cpp | 2 +-
 libraries/networking/src/udt/PacketHeaders.h   | 1 +
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h
index 51a0c34c76..65060c8d45 100644
--- a/libraries/entities/src/EntityPropertyFlags.h
+++ b/libraries/entities/src/EntityPropertyFlags.h
@@ -189,7 +189,7 @@ enum EntityPropertyList {
     PROP_BACKGROUND_MODE = PROP_MODEL_URL,
     PROP_SKYBOX_COLOR = PROP_ANIMATION_URL,
     PROP_SKYBOX_URL = PROP_ANIMATION_FPS,
-    PROP_KEYLIGHT_AMBIENT_URL = PROP_ANIMATION_FRAME_INDEX,
+    PROP_KEYLIGHT_AMBIENT_URL = PROP_ANIMATION_PLAYING,
     
     // Aliases/Piggyback properties for Web. These properties intentionally reuse the enum values for
     // other properties which will never overlap with each other. 
diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp
index 7062942c51..a46a9693ac 100644
--- a/libraries/networking/src/udt/PacketHeaders.cpp
+++ b/libraries/networking/src/udt/PacketHeaders.cpp
@@ -38,7 +38,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
         case PacketType::EntityAdd:
         case PacketType::EntityEdit:
         case PacketType::EntityData:
-            return VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP;
+            return VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS;
         case PacketType::AvatarData:
         case PacketType::BulkAvatarData:
         default:
diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h
index 64e0a9d8e4..553c12f8e3 100644
--- a/libraries/networking/src/udt/PacketHeaders.h
+++ b/libraries/networking/src/udt/PacketHeaders.h
@@ -144,5 +144,6 @@ const PacketVersion VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER = 44;
 const PacketVersion VERSION_ENTITIES_PROTOCOL_CHANNELS = 45;
 const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46;
 const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47;
+const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48;
 
 #endif // hifi_PacketHeaders_h

From b102081f2f1dd0a0bc63c9f7d9c9972c7cb2eb38 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth@highfidelity.io>
Date: Fri, 30 Oct 2015 11:35:51 -0700
Subject: [PATCH 265/301] upon release, set velocity after returning entity to
 being dynamic

---
 examples/controllers/handControllerGrab.js | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 9ee9ed1e04..353e7b3daa 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -588,7 +588,8 @@ function MyController(hand, triggerAction) {
             relativePosition: this.offsetPosition,
             relativeRotation: this.offsetRotation,
             ttl: ACTION_TTL,
-            kinematic: NEAR_GRABBING_KINEMATIC
+            kinematic: NEAR_GRABBING_KINEMATIC,
+            kinematicSetVelocity: true
         });
         if (this.actionID === NULL_ACTION_ID) {
             this.actionID = null;
@@ -641,7 +642,8 @@ function MyController(hand, triggerAction) {
                 relativePosition: this.offsetPosition,
                 relativeRotation: this.offsetRotation,
                 ttl: ACTION_TTL,
-                kinematic: NEAR_GRABBING_KINEMATIC
+                kinematic: NEAR_GRABBING_KINEMATIC,
+                kinematicSetVelocity: true
             });
             this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
         }
@@ -810,12 +812,13 @@ function MyController(hand, triggerAction) {
             Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
         }
 
+        this.deactivateEntity(this.grabbedEntity);
+
         // the action will tend to quickly bring an object's velocity to zero.  now that
         // the action is gone, set the objects velocity to something the holder might expect.
         Entities.editEntity(this.grabbedEntity, {
             velocity: this.grabbedVelocity
         });
-        this.deactivateEntity(this.grabbedEntity);
 
         this.grabbedVelocity = ZERO_VEC;
         this.grabbedEntity = null;

From ce7fed2292cc4b81f975c4022cf7d57a3755367c Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 30 Oct 2015 13:16:31 -0700
Subject: [PATCH 266/301] fix json

---
 interface/resources/controllers/keyboardMouse.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
index 096cdb35d3..fbc1533fff 100644
--- a/interface/resources/controllers/keyboardMouse.json
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -38,7 +38,7 @@
 
         { "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
           "when": "Keyboard.RightMouseClick",
-          "to": "Actions.Yaw",
+          "to": "Actions.Yaw"
         },
 
         { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },

From f652e983a979daa9d4007f3e0ff2836563fa9779 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Fri, 30 Oct 2015 14:53:29 -0700
Subject: [PATCH 267/301] flag kinematic objs when changed in stepSimulation()

---
 interface/src/avatar/AvatarActionHold.cpp     |  3 +-
 libraries/physics/src/ObjectAction.cpp        |  1 -
 libraries/physics/src/ObjectAction.h          | 10 ++---
 libraries/physics/src/ObjectMotionState.cpp   | 10 ++---
 libraries/physics/src/ObjectMotionState.h     | 16 ++++---
 .../physics/src/ThreadSafeDynamicsWorld.cpp   | 43 +++++++++++++++----
 .../physics/src/ThreadSafeDynamicsWorld.h     |  9 ++--
 7 files changed, 62 insertions(+), 30 deletions(-)

diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp
index 59bfd88be6..e7d030e17a 100644
--- a/interface/src/avatar/AvatarActionHold.cpp
+++ b/interface/src/avatar/AvatarActionHold.cpp
@@ -119,8 +119,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
         worldTrans.setRotation(glmToBullet(_rotationalTarget));
         rigidBody->setWorldTransform(worldTrans);
 
-        ownerEntity->setPosition(_positionalTarget);
-        ownerEntity->setRotation(_rotationalTarget);
+        motionState->dirtyInternalKinematicChanges();
 
         _previousPositionalTarget = _positionalTarget;
         _previousRotationalTarget = _rotationalTarget;
diff --git a/libraries/physics/src/ObjectAction.cpp b/libraries/physics/src/ObjectAction.cpp
index d44ebc30b1..3188283f68 100644
--- a/libraries/physics/src/ObjectAction.cpp
+++ b/libraries/physics/src/ObjectAction.cpp
@@ -16,7 +16,6 @@
 ObjectAction::ObjectAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) :
     btActionInterface(),
     EntityActionInterface(type, id),
-    _active(false),
     _ownerEntity(ownerEntity) {
 }
 
diff --git a/libraries/physics/src/ObjectAction.h b/libraries/physics/src/ObjectAction.h
index fca446aec4..45b40a9fb3 100644
--- a/libraries/physics/src/ObjectAction.h
+++ b/libraries/physics/src/ObjectAction.h
@@ -50,6 +50,8 @@ public:
     virtual quint64 getExpires() { return _expires; }
 
 protected:
+    quint64 localTimeToServerTime(quint64 timeValue) const;
+    quint64 serverTimeToLocalTime(quint64 timeValue) const;
 
     virtual btRigidBody* getRigidBody();
     virtual glm::vec3 getPosition();
@@ -62,14 +64,10 @@ protected:
     virtual void setAngularVelocity(glm::vec3 angularVelocity);
     virtual void activateBody();
 
-    bool _active;
     EntityItemWeakPointer _ownerEntity;
-
-    quint64 _expires; // in seconds since epoch
     QString _tag;
-
-    quint64 localTimeToServerTime(quint64 timeValue) const;
-    quint64 serverTimeToLocalTime(quint64 timeValue) const;
+    quint64 _expires { 0 }; // in seconds since epoch
+    bool _active { false };
 
 private:
     int getEntityServerClockSkew() const;
diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp
index 4f3d0396c6..be0edafff5 100644
--- a/libraries/physics/src/ObjectMotionState.cpp
+++ b/libraries/physics/src/ObjectMotionState.cpp
@@ -20,17 +20,17 @@
 // origin of physics simulation in world-frame
 glm::vec3 _worldOffset(0.0f);
 
-// static 
+// static
 void ObjectMotionState::setWorldOffset(const glm::vec3& offset) {
     _worldOffset = offset;
 }
 
-// static 
+// static
 const glm::vec3& ObjectMotionState::getWorldOffset() {
     return _worldOffset;
 }
 
-// static 
+// static
 uint32_t worldSimulationStep = 0;
 void ObjectMotionState::setWorldSimulationStep(uint32_t step) {
     assert(step > worldSimulationStep);
@@ -41,7 +41,7 @@ uint32_t ObjectMotionState::getWorldSimulationStep() {
     return worldSimulationStep;
 }
 
-// static 
+// static
 ShapeManager* shapeManager = nullptr;
 void ObjectMotionState::setShapeManager(ShapeManager* manager) {
     assert(manager);
@@ -85,7 +85,7 @@ glm::vec3 ObjectMotionState::getBodyLinearVelocity() const {
 
 glm::vec3 ObjectMotionState::getBodyLinearVelocityGTSigma() const {
     // NOTE: the threshold to use here relates to the linear displacement threshold (dX) for sending updates
-    // to objects that are tracked server-side (e.g. entities which use dX = 2mm).  Hence an object moving 
+    // to objects that are tracked server-side (e.g. entities which use dX = 2mm).  Hence an object moving
     // just under this velocity threshold would trigger an update about V/dX times per second.
     const float MIN_LINEAR_SPEED_SQUARED = 0.0036f; // 6 mm/sec
 
diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h
index 22f0e9dcb0..992bdd11d7 100644
--- a/libraries/physics/src/ObjectMotionState.h
+++ b/libraries/physics/src/ObjectMotionState.h
@@ -44,12 +44,12 @@ enum MotionStateType {
     MOTIONSTATE_TYPE_AVATAR
 };
 
-// The update flags trigger two varieties of updates: "hard" which require the body to be pulled 
+// The update flags trigger two varieties of updates: "hard" which require the body to be pulled
 // and re-added to the physics engine and "easy" which just updates the body properties.
-const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_SHAPE | 
+const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_SHAPE |
                                                      Simulation::DIRTY_COLLISION_GROUP);
 const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES |
-                                                     Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL | 
+                                                     Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL |
                                                      Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATOR_OWNERSHIP);
 
 // These are the set of incoming flags that the PhysicsEngine needs to hear about:
@@ -66,7 +66,7 @@ class PhysicsEngine;
 class ObjectMotionState : public btMotionState {
 public:
     // These poroperties of the PhysicsEngine are "global" within the context of all ObjectMotionStates
-    // (assuming just one PhysicsEngine).  They are cached as statics for fast calculations in the 
+    // (assuming just one PhysicsEngine).  They are cached as statics for fast calculations in the
     // ObjectMotionState context.
     static void setWorldOffset(const glm::vec3& offset);
     static const glm::vec3& getWorldOffset();
@@ -121,7 +121,7 @@ public:
     virtual float getObjectFriction() const = 0;
     virtual float getObjectLinearDamping() const = 0;
     virtual float getObjectAngularDamping() const = 0;
-    
+
     virtual glm::vec3 getObjectPosition() const = 0;
     virtual glm::quat getObjectRotation() const = 0;
     virtual glm::vec3 getObjectLinearVelocity() const = 0;
@@ -140,6 +140,11 @@ public:
 
     bool isActive() const { return _body ? _body->isActive() : false; }
 
+    bool hasInternalKinematicChanges() const { return _hasInternalKinematicChanges; }
+
+    void dirtyInternalKinematicChanges() { _hasInternalKinematicChanges = true; }
+    void clearInternalKinematicChanges() { _hasInternalKinematicChanges = false; }
+
     friend class PhysicsEngine;
 
 protected:
@@ -160,6 +165,7 @@ protected:
     float _mass;
 
     uint32_t _lastKinematicStep;
+    bool _hasInternalKinematicChanges { false };
 };
 
 typedef QSet<ObjectMotionState*> SetOfMotionStates;
diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
index 94d6315705..c7dddb95c4 100644
--- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
+++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
@@ -4,8 +4,8 @@
  *
  * This software is provided 'as-is', without any express or implied warranty.
  * In no event will the authors be held liable for any damages arising from the use of this software.
- * Permission is granted to anyone to use this software for any purpose, 
- * including commercial applications, and to alter it and redistribute it freely, 
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it freely,
  * subject to the following restrictions:
  *
  * 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
@@ -75,7 +75,7 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep
         }
     }
 
-    // NOTE: We do NOT call synchronizeMotionState() after each substep (to avoid multiple locks on the
+    // NOTE: We do NOT call synchronizeMotionStates() after each substep (to avoid multiple locks on the
     // object data outside of the physics engine).  A consequence of this is that the transforms of the
     // external objects only ever update at the end of the full step.
 
@@ -87,6 +87,33 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep
     return subSteps;
 }
 
+// call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
+void ThreadSafeDynamicsWorld::synchronizeMotionState(btRigidBody* body) {
+    btAssert(body);
+    if (body->getMotionState() && !body->isStaticObject()) {
+        //we need to call the update at least once, even for sleeping objects
+        //otherwise the 'graphics' transform never updates properly
+        ///@todo: add 'dirty' flag
+        //if (body->getActivationState() != ISLAND_SLEEPING)
+        {
+            if (body->isKinematicObject()) {
+                ObjectMotionState* objectMotionState = static_cast<ObjectMotionState*>(body->getMotionState());
+                if (!objectMotionState->hasInternalKinematicChanges()) {
+                    return;
+                } else {
+                    objectMotionState->clearInternalKinematicChanges();
+                }
+            }
+            btTransform interpolatedTransform;
+            btTransformUtil::integrateTransform(body->getInterpolationWorldTransform(),
+                body->getInterpolationLinearVelocity(),body->getInterpolationAngularVelocity(),
+                (m_latencyMotionStateInterpolation && m_fixedTimeStep) ? m_localTime - m_fixedTimeStep : m_localTime*body->getHitFraction(),
+                interpolatedTransform);
+            body->getMotionState()->setWorldTransform(interpolatedTransform);
+        }
+    }
+}
+
 void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
     _changedMotionStates.clear();
     BT_PROFILE("synchronizeMotionStates");
@@ -97,22 +124,22 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
             btRigidBody* body = btRigidBody::upcast(colObj);
             if (body) {
                 if (body->getMotionState()) {
-                    synchronizeSingleMotionState(body);
+                    synchronizeMotionState(body);
                     _changedMotionStates.push_back(static_cast<ObjectMotionState*>(body->getMotionState()));
                 }
             }
         }
-    } else  {       
+    } else  {
         //iterate over all active rigid bodies
         for (int i=0;i<m_nonStaticRigidBodies.size();i++) {
             btRigidBody* body = m_nonStaticRigidBodies[i];
             if (body->isActive()) {
                 if (body->getMotionState()) {
-                    synchronizeSingleMotionState(body);
+                    synchronizeMotionState(body);
                     _changedMotionStates.push_back(static_cast<ObjectMotionState*>(body->getMotionState()));
                 }
             }
         }
-    }   
-}       
+    }
+}
 
diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h
index 26954832cf..de37554f56 100644
--- a/libraries/physics/src/ThreadSafeDynamicsWorld.h
+++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h
@@ -4,8 +4,8 @@
  *
  * This software is provided 'as-is', without any express or implied warranty.
  * In no event will the authors be held liable for any damages arising from the use of this software.
- * Permission is granted to anyone to use this software for any purpose, 
- * including commercial applications, and to alter it and redistribute it freely, 
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it freely,
  * subject to the following restrictions:
  *
  * 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
@@ -43,13 +43,16 @@ public:
     void synchronizeMotionStates();
 
     // btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated
-    // but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide 
+    // but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide
     // smoother rendering of objects when the physics simulation loop is ansynchronous to the render loop).
     float getLocalTimeAccumulation() const { return m_localTime; }
 
     VectorOfMotionStates& getChangedMotionStates() { return _changedMotionStates; }
 
 private:
+    // call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
+    void synchronizeMotionState(btRigidBody* body);
+
     VectorOfMotionStates _changedMotionStates;
 };
 

From 22324eb281f7b3f46f91fdbe06c04f0196976f13 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Fri, 30 Oct 2015 14:55:33 -0700
Subject: [PATCH 268/301] more tweaking of keyboard input routes

---
 .../resources/controllers/keyboardMouse.json   | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
index fbc1533fff..8af6b1dc98 100644
--- a/interface/resources/controllers/keyboardMouse.json
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -2,6 +2,15 @@
     "name": "Keyboard/Mouse to Actions",
     "channels": [
 
+        { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
+        { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
+        { "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
+        { "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" },
+        { "from": "Keyboard.E", "when": "Keyboard.Shift", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.05 } ] },
+        { "from": "Keyboard.C", "when": "Keyboard.Shift", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.05 } ] },
+        { "from": "Keyboard.S", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" },
+        { "from": "Keyboard.W", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" },
+
         
         { "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
           "when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseClick" ],
@@ -41,15 +50,6 @@
           "to": "Actions.Yaw"
         },
 
-        { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
-        { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
-        { "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
-        { "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" },
-        { "from": "Keyboard.E", "when": "Keyboard.Shift", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.05 } ] },
-        { "from": "Keyboard.C", "when": "Keyboard.Shift", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.05 } ] },
-        { "from": "Keyboard.S", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" },
-        { "from": "Keyboard.W", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" },
-
         { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
         { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
         { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },

From b8a2fcbb2c74dfac021108e244c423e83e888453 Mon Sep 17 00:00:00 2001
From: AlessandroSigna <alesigna92@gmail.com>
Date: Fri, 30 Oct 2015 15:21:48 -0700
Subject: [PATCH 269/301] Vive controller - fix inverted inputs

---
 .../input-plugins/src/input-plugins/ViveControllerManager.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index 69303bb079..e90006e014 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -254,7 +254,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
         }
             
         numTrackedControllers++;
-        bool left = numTrackedControllers == 1;
+        bool left = numTrackedControllers == 2;
             
         const mat4& mat = _trackedDevicePoseMat4[device];
                   
@@ -307,13 +307,13 @@ void ViveControllerManager::focusOutEvent() {
 // These functions do translation from the Steam IDs to the standard controller IDs
 void ViveControllerManager::handleAxisEvent(uint32_t axis, float x, float y, bool left) {
 #ifdef Q_OS_WIN
+    //FIX ME? It enters here every frame: probably we want to enter only if an event occurs
     axis += vr::k_EButton_Axis0;
     using namespace controller;
     if (axis == vr::k_EButton_SteamVR_Touchpad) {
         _axisStateMap[left ? LX : RX] = x;
         _axisStateMap[left ? LY : RY] = y;
     } else if (axis == vr::k_EButton_SteamVR_Trigger) {
-        //FIX ME: Seems that enters here everytime
         _axisStateMap[left ? LT : RT] = x;
     }
 #endif

From cf83ca22bbaa77a195268e49ff720096f61d5a15 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth@highfidelity.io>
Date: Fri, 30 Oct 2015 15:30:54 -0700
Subject: [PATCH 270/301] change how kinematic objects get data back to entity
 when an action is active

---
 examples/controllers/handControllerGrab.js    | 64 ++++++++++++++-----
 libraries/physics/src/EntityMotionState.cpp   |  3 +-
 .../physics/src/ThreadSafeDynamicsWorld.cpp   |  2 +
 3 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 353e7b3daa..10775a483f 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -80,6 +80,18 @@ var ACTION_TTL_REFRESH = 5;
 var PICKS_PER_SECOND_PER_HAND = 5;
 var MSECS_PER_SEC = 1000.0;
 
+
+var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
+var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
+
+var DEFAULT_GRABBABLE_DATA = {
+    grabbable: true,
+    invertSolidWhileHeld: false
+};
+
+var disabledHand ='none';
+
+
 // states for the state machine
 var STATE_OFF = 0;
 var STATE_SEARCHING = 1;
@@ -93,15 +105,35 @@ var STATE_FAR_GRABBING_NON_COLLIDING = 8;
 var STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING = 9;
 var STATE_RELEASE = 10;
 
-var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
-var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
 
-var DEFAULT_GRABBABLE_DATA = {
-    grabbable: true,
-    invertSolidWhileHeld: false
-};
+function stateToName(state) {
+    switch (state) {
+    case STATE_OFF:
+        return "off";
+    case STATE_SEARCHING:
+        return "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_GRABBING_NON_COLLIDING:
+        return "near_grabbing_non_colliding";
+    case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING:
+        return "continue_near_grabbing_non_colliding";
+    case STATE_FAR_GRABBING_NON_COLLIDING:
+        return "far_grabbing_non_colliding";
+    case STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING:
+        return "continue_far_grabbing_non_colliding";
+    case STATE_RELEASE:
+        return "release";
+    }
 
-var disabledHand ='none';
+    return "unknown";
+}
 
 function getTag() {
     return "grab-" + MyAvatar.sessionUUID;
@@ -196,7 +228,7 @@ function MyController(hand, triggerAction) {
 
     this.setState = function(newState) {
         if (WANT_DEBUG) {
-            print("STATE: " + this.state + " --> " + newState);
+            print("STATE: " + stateToName(this.state) + " --> " + newState + ", hand: " + this.hand);
         }
         this.state = newState;
     }
@@ -348,10 +380,11 @@ function MyController(hand, triggerAction) {
                 }
                 if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) {
                     // the hand is very close to the intersected object.  go into close-grabbing mode.
-                    if (intersection.properties.collisionsWillMove === 1) {
-                        this.setState(STATE_NEAR_GRABBING);
-                    } else {
+                    var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
+                    if (grabbableData.wantsTrigger) {
                         this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
+                    } else {
+                        this.setState(STATE_NEAR_GRABBING);
                     }
                 } else {
                     // don't allow two people to distance grab the same object
@@ -392,11 +425,11 @@ function MyController(hand, triggerAction) {
             }
             if (this.grabbedEntity === null) {
                 return;
-            } else if (props.locked === 0 && props.collisionsWillMove === 1) {
-                this.setState(STATE_NEAR_GRABBING);
-            } else if (props.collisionsWillMove === 0 && grabbableData.wantsTrigger) {
-                // We have grabbed a non-physical object, so we want to trigger a non-colliding event as opposed to a grab event
+            }
+            if (grabbableData.wantsTrigger) {
                 this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
+            } else if (props.locked === 0) {
+                this.setState(STATE_NEAR_GRABBING);
             }
         }
     };
@@ -816,6 +849,7 @@ function MyController(hand, triggerAction) {
 
         // the action will tend to quickly bring an object's velocity to zero.  now that
         // the action is gone, set the objects velocity to something the holder might expect.
+        print("release velocity is " + vec3toStr(this.grabbedVelocity));
         Entities.editEntity(this.grabbedEntity, {
             velocity: this.grabbedVelocity
         });
diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp
index 6832b8daff..42aaea33c2 100644
--- a/libraries/physics/src/EntityMotionState.cpp
+++ b/libraries/physics/src/EntityMotionState.cpp
@@ -146,7 +146,7 @@ MotionType EntityMotionState::computeObjectMotionType() const {
     if (_entity->getCollisionsWillMove()) {
         return MOTION_TYPE_DYNAMIC;
     }
-    return _entity->isMoving() ?  MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC;
+    return (_entity->isMoving() || _entity->hasActions()) ?  MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC;
 }
 
 bool EntityMotionState::isMoving() const {
@@ -184,6 +184,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
     if (!_entity) {
         return;
     }
+
     assert(entityTreeIsLocked());
     measureBodyAcceleration();
     _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
index c7dddb95c4..f725315330 100644
--- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
+++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
@@ -102,6 +102,8 @@ void ThreadSafeDynamicsWorld::synchronizeMotionState(btRigidBody* body) {
                     return;
                 } else {
                     objectMotionState->clearInternalKinematicChanges();
+                    body->getMotionState()->setWorldTransform(body->getWorldTransform());
+                    return;
                 }
             }
             btTransform interpolatedTransform;

From 085282db4f4cf1ed69ec4489c3906a3ab9f32bcf Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Fri, 30 Oct 2015 16:13:04 -0700
Subject: [PATCH 271/301] Crash fix for AvatarManager when iterating over
 _avatarHash

The main problem is that a null shared pointer was inserted into the _avatarHash
via the AvatarManager::getAvatarBySessionID().  When the sessionID is not present
in the _avatarHash, [QHash](http://doc.qt.io/qt-5/qhash.html#operator-5b-5d) will *insert*
an empty smart_ptr into the hash.
---
 interface/src/avatar/AvatarManager.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index fbfbbad2de..b0da8faeca 100644
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -366,5 +366,10 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID)
         return std::static_pointer_cast<Avatar>(_myAvatar);
     }
     QReadLocker locker(&_hashLock);
-    return _avatarHash[sessionID];
+    auto iter = _avatarHash.find(sessionID);
+    if (iter != _avatarHash.end()) {
+        return iter.value();
+    } else {
+        return AvatarSharedPointer();
+    }
 }

From 77e0023b43ddcfe6db2fd7b9852cba2b0977cdd2 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Fri, 30 Oct 2015 16:31:15 -0700
Subject: [PATCH 272/301] Fix lifetime bug with first PolyLine in InfiniteLine

---
 examples/libraries/line.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/libraries/line.js b/examples/libraries/line.js
index d31a34867b..c21bf2f3ad 100644
--- a/examples/libraries/line.js
+++ b/examples/libraries/line.js
@@ -102,7 +102,7 @@ InfiniteLine = function(position, color, lifetime) {
     this.position = position;
     this.color = color;
     this.lifetime = lifetime === undefined ? DEFAULT_LIFETIME : lifetime;
-    this.lines = [new PolyLine(position, color, 0.01)];
+    this.lines = [];
     this.size = 0;
 };
 

From 944f0965c059a1d9af6a30d8c18523d59c836cff Mon Sep 17 00:00:00 2001
From: Seth Alves <seth@highfidelity.io>
Date: Fri, 30 Oct 2015 16:35:50 -0700
Subject: [PATCH 273/301] some refactoring and a bug fix -- grab script can
 throw things again

---
 examples/controllers/handControllerGrab.js        | 8 +-------
 libraries/physics/src/PhysicsEngine.cpp           | 9 ++++++---
 libraries/physics/src/ThreadSafeDynamicsWorld.cpp | 6 ++----
 3 files changed, 9 insertions(+), 14 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 10775a483f..815f903bfa 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -15,13 +15,11 @@
 Script.include("../libraries/utils.js");
 
 
-////////////////////////////////////////////////////////////
 //
 // add lines where the hand ray picking is happening
 //
 var WANT_DEBUG = false;
 
-/////////////////////////////////////////////////////////////////
 //
 // these tune time-averaging and "on" value for analog trigger
 //
@@ -30,7 +28,6 @@ var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value
 var TRIGGER_ON_VALUE = 0.4;
 var TRIGGER_OFF_VALUE = 0.15;
 
-/////////////////////////////////////////////////////////////////
 //
 // distant manipulation
 //
@@ -44,7 +41,6 @@ var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000,z: 1000};
 var LINE_LENGTH = 500;
 var PICK_MAX_DISTANCE = 500; // max length of pick-ray
 
-/////////////////////////////////////////////////////////////////
 //
 // near grabbing
 //
@@ -57,7 +53,6 @@ var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
 var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object
 var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed
 
-/////////////////////////////////////////////////////////////////
 //
 // other constants
 //
@@ -228,7 +223,7 @@ function MyController(hand, triggerAction) {
 
     this.setState = function(newState) {
         if (WANT_DEBUG) {
-            print("STATE: " + stateToName(this.state) + " --> " + newState + ", hand: " + this.hand);
+            print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand);
         }
         this.state = newState;
     }
@@ -849,7 +844,6 @@ function MyController(hand, triggerAction) {
 
         // the action will tend to quickly bring an object's velocity to zero.  now that
         // the action is gone, set the objects velocity to something the holder might expect.
-        print("release velocity is " + vec3toStr(this.grabbedVelocity));
         Entities.editEntity(this.grabbedEntity, {
             velocity: this.grabbedVelocity
         });
diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp
index 1e652b75c4..f3ef855e50 100644
--- a/libraries/physics/src/PhysicsEngine.cpp
+++ b/libraries/physics/src/PhysicsEngine.cpp
@@ -82,12 +82,12 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
                 btCollisionShape* shape = motionState->getShape();
                 assert(shape);
                 body = new btRigidBody(mass, motionState, shape, inertia);
+                motionState->setRigidBody(body);
             } else {
                 body->setMassProps(mass, inertia);
             }
             body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
             body->updateInertiaTensor();
-            motionState->setRigidBody(body);
             motionState->updateBodyVelocities();
             const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f;  // 1 cm/sec
             const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f;  // ~1 deg/sec
@@ -101,12 +101,15 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
             shape->calculateLocalInertia(mass, inertia);
             if (!body) {
                 body = new btRigidBody(mass, motionState, shape, inertia);
+                motionState->setRigidBody(body);
             } else {
                 body->setMassProps(mass, inertia);
             }
+            body->setCollisionFlags(body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT |
+                                                                  btCollisionObject::CF_STATIC_OBJECT));
             body->updateInertiaTensor();
-            motionState->setRigidBody(body);
             motionState->updateBodyVelocities();
+
             // NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
             // (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
             const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f;  // 5 cm/sec
@@ -123,12 +126,12 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
             if (!body) {
                 assert(motionState->getShape());
                 body = new btRigidBody(mass, motionState, motionState->getShape(), inertia);
+                motionState->setRigidBody(body);
             } else {
                 body->setMassProps(mass, inertia);
             }
             body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
             body->updateInertiaTensor();
-            motionState->setRigidBody(body);
             break;
         }
     }
diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
index f725315330..d06a9b8e07 100644
--- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
+++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp
@@ -98,13 +98,11 @@ void ThreadSafeDynamicsWorld::synchronizeMotionState(btRigidBody* body) {
         {
             if (body->isKinematicObject()) {
                 ObjectMotionState* objectMotionState = static_cast<ObjectMotionState*>(body->getMotionState());
-                if (!objectMotionState->hasInternalKinematicChanges()) {
-                    return;
-                } else {
+                if (objectMotionState->hasInternalKinematicChanges()) {
                     objectMotionState->clearInternalKinematicChanges();
                     body->getMotionState()->setWorldTransform(body->getWorldTransform());
-                    return;
                 }
+                return;
             }
             btTransform interpolatedTransform;
             btTransformUtil::integrateTransform(body->getInterpolationWorldTransform(),

From f50e1a0977f92d28c5e117f80a2e7723e6acd8ae Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Fri, 30 Oct 2015 17:18:37 -0700
Subject: [PATCH 274/301] Fix for rare crash in
 LogHandler::flushRepeatedMessages()

This can happen when LogHandler::flushRepetedMessages is called on
the main thread, while the application is printing messages on
a separate thread.  The access to the _lastRepeatedMessage QHash was
not guarded.

I've added two mutexes to guard access to both the repeatedMessage
hashes/regexes and the onlyOnceMessages/regexes.  This will unfortunately
incur a performance hit for frequent debug logging, but that's better
then crashing.

Also, I've added the ability to print threadIDs as well as Process ids.
This is helpful when debugging multi-threaded access to shared variables.
---
 assignment-client/src/AssignmentClient.cpp    |  2 +-
 .../src/AssignmentClientMonitor.cpp           |  2 +-
 libraries/shared/src/LogHandler.cpp           | 66 ++++++++++++-------
 libraries/shared/src/LogHandler.h             | 26 ++++----
 4 files changed, 60 insertions(+), 36 deletions(-)

diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp
index f4f98114d0..bf5f9c3b7f 100644
--- a/assignment-client/src/AssignmentClient.cpp
+++ b/assignment-client/src/AssignmentClient.cpp
@@ -74,7 +74,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
     LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
 
     // make sure we output process IDs for a child AC otherwise it's insane to parse
-    LogHandler::getInstance().setShouldOutputPID(true);
+    LogHandler::getInstance().setShouldOutputProcessID(true);
 
     // setup our _requestAssignment member variable from the passed arguments
     _requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp
index 58cf3c49f3..7b3d5695e1 100644
--- a/assignment-client/src/AssignmentClientMonitor.cpp
+++ b/assignment-client/src/AssignmentClientMonitor.cpp
@@ -44,7 +44,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
     LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
 
     // make sure we output process IDs for a monitor otherwise it's insane to parse
-    LogHandler::getInstance().setShouldOutputPID(true);
+    LogHandler::getInstance().setShouldOutputProcessID(true);
 
     // create a NodeList so we can receive stats from children
     DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp
index cc3519e43e..0e05df277b 100644
--- a/libraries/shared/src/LogHandler.cpp
+++ b/libraries/shared/src/LogHandler.cpp
@@ -12,9 +12,10 @@
 
 #include <qcoreapplication.h>
 
-#include <qdatetime.h>
-#include <qdebug.h>
-#include <qtimer.h>
+#include <QDateTime>
+#include <QDebug>
+#include <QTimer>
+#include <QThread>
 
 #include "LogHandler.h"
 
@@ -24,13 +25,14 @@ LogHandler& LogHandler::getInstance() {
 }
 
 LogHandler::LogHandler() :
-    _shouldOutputPID(false)
+    _shouldOutputProcessID(false),
+    _shouldOutputThreadID(false)
 {
     // setup our timer to flush the verbose logs every 5 seconds
     QTimer* logFlushTimer = new QTimer(this);
     connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages);
     logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000);
-    
+
     // when the log handler is first setup we should print our timezone
     QString timezoneString = "Time zone: " + QDateTime::currentDateTime().toString("t");
     printf("%s\n", qPrintable(timezoneString));
@@ -57,51 +59,55 @@ const char* stringForLogType(LogMsgType msgType) {
 const QString DATE_STRING_FORMAT = "MM/dd hh:mm:ss";
 
 void LogHandler::flushRepeatedMessages() {
+    QMutexLocker locker(&_repeatedMessageLock);
     QHash<QString, int>::iterator message = _repeatMessageCountHash.begin();
     while (message != _repeatMessageCountHash.end()) {
-        
+
         if (message.value() > 0) {
             QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"")
             .arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key()));
-            
+
             QMessageLogContext emptyContext;
             printMessage(LogSuppressed, emptyContext, repeatMessage);
         }
-        
+
         _lastRepeatedMessage.remove(message.key());
         message = _repeatMessageCountHash.erase(message);
     }
 }
 
 QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) {
-    
+
     if (message.isEmpty()) {
         return QString();
     }
-    
+
     if (type == LogDebug) {
         // for debug messages, check if this matches any of our regexes for repeated log messages
+        QMutexLocker locker(&_repeatedMessageLock);
         foreach(const QString& regexString, getInstance()._repeatedMessageRegexes) {
             QRegExp repeatRegex(regexString);
             if (repeatRegex.indexIn(message) != -1) {
-                
+
                 if (!_repeatMessageCountHash.contains(regexString)) {
                     // we have a match but didn't have this yet - output the first one
                     _repeatMessageCountHash[regexString] = 0;
-                    
+
                     // break the foreach so we output the first match
                     break;
                 } else {
                     // we have a match - add 1 to the count of repeats for this message and set this as the last repeated message
                     _repeatMessageCountHash[regexString] += 1;
                     _lastRepeatedMessage[regexString] = message;
-                    
+
                     // return out, we're not printing this one
                     return QString();
                 }
             }
         }
-
+    }
+    if (type == LogDebug) {
+        QMutexLocker locker(&_onlyOnceMessageLock);
         // see if this message is one we should only print once
         foreach(const QString& regexString, getInstance()._onlyOnceMessageRegexes) {
             QRegExp onlyOnceRegex(regexString);
@@ -118,23 +124,27 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
             }
         }
     }
-    
+
     // log prefix is in the following format
-    // [TIMESTAMP] [DEBUG] [PID] [TARGET] logged string
-    
+    // [TIMESTAMP] [DEBUG] [PID] [TID] [TARGET] logged string
+
     QString prefixString = QString("[%1]").arg(QDateTime::currentDateTime().toString(DATE_STRING_FORMAT));
-    
+
     prefixString.append(QString(" [%1]").arg(stringForLogType(type)));
-    
-    if (_shouldOutputPID) {
+
+    if (_shouldOutputProcessID) {
         prefixString.append(QString(" [%1]").arg(QCoreApplication::instance()->applicationPid()));
-        
     }
-    
+
+    if (_shouldOutputThreadID) {
+        size_t threadID = (size_t)QThread::currentThreadId();
+        prefixString.append(QString(" [%1]").arg(threadID));
+    }
+
     if (!_targetName.isEmpty()) {
         prefixString.append(QString(" [%1]").arg(_targetName));
     }
-    
+
     QString logMessage = QString("%1 %2").arg(prefixString, message.split("\n").join("\n" + prefixString + " "));
     fprintf(stdout, "%s\n", qPrintable(logMessage));
     return logMessage;
@@ -143,3 +153,13 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
 void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
     getInstance().printMessage((LogMsgType) type, context, message);
 }
+
+const QString& LogHandler::addRepeatedMessageRegex(const QString& regexString) {
+    QMutexLocker locker(&_repeatedMessageLock);
+    return *_repeatedMessageRegexes.insert(regexString);
+}
+
+const QString& LogHandler::addOnlyOnceMessageRegex(const QString& regexString) {
+    QMutexLocker locker(&_onlyOnceMessageLock);
+    return *_onlyOnceMessageRegexes.insert(regexString);
+}
diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h
index 6af721f96c..fff6ca43d6 100644
--- a/libraries/shared/src/LogHandler.h
+++ b/libraries/shared/src/LogHandler.h
@@ -34,34 +34,38 @@ class LogHandler : public QObject {
     Q_OBJECT
 public:
     static LogHandler& getInstance();
-    
+
     /// sets the target name to output via the verboseMessageHandler, called once before logging begins
     /// \param targetName the desired target name to output in logs
     void setTargetName(const QString& targetName) { _targetName = targetName; }
-    
-    void setShouldOutputPID(bool shouldOutputPID) { _shouldOutputPID = shouldOutputPID; }
-    
+
+    void setShouldOutputProcessID(bool shouldOutputProcessID) { _shouldOutputProcessID = shouldOutputProcessID; }
+    void setShouldOutputThreadID(bool shouldOutputThreadID) { _shouldOutputThreadID = shouldOutputThreadID; }
+
     QString printMessage(LogMsgType type, const QMessageLogContext& context, const QString &message);
-    
+
     /// a qtMessageHandler that can be hooked up to a target that links to Qt
     /// prints various process, message type, and time information
     static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message);
-    
-    const QString& addRepeatedMessageRegex(const QString& regexString) { return *_repeatedMessageRegexes.insert(regexString); }
-    const QString& addOnlyOnceMessageRegex(const QString& regexString) { return *_onlyOnceMessageRegexes.insert(regexString); }
+
+    const QString& addRepeatedMessageRegex(const QString& regexString);
+    const QString& addOnlyOnceMessageRegex(const QString& regexString);
 private:
     LogHandler();
-    
+
     void flushRepeatedMessages();
-    
+
     QString _targetName;
-    bool _shouldOutputPID;
+    bool _shouldOutputProcessID;
+    bool _shouldOutputThreadID;
     QSet<QString> _repeatedMessageRegexes;
     QHash<QString, int> _repeatMessageCountHash;
     QHash<QString, QString> _lastRepeatedMessage;
+    QMutex _repeatedMessageLock;
 
     QSet<QString> _onlyOnceMessageRegexes;
     QHash<QString, int> _onlyOnceMessageCountHash;
+    QMutex _onlyOnceMessageLock;
 };
 
 #endif // hifi_LogHandler_h

From 2eb62f2fd89fb9c49107a72bdab9106dc00a8efa Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Fri, 30 Oct 2015 17:44:06 -0700
Subject: [PATCH 275/301] LogHandler: fix for linux build

---
 libraries/shared/src/LogHandler.cpp |  2 ++
 libraries/shared/src/LogHandler.h   | 10 +++++-----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp
index 0e05df277b..7dd1aceb3d 100644
--- a/libraries/shared/src/LogHandler.cpp
+++ b/libraries/shared/src/LogHandler.cpp
@@ -16,6 +16,8 @@
 #include <QDebug>
 #include <QTimer>
 #include <QThread>
+#include <QMutexLocker>
+#include <QRegExp>
 
 #include "LogHandler.h"
 
diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h
index fff6ca43d6..a74a6287d7 100644
--- a/libraries/shared/src/LogHandler.h
+++ b/libraries/shared/src/LogHandler.h
@@ -13,11 +13,11 @@
 #ifndef hifi_LogHandler_h
 #define hifi_LogHandler_h
 
-#include <qhash.h>
-#include <qobject.h>
-#include <qregexp.h>
-#include <qset.h>
-#include <qstring.h>
+#include <QHash>
+#include <QObject>
+#include <QSet>
+#include <QString>
+#include <QMutex>
 
 const int VERBOSE_LOG_INTERVAL_SECONDS = 5;
 

From 46d87dda5a8d4f77e74718da6e43cd635a153903 Mon Sep 17 00:00:00 2001
From: Bradley Austin Davis <bdavis@saintandreas.org>
Date: Fri, 30 Oct 2015 19:00:01 -0700
Subject: [PATCH 276/301] Fixing paths for SDL2 and Sixense libs

---
 cmake/externals/sdl2/CMakeLists.txt    | 42 ++++++++++++++++++--------
 cmake/externals/sixense/CMakeLists.txt | 12 ++++++++
 libraries/entities/CMakeLists.txt      |  2 +-
 libraries/procedural/CMakeLists.txt    |  2 +-
 4 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/cmake/externals/sdl2/CMakeLists.txt b/cmake/externals/sdl2/CMakeLists.txt
index 0f44f28610..abd436d571 100644
--- a/cmake/externals/sdl2/CMakeLists.txt
+++ b/cmake/externals/sdl2/CMakeLists.txt
@@ -2,6 +2,8 @@ set(EXTERNAL_NAME sdl2)
 
 include(ExternalProject)
 
+string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
+
 if (WIN32)
   ExternalProject_Add(
     ${EXTERNAL_NAME}
@@ -13,15 +15,33 @@ if (WIN32)
     LOG_DOWNLOAD 1
   )
 elseif (APPLE)
-  ExternalProject_Add(
-    ${EXTERNAL_NAME}
-    URL http://hifi-public.s3.amazonaws.com/dependencies/SDL2-2.0.3-OSX.tar.gz
-    URL_MD5 64f888886268bdf1656ef1b4b7d7756d
-    CONFIGURE_COMMAND ""
-    BUILD_COMMAND ""
-    INSTALL_COMMAND ""
-    LOG_DOWNLOAD 1
-  )
+
+    ExternalProject_Add(
+      ${EXTERNAL_NAME}
+      URL https://hifi-public.s3.amazonaws.com/dependencies/SDL2-2.0.3.zip
+      CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DVIDEO_OPENGL=OFF
+      BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
+      LOG_DOWNLOAD 1
+      LOG_CONFIGURE 1
+      LOG_BUILD 1
+    )
+
+    ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
+    set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include/SDL2 CACHE PATH "Location of SDL2 include directory")
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY "${INSTALL_DIR}/lib/libSDL2-2.0.dylib" CACHE STRING "Path to SDL2 library")
+
+    set(_SDL2_LIB_DIR "${INSTALL_DIR}/lib")
+
+    ExternalProject_Add_Step(
+      ${EXTERNAL_NAME}
+      change-install-name
+      COMMENT "Calling install_name_tool on SDL2 libraries to fix install name for dylib linking"
+      COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SDL2_LIB_DIR} -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
+      DEPENDEES install
+      WORKING_DIRECTORY <INSTALL_DIR>
+      LOG 1
+    )
+
 else ()
   if (ANDROID)
     set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
@@ -41,12 +61,8 @@ endif ()
 # Hide this external target (for ide users)
 set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
 
-string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
 
 if (APPLE)
-  ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
-  set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/SDL2.framework/Headers CACHE PATH "Location of SDL2 include directory")
-  set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/SDL2.framework/SDL2 CACHE STRING "Path to SDL2 library")
 elseif (WIN32)
   ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
   set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/include CACHE PATH "Location of SDL2 include directory")
diff --git a/cmake/externals/sixense/CMakeLists.txt b/cmake/externals/sixense/CMakeLists.txt
index 72de4a7e15..dea15485dc 100644
--- a/cmake/externals/sixense/CMakeLists.txt
+++ b/cmake/externals/sixense/CMakeLists.txt
@@ -37,6 +37,18 @@ elseif(APPLE)
 
     set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
 
+    set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64/release_dll")
+
+    ExternalProject_Add_Step(
+      ${EXTERNAL_NAME}
+      change-install-name-release
+      COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking"
+      COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR} -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
+      DEPENDEES install
+      WORKING_DIRECTORY <SOURCE_DIR>
+      LOG 1
+    )
+
 elseif(NOT ANDROID)
 
     # FIXME need to account for different architectures 
diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt
index f6b2e0e280..26e90f5d41 100644
--- a/libraries/entities/CMakeLists.txt
+++ b/libraries/entities/CMakeLists.txt
@@ -1,6 +1,6 @@
 set(TARGET_NAME entities)
 setup_hifi_library(Network Script)
-link_hifi_libraries(avatars shared octree gpu model fbx networking animation environment)
+link_hifi_libraries(avatars shared audio octree gpu model fbx networking animation environment)
 
 target_bullet()
 
diff --git a/libraries/procedural/CMakeLists.txt b/libraries/procedural/CMakeLists.txt
index 0483b8d3a8..37c4fbfbe8 100644
--- a/libraries/procedural/CMakeLists.txt
+++ b/libraries/procedural/CMakeLists.txt
@@ -1,5 +1,5 @@
 set(TARGET_NAME procedural)
 AUTOSCRIBE_SHADER_LIB(gpu model)
 setup_hifi_library()
-link_hifi_libraries(shared gpu model model-networking)
+link_hifi_libraries(shared gpu networking model model-networking)
 

From 9b9e35d3963e556842c243da6bd8a33f2f9a4a26 Mon Sep 17 00:00:00 2001
From: Bradley Austin Davis <bdavis@saintandreas.org>
Date: Fri, 30 Oct 2015 22:01:43 -0700
Subject: [PATCH 277/301] Limit sixense to mavericks and below

---
 cmake/externals/sixense/CMakeLists.txt        | 21 ++++++++++++++-----
 cmake/modules/FindSixense.cmake               |  4 ++++
 .../src/input-plugins/SixenseManager.cpp      |  8 +++++++
 3 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/cmake/externals/sixense/CMakeLists.txt b/cmake/externals/sixense/CMakeLists.txt
index dea15485dc..5edccb2c88 100644
--- a/cmake/externals/sixense/CMakeLists.txt
+++ b/cmake/externals/sixense/CMakeLists.txt
@@ -35,20 +35,31 @@ if (WIN32)
 
 elseif(APPLE)
 
-    set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
-
-    set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64/release_dll")
-
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/lib/osx_x64/debug_dll/libsixensed_x64.dylib CACHE TYPE INTERNAL)
+  
+    set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64")
     ExternalProject_Add_Step(
       ${EXTERNAL_NAME}
       change-install-name-release
       COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking"
-      COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR} -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
+      COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR}/release_dll -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
       DEPENDEES install
       WORKING_DIRECTORY <SOURCE_DIR>
       LOG 1
     )
 
+    set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64")
+    ExternalProject_Add_Step(
+      ${EXTERNAL_NAME}
+      change-install-name-debug
+      COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking"
+      COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR}/debug_dll -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
+      DEPENDEES install
+      WORKING_DIRECTORY <SOURCE_DIR>
+      LOG 1
+    )
+    
 elseif(NOT ANDROID)
 
     # FIXME need to account for different architectures 
diff --git a/cmake/modules/FindSixense.cmake b/cmake/modules/FindSixense.cmake
index 9abacac136..5a94d592d4 100644
--- a/cmake/modules/FindSixense.cmake
+++ b/cmake/modules/FindSixense.cmake
@@ -18,6 +18,10 @@
 #  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 # 
 
+include(SelectLibraryConfigurations)
+select_library_configurations(SIXENSE)
+
+set(SIXENSE_REQUIREMENTS SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
 mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 2527da9e03..6cb58ced82 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -12,6 +12,8 @@
 #include <vector>
 
 #include <QCoreApplication>
+#include <QtCore/QSysInfo>
+#include <QtGlobal>
 
 #include <GLMHelpers.h>
 #include <NumericalConstants.h>
@@ -74,7 +76,13 @@ SixenseManager::SixenseManager() :
 
 bool SixenseManager::isSupported() const {
 #ifdef HAVE_SIXENSE
+
+#if defined(Q_OS_OSX)
+    return QSysInfo::macVersion() <= QSysInfo::MV_MAVERICKS;
+#else
     return true;
+#endif
+    
 #else
     return false;
 #endif

From 0355a37fb147d8bc7b4dcc3a28129d4343edd3d8 Mon Sep 17 00:00:00 2001
From: Bradley Austin Davis <bdavis@saintandreas.org>
Date: Fri, 30 Oct 2015 22:19:44 -0700
Subject: [PATCH 278/301] Fixing SDL2 active/inactive value

---
 libraries/input-plugins/src/input-plugins/SDL2Manager.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
index 600dc5c56f..48864beedc 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
@@ -82,6 +82,7 @@ void SDL2Manager::activate() {
         emit joystickAdded(joystick.get());
     }
 #endif
+    InputPlugin::activate();
 }
 
 void SDL2Manager::deactivate() {
@@ -92,6 +93,7 @@ void SDL2Manager::deactivate() {
         emit joystickRemoved(joystick.get());
     }
 #endif
+    InputPlugin::deactivate();
 }
 
 

From aee03e79f390a6b60a474eedb9bcf4ecfd3a5e50 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 30 Oct 2015 22:37:00 -0700
Subject: [PATCH 279/301] Fix win32 and linux Sixense config

---
 cmake/externals/sixense/CMakeLists.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cmake/externals/sixense/CMakeLists.txt b/cmake/externals/sixense/CMakeLists.txt
index 5edccb2c88..07cf1c1163 100644
--- a/cmake/externals/sixense/CMakeLists.txt
+++ b/cmake/externals/sixense/CMakeLists.txt
@@ -30,7 +30,7 @@ if (WIN32)
         set(ARCH_SUFFIX "")
     endif()
     
-    set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${SOURCE_DIR}/lib/${ARCH_DIR}/VS2013/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL)
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE "${SOURCE_DIR}/lib/${ARCH_DIR}/VS2013/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL)
     add_paths_to_fixup_libs("${SOURCE_DIR}/bin/${ARCH_DIR}/VS2013/release_dll")
 
 elseif(APPLE)
@@ -63,7 +63,7 @@ elseif(APPLE)
 elseif(NOT ANDROID)
 
     # FIXME need to account for different architectures 
-    set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux_x64/release/libsixense_x64.so CACHE TYPE INTERNAL)
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/lib/linux_x64/release/libsixense_x64.so CACHE TYPE INTERNAL)
 
 endif()
 

From 224aeea04406d56ae901e14d7d1216c34ff592b6 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Sat, 31 Oct 2015 08:11:43 -0700
Subject: [PATCH 280/301] quiet compiler

---
 libraries/animation/src/AnimVariant.cpp                       | 2 +-
 libraries/controllers/src/controllers/UserInputMapper.cpp     | 4 ++--
 libraries/controllers/src/controllers/impl/Endpoint.h         | 3 ++-
 .../src/controllers/impl/conditionals/EndpointConditional.h   | 2 +-
 .../controllers/src/controllers/impl/endpoints/AnyEndpoint.h  | 1 +
 .../src/controllers/impl/endpoints/ArrayEndpoint.h            | 1 +
 .../src/controllers/impl/endpoints/CompositeEndpoint.h        | 1 +
 .../controllers/src/controllers/impl/endpoints/JSEndpoint.h   | 1 +
 .../src/controllers/impl/endpoints/ScriptEndpoint.h           | 1 +
 .../src/controllers/impl/endpoints/StandardEndpoint.h         | 2 +-
 10 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp
index 8d320195dd..234e9cef09 100644
--- a/libraries/animation/src/AnimVariant.cpp
+++ b/libraries/animation/src/AnimVariant.cpp
@@ -44,7 +44,7 @@ QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine,
                 break;
             default:
                 // Note that we don't do mat4 in Javascript currently, and there's not yet a reason to start now.
-                assert("AnimVariant::Type" == "valid");
+                assert(QString("AnimVariant::Type") == QString("valid"));
         }
     };
     if (useNames) { // copy only the requested names
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index d33e215797..8e121de7fb 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -74,7 +74,7 @@ void UserInputMapper::registerDevice(InputDevice::Pointer device) {
     }
     const auto& deviceID = device->_deviceID;
 
-    int numberOfType = recordDeviceOfType(device->getName());
+    recordDeviceOfType(device->getName());
 
     qCDebug(controllers) << "Registered input device <" << device->getName() << "> deviceID = " << deviceID;
     for (const auto& inputMapping : device->getAvailableInputs()) {
@@ -266,7 +266,7 @@ void UserInputMapper::update(float deltaTime) {
     }
 
     auto standardInputs = getStandardInputs();
-    if (_lastStandardStates.size() != standardInputs.size()) {
+    if ((int)_lastStandardStates.size() != standardInputs.size()) {
         _lastStandardStates.resize(standardInputs.size());
         for (auto& lastValue : _lastStandardStates) {
             lastValue = 0;
diff --git a/libraries/controllers/src/controllers/impl/Endpoint.h b/libraries/controllers/src/controllers/impl/Endpoint.h
index 5dd3f6adb4..bc604da2c5 100644
--- a/libraries/controllers/src/controllers/impl/Endpoint.h
+++ b/libraries/controllers/src/controllers/impl/Endpoint.h
@@ -40,7 +40,7 @@ namespace controller {
         virtual void apply(float value, const Pointer& source) = 0;
         virtual Pose pose() { return Pose(); }
         virtual void apply(const Pose& value, const Pointer& source) {}
-        virtual const bool isPose() { return _input.isPose(); }
+        virtual bool isPose() { return _input.isPose(); }
 
         virtual bool writeable() const { return true; }
         virtual bool readable() const { return true; }
@@ -54,6 +54,7 @@ namespace controller {
 
     class LambdaEndpoint : public Endpoint {
     public:
+        using Endpoint::apply;
         LambdaEndpoint(ReadLambda readLambda, WriteLambda writeLambda = [](float) {})
             : Endpoint(Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
 
diff --git a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
index 1e4205afc7..54ed57e871 100644
--- a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
+++ b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
@@ -18,7 +18,7 @@ namespace controller {
 class EndpointConditional : public Conditional {
 public:
     EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
-    virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
+    virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0f; }
 private:
     Endpoint::Pointer _endpoint;
 };
diff --git a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
index 86dd057414..24834ce223 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
@@ -17,6 +17,7 @@ namespace controller {
 class AnyEndpoint : public Endpoint {
     friend class UserInputMapper;
 public:
+    using Endpoint::apply;
     AnyEndpoint(Endpoint::List children);
     virtual float value() override;
     virtual void apply(float newValue, const Endpoint::Pointer& source) override;
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
index 79bb604ec0..899fa46de0 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
@@ -17,6 +17,7 @@ namespace controller {
 class ArrayEndpoint : public Endpoint {
     friend class UserInputMapper;
 public:
+    using Endpoint::apply;
     using Pointer = std::shared_ptr<ArrayEndpoint>;
     ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
 
diff --git a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
index c6ec90b7c8..b29266464c 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
@@ -15,6 +15,7 @@
 namespace controller {
     class CompositeEndpoint : public Endpoint, Endpoint::Pair {
     public:
+        using Endpoint::apply;
         CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second);
 
         virtual float value() override;
diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
index 27f17b5cd3..5113fef657 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
@@ -19,6 +19,7 @@ namespace controller {
 
 class JSEndpoint : public Endpoint {
 public:
+    using Endpoint::apply;
     JSEndpoint(const QJSValue& callable)
         : Endpoint(Input::INVALID_INPUT), _callable(callable) {
     }
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
index 23f77892c6..37160fcb48 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
@@ -19,6 +19,7 @@ namespace controller {
 class ScriptEndpoint : public Endpoint {
     Q_OBJECT;
 public:
+    using Endpoint::apply;
     ScriptEndpoint(const QScriptValue& callable)
         : Endpoint(Input::INVALID_INPUT), _callable(callable) {
     }
diff --git a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h
index 74adaf825d..7fe1a5467e 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h
@@ -32,7 +32,7 @@ public:
 
     virtual void apply(float value, const Pointer& source) override {
         // For standard endpoints, the first NON-ZERO write counts.
-        if (value != 0.0) {
+        if (value != 0.0f) {
             _written = true;
         }
         VirtualEndpoint::apply(value, source);

From 5916875345dcd51d16cfc484c5762295f40feac2 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Sat, 31 Oct 2015 08:20:24 -0700
Subject: [PATCH 281/301] one more

---
 .../controllers/src/controllers/impl/filters/InvertFilter.h      | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libraries/controllers/src/controllers/impl/filters/InvertFilter.h b/libraries/controllers/src/controllers/impl/filters/InvertFilter.h
index 889cd0140c..8acc9d56d6 100644
--- a/libraries/controllers/src/controllers/impl/filters/InvertFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/InvertFilter.h
@@ -17,6 +17,7 @@ namespace controller {
 class InvertFilter : public ScaleFilter {
     REGISTER_FILTER_CLASS(InvertFilter);
 public:
+    using ScaleFilter::parseParameters;
     InvertFilter() : ScaleFilter(-1.0f) {}
 
     virtual bool parseParameters(const QJsonArray& parameters) { return true; }

From b877f832a9d7175826ad581c0ca50abe044a5936 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 31 Oct 2015 13:02:17 -0700
Subject: [PATCH 282/301] fix SDL joysticks

---
 .../src/controllers/StandardControls.h        |  6 ++---
 .../src/input-plugins/SDL2Manager.cpp         | 27 +++++++++++++++++++
 2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h
index 9c6defb865..d5063f6034 100644
--- a/libraries/controllers/src/controllers/StandardControls.h
+++ b/libraries/controllers/src/controllers/StandardControls.h
@@ -58,15 +58,15 @@ namespace controller {
         // Left Analog stick
         LX = 0,
         LY,
-        LZ,
         // Right Analog stick
         RX,
         RY,
-        RZ,
         // Triggers
         LT,
         RT,
-        NUM_STANDARD_AXES
+        NUM_STANDARD_AXES,
+        LZ = LT,
+        RZ = RT
     };
 
     // No correlation to SDL
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
index 48864beedc..ec2fa2ed07 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
@@ -18,6 +18,33 @@
 
 #include "SDL2Manager.h"
 
+#ifdef HAVE_SDL2
+static_assert(
+    controller::A == SDL_CONTROLLER_BUTTON_A &&
+    controller::B == SDL_CONTROLLER_BUTTON_B &&
+    controller::X == SDL_CONTROLLER_BUTTON_X &&
+    controller::Y == SDL_CONTROLLER_BUTTON_Y &&
+    controller::BACK == SDL_CONTROLLER_BUTTON_BACK &&
+    controller::GUIDE == SDL_CONTROLLER_BUTTON_GUIDE &&
+    controller::START == SDL_CONTROLLER_BUTTON_START &&
+    controller::LS == SDL_CONTROLLER_BUTTON_LEFTSTICK &&
+    controller::RS == SDL_CONTROLLER_BUTTON_RIGHTSTICK &&
+    controller::LB == SDL_CONTROLLER_BUTTON_LEFTSHOULDER &&
+    controller::RB == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER &&
+    controller::DU == SDL_CONTROLLER_BUTTON_DPAD_UP &&
+    controller::DD == SDL_CONTROLLER_BUTTON_DPAD_DOWN &&
+    controller::DL == SDL_CONTROLLER_BUTTON_DPAD_LEFT &&
+    controller::DR == SDL_CONTROLLER_BUTTON_DPAD_RIGHT &&
+    controller::LX == SDL_CONTROLLER_AXIS_LEFTX &&
+    controller::LY == SDL_CONTROLLER_AXIS_LEFTY &&
+    controller::RX == SDL_CONTROLLER_AXIS_RIGHTX &&
+    controller::RY == SDL_CONTROLLER_AXIS_RIGHTY &&
+    controller::LT == SDL_CONTROLLER_AXIS_TRIGGERLEFT &&
+    controller::RT == SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
+    "SDL2 equvalence: Enums and values from StandardControls.h are assumed to match enums from SDL_gamecontroller.h");
+#endif
+
+
 const QString SDL2Manager::NAME = "SDL2";
 
 #ifdef HAVE_SDL2

From 46f9a432aba2778a0060ae2ba0935effc8e83bf2 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 31 Oct 2015 14:21:50 -0700
Subject: [PATCH 283/301] fix handControllerGrab.js

---
 examples/controllers/handControllerGrab.js | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 60e5286ad8..727e42cdc1 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -154,7 +154,7 @@ function entityIsGrabbedByOther(entityID) {
 }
 
 
-function MyController(hand, triggerAction) {
+function MyController(hand) {
     this.hand = hand;
     if (this.hand === RIGHT_HAND) {
         this.getHandPosition = MyAvatar.getRightPalmPosition;
@@ -166,7 +166,6 @@ function MyController(hand, triggerAction) {
 
     var SPATIAL_CONTROLLERS_PER_PALM = 2;
     var TIP_CONTROLLER_OFFSET = 1;
-    this.triggerAction = triggerAction;
     this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand;
     this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET;
 
@@ -282,7 +281,6 @@ function MyController(hand, triggerAction) {
         // smooth out trigger value
         this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
             (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO));
-
     };
 
     this.triggerSmoothedSqueezed = function() {
@@ -439,8 +437,7 @@ function MyController(hand, triggerAction) {
         var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
         var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
         var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation);
-        var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation",
-                                                                                  "gravity", "ignoreForCollisions",
+        var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]);
  
         var now = Date.now();
 
@@ -906,8 +903,8 @@ function MyController(hand, triggerAction) {
     };
 }
 
-var rightController = new MyController(RIGHT_HAND, Controller.Standard.RT);
-var leftController = new MyController(LEFT_HAND, Controller.Standard.LT);
+var rightController = new MyController(RIGHT_HAND);
+var leftController = new MyController(LEFT_HAND);
 
 var MAPPING_NAME = "com.highfidelity.handControllerGrab";
 

From abbfe153959cbe51db4b18b409903da7cfadc2f7 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 30 Oct 2015 14:34:18 -0700
Subject: [PATCH 284/301] Adding peek support for endpoints

---
 examples/controllers/handControllerGrab.js      |  4 ++--
 .../src/controllers/UserInputMapper.cpp         | 16 +++++++++-------
 .../src/controllers/UserInputMapper.h           |  8 ++++----
 .../controllers/src/controllers/impl/Endpoint.h | 15 ++++++++-------
 .../controllers/src/controllers/impl/Route.h    |  1 +
 .../src/controllers/impl/RouteBuilderProxy.cpp  |  5 +++++
 .../src/controllers/impl/RouteBuilderProxy.h    |  3 ++-
 .../impl/conditionals/EndpointConditional.h     |  2 +-
 .../controllers/impl/endpoints/ActionEndpoint.h |  4 ++--
 .../controllers/impl/endpoints/AnyEndpoint.cpp  | 11 +++++++++++
 .../controllers/impl/endpoints/AnyEndpoint.h    |  1 +
 .../controllers/impl/endpoints/ArrayEndpoint.h  |  4 +---
 .../impl/endpoints/CompositeEndpoint.cpp        |  6 ++++++
 .../impl/endpoints/CompositeEndpoint.h          |  1 +
 .../impl/endpoints/InputEndpoint.cpp            | 17 +++++++++++++----
 .../controllers/impl/endpoints/InputEndpoint.h  |  2 ++
 .../src/controllers/impl/endpoints/JSEndpoint.h |  5 ++---
 .../impl/endpoints/ScriptEndpoint.cpp           |  4 ++--
 .../controllers/impl/endpoints/ScriptEndpoint.h |  4 ++--
 19 files changed, 75 insertions(+), 38 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 727e42cdc1..a866983194 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -909,8 +909,8 @@ var leftController = new MyController(LEFT_HAND);
 var MAPPING_NAME = "com.highfidelity.handControllerGrab";
 
 var mapping = Controller.newMapping(MAPPING_NAME);
-mapping.from([Controller.Standard.RB, Controller.Standard.RT]).to(rightController.eitherTrigger);
-mapping.from([Controller.Standard.LB, Controller.Standard.LT]).to(leftController.eitherTrigger);
+mapping.from([Controller.Standard.RB, Controller.Standard.RT]).peek().to(rightController.eitherTrigger);
+mapping.from([Controller.Standard.LB, Controller.Standard.LT]).peek().to(leftController.eitherTrigger);
 Controller.enableMapping(MAPPING_NAME);
 
 
diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp
index 8e121de7fb..1a0fae8158 100755
--- a/libraries/controllers/src/controllers/UserInputMapper.cpp
+++ b/libraries/controllers/src/controllers/UserInputMapper.cpp
@@ -513,7 +513,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
     // and someone else wires it to CONTEXT_MENU, I don't want both to occur when 
     // I press the button.  The exception is if I'm wiring a control back to itself
     // in order to adjust my interface, like inverting the Y axis on an analog stick
-    if (!source->readable()) {
+    if (!route->peek && !source->readable()) {
         if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Source unreadable";
         }
@@ -539,7 +539,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
 
     // Fetch the value, may have been overriden by previous loopback routes
     if (source->isPose()) {
-        Pose value = getPose(source);
+        Pose value = getPose(source, route->peek);
         static const Pose IDENTITY_POSE { vec3(), quat() };
         if (debugRoutes && route->debug) {
             if (!value.valid) {
@@ -554,7 +554,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
         destination->apply(value, source);
     } else {
         // Fetch the value, may have been overriden by previous loopback routes
-        float value = getValue(source);
+        float value = getValue(source, route->peek);
 
         if (debugRoutes && route->debug) {
             qCDebug(controllers) << "Value was " << value;
@@ -691,8 +691,8 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
     }
 }
 
-float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) {
-    return endpoint->value();
+float UserInputMapper::getValue(const Endpoint::Pointer& endpoint, bool peek) {
+    return peek ? endpoint->peek() : endpoint->value();
 }
 
 float UserInputMapper::getValue(const Input& input) const {
@@ -704,11 +704,11 @@ float UserInputMapper::getValue(const Input& input) const {
     return endpoint->value();
 }
 
-Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) {
+Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint, bool peek) {
     if (!endpoint->isPose()) {
         return Pose();
     }
-    return endpoint->pose();
+    return peek ? endpoint->peekPose() : endpoint->pose();
 }
 
 Pose UserInputMapper::getPose(const Input& input) const {
@@ -742,6 +742,7 @@ static const QString JSON_NAME = QStringLiteral("name");
 static const QString JSON_CHANNELS = QStringLiteral("channels");
 static const QString JSON_CHANNEL_FROM = QStringLiteral("from");
 static const QString JSON_CHANNEL_DEBUG = QStringLiteral("debug");
+static const QString JSON_CHANNEL_PEEK = QStringLiteral("peek");
 static const QString JSON_CHANNEL_WHEN = QStringLiteral("when");
 static const QString JSON_CHANNEL_TO = QStringLiteral("to");
 static const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
@@ -953,6 +954,7 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
     result->json = QString(QJsonDocument(obj).toJson());
     result->source = parseSource(obj[JSON_CHANNEL_FROM]);
     result->debug = obj[JSON_CHANNEL_DEBUG].toBool();
+    result->debug = obj[JSON_CHANNEL_PEEK].toBool();
     if (!result->source) {
         qWarning() << "Invalid route source " << obj[JSON_CHANNEL_FROM];
         return Route::Pointer();
diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h
index 7684ecb7c5..c1dfcf5d33 100644
--- a/libraries/controllers/src/controllers/UserInputMapper.h
+++ b/libraries/controllers/src/controllers/UserInputMapper.h
@@ -38,8 +38,8 @@ namespace controller {
 
     class UserInputMapper : public QObject, public Dependency {
         Q_OBJECT
-            SINGLETON_DEPENDENCY
-            Q_ENUMS(Action)
+        SINGLETON_DEPENDENCY
+        Q_ENUMS(Action)
 
     public:
         // FIXME move to unordered set / map
@@ -135,8 +135,8 @@ namespace controller {
         int recordDeviceOfType(const QString& deviceName);
         QHash<const QString&, int> _deviceCounts;
 
-        static float getValue(const EndpointPointer& endpoint);
-        static Pose getPose(const EndpointPointer& endpoint);
+        static float getValue(const EndpointPointer& endpoint, bool peek = false);
+        static Pose getPose(const EndpointPointer& endpoint, bool peek = false);
 
         friend class RouteBuilderProxy;
         friend class MappingBuilderProxy;
diff --git a/libraries/controllers/src/controllers/impl/Endpoint.h b/libraries/controllers/src/controllers/impl/Endpoint.h
index bc604da2c5..475dc035bb 100644
--- a/libraries/controllers/src/controllers/impl/Endpoint.h
+++ b/libraries/controllers/src/controllers/impl/Endpoint.h
@@ -36,12 +36,13 @@ namespace controller {
         using WriteLambda = std::function<void(float)>;
 
         Endpoint(const Input& input) : _input(input) {}
-        virtual float value() = 0;
+        virtual float value() { return peek(); }
+        virtual float peek() const = 0;
         virtual void apply(float value, const Pointer& source) = 0;
-        virtual Pose pose() { return Pose(); }
+        virtual Pose peekPose() const { return Pose(); };
+        virtual Pose pose() { return peekPose(); }
         virtual void apply(const Pose& value, const Pointer& source) {}
-        virtual bool isPose() { return _input.isPose(); }
-
+        virtual bool isPose() const { return _input.isPose(); }
         virtual bool writeable() const { return true; }
         virtual bool readable() const { return true; }
         virtual void reset() { }
@@ -58,7 +59,7 @@ namespace controller {
         LambdaEndpoint(ReadLambda readLambda, WriteLambda writeLambda = [](float) {})
             : Endpoint(Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
 
-        virtual float value() override { return _readLambda(); }
+        virtual float peek() const override { return _readLambda(); }
         virtual void apply(float value, const Pointer& source) override { _writeLambda(value); }
 
     private:
@@ -73,10 +74,10 @@ namespace controller {
             : Endpoint(id) {
         }
 
-        virtual float value() override { return _currentValue; }
+        virtual float peek() const override { return _currentValue; }
         virtual void apply(float value, const Pointer& source) override { _currentValue = value; }
 
-        virtual Pose pose() override { return _currentPose; }
+        virtual Pose peekPose() const override { return _currentPose; }
         virtual void apply(const Pose& value, const Pointer& source) override {
             _currentPose = value;
         }
diff --git a/libraries/controllers/src/controllers/impl/Route.h b/libraries/controllers/src/controllers/impl/Route.h
index 5ad3d36628..554dd82d5a 100644
--- a/libraries/controllers/src/controllers/impl/Route.h
+++ b/libraries/controllers/src/controllers/impl/Route.h
@@ -26,6 +26,7 @@ namespace controller {
         Filter::List filters;
         QString json;
         bool debug { false };
+        bool peek { false };
 
         using Pointer = std::shared_ptr<Route>;
         using List = std::list<Pointer>;
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
index 49e615439d..5ae52893e0 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp
@@ -52,6 +52,11 @@ QObject* RouteBuilderProxy::debug(bool enable) {
     return this;
 }
 
+QObject* RouteBuilderProxy::peek(bool enable) {
+    _route->peek = enable;
+    return this;
+}
+
 QObject* RouteBuilderProxy::when(const QScriptValue& expression) {
     _route->conditional = _parent.conditionalFor(expression);
     return this;
diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
index d55aa80f6b..1c0ed6931d 100644
--- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
+++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
@@ -38,6 +38,7 @@ class RouteBuilderProxy : public QObject {
 
         Q_INVOKABLE void to(const QScriptValue& destination);
         Q_INVOKABLE QObject* debug(bool enable = true);
+        Q_INVOKABLE QObject* peek(bool enable = true);
         Q_INVOKABLE QObject* when(const QScriptValue& expression);
         Q_INVOKABLE QObject* clamp(float min, float max);
         Q_INVOKABLE QObject* hysteresis(float min, float max);
@@ -48,7 +49,7 @@ class RouteBuilderProxy : public QObject {
         Q_INVOKABLE QObject* constrainToInteger();
         Q_INVOKABLE QObject* constrainToPositiveInteger();
 
-private:
+    private:
         void to(const Endpoint::Pointer& destination);
         void conditional(const Conditional::Pointer& conditional);
         void addFilter(Filter::Pointer filter);
diff --git a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
index 54ed57e871..0ba1347087 100644
--- a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
+++ b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
@@ -18,7 +18,7 @@ namespace controller {
 class EndpointConditional : public Conditional {
 public:
     EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
-    virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0f; }
+    virtual bool satisfied() override { return _endpoint && _endpoint->peek() != 0.0f; }
 private:
     Endpoint::Pointer _endpoint;
 };
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h
index 574fdcedb5..e07dc9e4c8 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h
@@ -23,10 +23,10 @@ class ActionEndpoint : public Endpoint {
 public:
     ActionEndpoint(const Input& id = Input::INVALID_INPUT) : Endpoint(id) { }
 
-    virtual float value() override { return _currentValue; }
+    virtual float peek() const { return _currentValue; }
     virtual void apply(float newValue, const Pointer& source) override;
 
-    virtual Pose pose() override { return _currentPose; }
+    virtual Pose peekPose() const { return _currentPose; }
     virtual void apply(const Pose& value, const Pointer& source) override;
 
     virtual void reset() override;
diff --git a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
index 24f3479ea8..0dd53fe78f 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
@@ -27,6 +27,17 @@ AnyEndpoint::AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPU
     }
 }
 
+float AnyEndpoint::peek() const {
+    for (auto& child : _children) {
+        float childResult = child->peek();
+        if (childResult != 0.0f) {
+            return childResult;
+        }
+    }
+    return 0.0f;
+}
+
+// Fetching the value must trigger any necessary side effects of value() on ALL the children.
 float AnyEndpoint::value() {
     float result = 0;
     for (auto& child : _children) {
diff --git a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
index 24834ce223..8947eb675f 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.h
@@ -19,6 +19,7 @@ class AnyEndpoint : public Endpoint {
 public:
     using Endpoint::apply;
     AnyEndpoint(Endpoint::List children);
+    virtual float peek() const override;
     virtual float value() override;
     virtual void apply(float newValue, const Endpoint::Pointer& source) override;
     virtual bool writeable() const override;
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
index 899fa46de0..34d30a2e97 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.h
@@ -21,9 +21,7 @@ public:
     using Pointer = std::shared_ptr<ArrayEndpoint>;
     ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
 
-    virtual float value() override {
-        return 0.0;
-    }
+    virtual float peek() const override { return 0.0f; }
 
     virtual void apply(float value, const Endpoint::Pointer& source) override {
         for (auto& child : _children) {
diff --git a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
index 913bf0136b..1bd27489f8 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.cpp
@@ -24,6 +24,12 @@ bool CompositeEndpoint::readable() const {
     return first->readable() && second->readable();
 }
 
+float CompositeEndpoint::peek() const {
+    float result = first->peek() * -1.0f + second->peek();
+    return result;
+}
+
+// Fetching via value() must trigger any side effects of value() on the children
 float CompositeEndpoint::value() {
     float result = first->value() * -1.0f + second->value();
     return result;
diff --git a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
index b29266464c..3249aa1d37 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/CompositeEndpoint.h
@@ -18,6 +18,7 @@ namespace controller {
         using Endpoint::apply;
         CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second);
 
+        virtual float peek() const override;
         virtual float value() override;
         virtual void apply(float newValue, const Pointer& source) override;
         virtual bool readable() const override;
diff --git a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp
index bb1f6df191..ce58c948d1 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.cpp
@@ -13,10 +13,10 @@
 #include "../../UserInputMapper.h"
 
 using namespace controller;
-float InputEndpoint::value(){
-    _read = true;
+
+float InputEndpoint::peek() const {
     if (isPose()) {
-        return pose().valid ? 1.0f : 0.0f;
+        return peekPose().valid ? 1.0f : 0.0f;
     }
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     auto deviceProxy = userInputMapper->getDevice(_input);
@@ -26,8 +26,12 @@ float InputEndpoint::value(){
     return deviceProxy->getValue(_input);
 }
 
-Pose InputEndpoint::pose() {
+float InputEndpoint::value(){
     _read = true;
+    return peek();
+}
+
+Pose InputEndpoint::peekPose() const {
     if (!isPose()) {
         return Pose();
     }
@@ -39,3 +43,8 @@ Pose InputEndpoint::pose() {
     return deviceProxy->getPose(_input.channel);
 }
 
+Pose InputEndpoint::pose() {
+    _read = true;
+    return peekPose();
+}
+
diff --git a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h
index d58f0c2e73..663168bedc 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h
@@ -20,9 +20,11 @@ public:
         : Endpoint(id) {
     }
 
+    virtual float peek() const override;
     virtual float value() override;
     // FIXME need support for writing back to vibration / force feedback effects
     virtual void apply(float newValue, const Pointer& source) override {}
+    virtual Pose peekPose() const override;
     virtual Pose pose() override;
     virtual void apply(const Pose& value, const Pointer& source) override { }
 
diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
index 5113fef657..958914264e 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h
@@ -24,9 +24,8 @@ public:
         : Endpoint(Input::INVALID_INPUT), _callable(callable) {
     }
 
-    virtual float value() {
-        float result = (float)_callable.call().toNumber();
-        return result;
+    virtual float peek() const {
+        return (float)const_cast<JSEndpoint*>(this)->_callable.call().toNumber();
     }
 
     virtual void apply(float newValue, const Pointer& source) {
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
index d9b4a5fc59..bb9517b136 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp
@@ -12,8 +12,8 @@
 
 using namespace controller;
 
-float ScriptEndpoint::value() {
-    updateValue();
+float ScriptEndpoint::peek() const {
+    const_cast<ScriptEndpoint*>(this)->updateValue();
     return _lastValueRead;
 }
 
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
index 37160fcb48..836af721f6 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
+++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h
@@ -24,8 +24,8 @@ public:
         : Endpoint(Input::INVALID_INPUT), _callable(callable) {
     }
 
-    virtual float value();
-    virtual void apply(float newValue, const Pointer& source);
+    virtual float peek() const override;
+    virtual void apply(float newValue, const Pointer& source) override;
 
 protected:
     Q_INVOKABLE void updateValue();

From 0e13348b5a3f4874552097cff8f58a122be72676 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sat, 31 Oct 2015 13:24:26 -0700
Subject: [PATCH 285/301] PR feedback

---
 .../src/controllers/impl/endpoints/AnyEndpoint.cpp  | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
index 0dd53fe78f..a3b719b2c1 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/AnyEndpoint.cpp
@@ -28,23 +28,18 @@ AnyEndpoint::AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPU
 }
 
 float AnyEndpoint::peek() const {
+    float result = 0;
     for (auto& child : _children) {
-        float childResult = child->peek();
-        if (childResult != 0.0f) {
-            return childResult;
-        }
+        result = std::max(result, child->peek());
     }
-    return 0.0f;
+    return result;
 }
 
 // Fetching the value must trigger any necessary side effects of value() on ALL the children.
 float AnyEndpoint::value() {
     float result = 0;
     for (auto& child : _children) {
-        float childResult = child->value();
-        if (childResult != 0.0f) {
-            result = childResult;
-        }
+        result = std::max(result, child->value());
     }
     return result;
 }

From 9346366fc51e79cc1515ec63166ec0dc9f912824 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Sat, 31 Oct 2015 14:28:54 -0700
Subject: [PATCH 286/301] fix grab script

---
 examples/controllers/handControllerGrab.js | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js
index 727e42cdc1..339c1ad002 100644
--- a/examples/controllers/handControllerGrab.js
+++ b/examples/controllers/handControllerGrab.js
@@ -437,8 +437,9 @@ function MyController(hand) {
         var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
         var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
         var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation);
-        var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]);
- 
+        var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation",
+                                                                                  "gravity", "ignoreForCollisions",
+                                                                                  "collisionsWillMove"]);
         var now = Date.now();
 
         // add the action and initialize some variables

From 05dea847be1e2029157e6355fccf9df8794f0f7a Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 31 Oct 2015 15:47:40 -0700
Subject: [PATCH 287/301] add Actions.CycleCamera and wire up secondary thumb
 buttons to Actions.CycleCamera and Actions.ContextMenu

---
 interface/resources/controllers/standard.json |  3 +
 interface/src/Application.cpp                 | 32 ++++++++-
 interface/src/Application.h                   |  3 +-
 .../controllers/src/controllers/Actions.cpp   |  1 +
 .../controllers/src/controllers/Actions.h     |  1 +
 .../src/controllers/StandardController.cpp    | 36 ----------
 .../src/input-plugins/KeyboardMouseDevice.cpp | 69 -------------------
 .../src/input-plugins/SixenseManager.cpp      | 43 ------------
 8 files changed, 37 insertions(+), 151 deletions(-)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index 871374b85b..dff0ab95b0 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -25,6 +25,9 @@
         { "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" },
         { "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" },
 
+        { "from": "Standard.LeftSecondaryThumb", "to": "Actions.CycleCamera" }, 
+        { "from": "Standard.RightSecondaryThumb", "to": "Actions.ContextMenu" },
+
         { "from": "Standard.LT", "to": "Actions.LeftHandClick" }, 
         { "from": "Standard.RT", "to": "Actions.RightHandClick" },
 
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 7f4b5a3c3d..dc2eee000d 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -630,8 +630,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     // Setup the userInputMapper with the actions
     auto userInputMapper = DependencyManager::get<UserInputMapper>();
     connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
-        if (state && action == toInt(controller::Action::TOGGLE_MUTE)) {
-            DependencyManager::get<AudioClient>()->toggleMute();
+        if (state) {
+            if (action == controller::toInt(controller::Action::TOGGLE_MUTE)) {
+                DependencyManager::get<AudioClient>()->toggleMute();
+            } else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
+                cycleCamera();
+            }
         }
     });
 
@@ -2620,6 +2624,30 @@ void Application::updateThreads(float deltaTime) {
     }
 }
 
+void Application::cycleCamera() {
+    auto menu = Menu::getInstance();
+    if (menu->isOptionChecked(MenuOption::FullscreenMirror)) {
+
+        menu->setIsOptionChecked(MenuOption::FullscreenMirror, false);
+        menu->setIsOptionChecked(MenuOption::FirstPerson, true);
+
+    } else if (menu->isOptionChecked(MenuOption::FirstPerson)) {
+
+        menu->setIsOptionChecked(MenuOption::FirstPerson, false);
+        menu->setIsOptionChecked(MenuOption::ThirdPerson, true);
+
+    } else if (menu->isOptionChecked(MenuOption::ThirdPerson)) {
+
+        menu->setIsOptionChecked(MenuOption::ThirdPerson, false);
+        menu->setIsOptionChecked(MenuOption::FullscreenMirror, true);
+
+    } else if (menu->isOptionChecked(MenuOption::IndependentMode)) {
+        // do nothing if in independe mode
+        return;
+    }
+    cameraMenuChanged(); // handle the menu change
+}
+
 void Application::cameraMenuChanged() {
     if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
         if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
diff --git a/interface/src/Application.h b/interface/src/Application.h
index bf45a0c6ec..dfc904e0ef 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -293,8 +293,9 @@ public slots:
     void aboutApp();
     void showEditEntitiesHelp();
 
+    void cycleCamera();
     void cameraMenuChanged();
-    
+
     void reloadResourceCaches();
 
     void crashApplication();
diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp
index a4a8656fb7..701aea79c5 100644
--- a/libraries/controllers/src/controllers/Actions.cpp
+++ b/libraries/controllers/src/controllers/Actions.cpp
@@ -60,6 +60,7 @@ namespace controller {
             makeButtonPair(Action::ACTION2, "SecondaryAction"),
             makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"),
             makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"),
+            makeButtonPair(Action::CYCLE_CAMERA, "CycleCamera"),
 
             // Aliases and bisected versions
             makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),
diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h
index 36df695032..d5ad44c720 100644
--- a/libraries/controllers/src/controllers/Actions.h
+++ b/libraries/controllers/src/controllers/Actions.h
@@ -51,6 +51,7 @@ enum class Action {
 
     CONTEXT_MENU,
     TOGGLE_MUTE,
+    CYCLE_CAMERA,
 
     SHIFT,
 
diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp
index 44f1bff1ae..31c023b1ea 100644
--- a/libraries/controllers/src/controllers/StandardController.cpp
+++ b/libraries/controllers/src/controllers/StandardController.cpp
@@ -118,41 +118,5 @@ QString StandardController::getDefaultMappingConfig() const {
     return DEFAULT_MAPPING_JSON;
 }
 
-// FIXME figure out how to move the shifted version to JSON
-//void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
-//    const float JOYSTICK_MOVE_SPEED = 1.0f;
-//    const float DPAD_MOVE_SPEED = 0.5f;
-//    const float JOYSTICK_YAW_SPEED = 0.5f;
-//    const float JOYSTICK_PITCH_SPEED = 0.25f;
-//    const float BOOM_SPEED = 0.1f;
-//
-//    // Hold front right shoulder button for precision controls
-//    // Left Joystick: Movement, strafing
-//    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
-//    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
-//
-//    // Right Joystick: Camera orientation
-//    mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
-//    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
-//
-//    // Dpad movement
-//    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-//    mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-//    mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-//    mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-//
-//    // Button controls
-//    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-//    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
-//
-//    // Zoom
-//    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
-//    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
-//
-//    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
-//
-//    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
-//    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A));
-//}
 
 }
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
index a0481dfaa0..9cd510c521 100755
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
@@ -209,72 +209,3 @@ QString KeyboardMouseDevice::getDefaultMappingConfig() const {
     return MAPPING_JSON;
 }
 
-//void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) {
-//    const float BUTTON_MOVE_SPEED = 1.0f;
-//    const float BUTTON_YAW_SPEED = 0.75f;
-//    const float BUTTON_PITCH_SPEED = 0.5f;
-//    const float MOUSE_YAW_SPEED = 0.5f;
-//    const float MOUSE_PITCH_SPEED = 0.25f;
-//    const float TOUCH_YAW_SPEED = 0.5f;
-//    const float TOUCH_PITCH_SPEED = 0.25f;
-//    const float BUTTON_BOOM_SPEED = 0.1f;
-// 
-//    // AWSD keys mapping
-//
-//    mapper.addInputChannel(controller::BOOM_IN, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
-//    mapper.addInputChannel(controller::BOOM_OUT, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
-//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
-//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
-//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
-//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
-//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
-//    mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
-//
-//    // Arrow keys mapping
-//    mapper.addInputChannel(controller::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED);
-//    mapper.addInputChannel(controller::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED);
-//    mapper.addInputChannel(controller::YAW_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED);
-//    mapper.addInputChannel(controller::YAW_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED);
-//    mapper.addInputChannel(controller::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED);
-//    mapper.addInputChannel(controller::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED);
-//
-//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
-//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
-//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
-//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
-//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
-//    mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
-//
-//    // Mouse move
-//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
-//    mapper.addInputChannel(controller::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
-//    mapper.addInputChannel(controller::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
-//    mapper.addInputChannel(controller::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
-//
-//    
-//#ifdef Q_OS_MAC
-//    // wheel event modifier on Mac collide with the touchpad scroll event
-//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
-//    mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
-//    mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
-//    mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
-//#else
-//    // Touch pad yaw pitch
-//    mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
-//    mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
-//    mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
-//    mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
-//    
-//    // Wheel move
-//    mapper.addInputChannel(controller::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED);
-//    mapper.addInputChannel(controller::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED);
-//    mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED);
-//    mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED);
-//
-//#endif
-//    
-//    mapper.addInputChannel(controller::SHIFT, makeInput(Qt::Key_Space));
-//    mapper.addInputChannel(controller::ACTION1, makeInput(Qt::Key_R));
-//    mapper.addInputChannel(controller::ACTION2, makeInput(Qt::Key_T));
-//}
-
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 6cb58ced82..5e0f3277b1 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -556,49 +556,6 @@ QString SixenseManager::getDefaultMappingConfig() const {
     return MAPPING_JSON;
 }
 
-//
-//void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
-//    const float JOYSTICK_MOVE_SPEED = 1.0f;
-//    const float JOYSTICK_YAW_SPEED = 0.5f;
-//    const float JOYSTICK_PITCH_SPEED = 0.25f;
-//    const float BUTTON_MOVE_SPEED = 1.0f;
-//    const float BOOM_SPEED = 0.1f;
-//    using namespace controller;
-//
-//    // Left Joystick: Movement, strafing
-//    mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(LY), JOYSTICK_MOVE_SPEED);
-//    mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(LX), JOYSTICK_MOVE_SPEED);
-//
-//    // Right Joystick: Camera orientation
-//    mapper.addInputChannel(UserInputMapper::YAW, makeInput(RX), JOYSTICK_YAW_SPEED);
-//    mapper.addInputChannel(UserInputMapper::PITCH, makeInput(RY), JOYSTICK_PITCH_SPEED);
-//
-//    // Buttons
-//    mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(L3), BOOM_SPEED);
-//    mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(L1), BOOM_SPEED);
-//
-//    mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(R3), BUTTON_MOVE_SPEED);
-//    mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(R1), BUTTON_MOVE_SPEED);
-//
-//    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(L2));
-//    mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(R2));
-//
-//    mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(L4));
-//    mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(R4));
-//
-//    // FIXME
-////    mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
-////    mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
-//
-//    mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(LT));
-//    mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(RT));
-//
-//    // TODO find a mechanism to allow users to navigate the context menu via
-//    mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(L0));
-//    mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(R0));
-//
-//}
-
 // virtual
 void SixenseManager::saveSettings() const {
     Settings settings;

From 77816d818a096b3d331b857b602a3074e22cd453 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sat, 31 Oct 2015 16:00:22 -0700
Subject: [PATCH 288/301] make RY map to jump

---
 interface/resources/controllers/standard.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index dff0ab95b0..b08abcbaad 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -16,7 +16,7 @@
 
 
         { "from": "Standard.RX", "to": "Actions.Yaw" },
-        { "from": "Standard.RY", "to": "Actions.Pitch" },
+        { "from": "Standard.RY", "filters": "invert", "to": "Actions.TranslateY" }, 
 
 
         { "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },

From 7fa6fb13085793560eca7b153aacf63e4b4e0f68 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 1 Nov 2015 01:36:12 -0700
Subject: [PATCH 289/301] Remove GLEW spam in cmake

---
 cmake/modules/FindGLEW.cmake | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/cmake/modules/FindGLEW.cmake b/cmake/modules/FindGLEW.cmake
index 4f22271e3e..f4eca0eddf 100644
--- a/cmake/modules/FindGLEW.cmake
+++ b/cmake/modules/FindGLEW.cmake
@@ -30,6 +30,4 @@ include(SelectLibraryConfigurations)
 select_library_configurations(GLEW)
 
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
-
-message(STATUS "Found GLEW - Assuming that GLEW is static and defining GLEW_STATIC")
\ No newline at end of file
+find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
\ No newline at end of file

From 99d8554cc8050fa29ba73205155e7d455f0d2458 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 1 Nov 2015 01:36:54 -0700
Subject: [PATCH 290/301] Make zlib a true external on windows (linux and OSX
 should rely on system libraries)

---
 cmake/externals/zlib/CMakeLists.txt | 49 +++++++++++++++--------------
 cmake/macros/TargetZlib.cmake       | 17 ++++++++++
 libraries/shared/CMakeLists.txt     | 12 +------
 3 files changed, 44 insertions(+), 34 deletions(-)
 create mode 100644 cmake/macros/TargetZlib.cmake

diff --git a/cmake/externals/zlib/CMakeLists.txt b/cmake/externals/zlib/CMakeLists.txt
index 69dbca714d..0d279cc469 100644
--- a/cmake/externals/zlib/CMakeLists.txt
+++ b/cmake/externals/zlib/CMakeLists.txt
@@ -1,28 +1,31 @@
+set(EXTERNAL_NAME zlib)
+string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
 
-if (WIN32)
-  set(EXTERNAL_NAME zlib)
-  string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
+include(ExternalProject)
 
-  include(ExternalProject)
-  ExternalProject_Add(
-    ${EXTERNAL_NAME}
-    URL http://zlib.net/zlib128.zip
-    URL_MD5 126f8676442ffbd97884eb4d6f32afb4
-    INSTALL_COMMAND ""
-    LOG_DOWNLOAD 1
-  )
+ExternalProject_Add(
+${EXTERNAL_NAME}
+URL http://zlib.net/zlib128.zip
+CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
+LOG_DOWNLOAD 1
+LOG_CONFIGURE 1
+LOG_BUILD 1
+)
+  
+# Hide this external target (for ide users)
+set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
 
-  # Hide this external target (for ide users)
-  set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
+ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
+set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include CACHE PATH "List of zlib include directories")
+set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIR} CACHE PATH "List of zlib include directories")
+set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${INSTALL_DIR}/bin CACHE FILEPATH "Location of ZLib DLL")
+set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/zlib.lib CACHE FILEPATH "Location of zlib release library")
+set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/zlibd.lib CACHE FILEPATH "Location of zlib debug library")
 
-  ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
+include(SelectLibraryConfigurations)
+select_library_configurations(${EXTERNAL_NAME_UPPER})
 
-  set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of zlib include directories")
-
-  ExternalProject_Get_Property(${EXTERNAL_NAME} BINARY_DIR)
-
-  set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${BINARY_DIR}/Release CACHE FILEPATH "Location of GLEW DLL")
-  set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${BINARY_DIR}/Release/zlib.lib CACHE FILEPATH "Location of ZLib release library")
-  set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of ZLib debug library")
-
-endif ()
\ No newline at end of file
+# Force selected libraries into the cache
+set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE FILEPATH "Location of zlib libraries")
+set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of zlib libraries") 
diff --git a/cmake/macros/TargetZlib.cmake b/cmake/macros/TargetZlib.cmake
new file mode 100644
index 0000000000..11eb8c132e
--- /dev/null
+++ b/cmake/macros/TargetZlib.cmake
@@ -0,0 +1,17 @@
+# 
+#  Copyright 2015 High Fidelity, Inc.
+#  Created by Bradley Austin Davis on 2015/10/10
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+# 
+macro(TARGET_ZLIB)
+    if (WIN32)
+        add_dependency_external_projects(zlib)
+        add_paths_to_fixup_libs(${ZLIB_DLL_PATH})
+    else()
+        find_package(ZLIB REQUIRED)
+    endif()
+    target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${ZLIB_INCLUDE_DIRS})
+    target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
+endmacro()
diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt
index d9df5eba7f..2691c51128 100644
--- a/libraries/shared/CMakeLists.txt
+++ b/libraries/shared/CMakeLists.txt
@@ -3,14 +3,4 @@ set(TARGET_NAME shared)
 # TODO: there isn't really a good reason to have Script linked here - let's get what is requiring it out (RegisteredMetaTypes.cpp)
 setup_hifi_library(Gui Network Script Widgets)
 
-find_package(ZLIB REQUIRED)
-target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
-target_include_directories(${TARGET_NAME} PUBLIC ${ZLIB_INCLUDE_DIRS})
-
-if (WIN32)
-  # Birarda will fix this when he finds it.
-  get_filename_component(ZLIB_LIB_DIR "${ZLIB_LIBRARIES}" DIRECTORY)
-  get_filename_component(ZLIB_DIR "${ZLIB_LIB_DIR}" DIRECTORY)
-  set(ZLIB_BIN_DIR "${ZLIB_DIR}/bin")
-  add_paths_to_fixup_libs(${ZLIB_BIN_DIR})
-endif ()
+target_zlib()

From cad1d28b7bee0af3474c06cea1ae1fed4e750af7 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 1 Nov 2015 01:49:33 -0700
Subject: [PATCH 291/301] Updating build notes

---
 BUILD.md     |  6 +-----
 BUILD_WIN.md | 10 ----------
 2 files changed, 1 insertion(+), 15 deletions(-)

diff --git a/BUILD.md b/BUILD.md
index e2f310bb1f..7ad2ddeee0 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -13,17 +13,13 @@
 * [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
 * [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4
 * [gverb](https://github.com/highfidelity/gverb)
-
-The following external projects are optional dependencies. You can indicate to CMake that you would like to include them by passing -DGET_$NAME=1 when running a clean CMake build. For example, to get CMake to download and compile SDL2 you would pass -DGET_SDL2=1.
-
 * [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3
-  * Enables game controller support in Interface
 
 The above dependencies will be downloaded, built, linked and included automatically by CMake where we require them. The CMakeLists files that handle grabbing each of the following external dependencies can be found in the [cmake/externals folder](cmake/externals). The resulting downloads, source files and binaries will be placed in the `build/ext` folder in each of the subfolders for each external project. 
 
 These are not placed in your normal build tree when doing an out of source build so that they do not need to be re-downloaded and re-compiled every time the CMake build folder is cleared. Should you want to force a re-download and re-compile of a specific external, you can simply remove that directory from the appropriate subfolder in `build/ext`. Should you want to force a re-download and re-compile of all externals, just remove the `build/ext` folder.
 
-If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DGET_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
+If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE_LOCAL_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
 
 ###OS Specific Build Guides
 * [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X.
diff --git a/BUILD_WIN.md b/BUILD_WIN.md
index d291cef4f2..89646e99ff 100644
--- a/BUILD_WIN.md
+++ b/BUILD_WIN.md
@@ -75,16 +75,6 @@ To prevent these problems, install OpenSSL yourself. Download the following bina
 
 Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
 
-####zlib
-
-Install zlib from
-
-  [Zlib for Windows](http://gnuwin32.sourceforge.net/packages/zlib.htm)
-
-and fix a header file, as described here:
-
-  [zlib zconf.h bug](http://sourceforge.net/p/gnuwin32/bugs/169/)
-
 ###Build High Fidelity using Visual Studio
 Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.
 

From e899229cdeb0f78d274ad4b83c91585b778d37c1 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sun, 1 Nov 2015 09:55:30 -0800
Subject: [PATCH 292/301] tweaks to how VrMenu is shown

---
 interface/resources/controllers/keyboardMouse.json | 3 ++-
 interface/src/Application.cpp                      | 6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
index 8af6b1dc98..9c3ba79d76 100644
--- a/interface/resources/controllers/keyboardMouse.json
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -81,6 +81,7 @@
 
         { "from": "Keyboard.Space", "to": "Actions.SHIFT" },
         { "from": "Keyboard.R", "to": "Actions.ACTION1" },
-        { "from": "Keyboard.T", "to": "Actions.ACTION2" }
+        { "from": "Keyboard.T", "to": "Actions.ACTION2" },
+        { "from": "Keyboard.RightMouseClick", "to": "Actions.ContextMenu" }
     ]
 }
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index dc2eee000d..22f61a12e0 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -635,6 +635,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
                 DependencyManager::get<AudioClient>()->toggleMute();
             } else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
                 cycleCamera();
+            } else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
+                VrMenu::toggle(); // show context menu even on non-stereo displays
             }
         }
     });
@@ -1789,9 +1791,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
 
 void Application::keyReleaseEvent(QKeyEvent* event) {
     if (event->key() == Qt::Key_Alt && _altPressed && hasFocus()) {
-        if (getActiveDisplayPlugin()->isStereo()) {
-            VrMenu::toggle();
-        }
+        VrMenu::toggle(); // show context menu even on non-stereo displays
     }
 
     _keysPressed.remove(event->key());

From cfb2fd1523c8c7ce027a720c4c5abe157fa788ef Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Tue, 27 Oct 2015 11:52:47 -0700
Subject: [PATCH 293/301] Support for runtime plugins (DLLs)

---
 CMakeLists.txt                                |   1 +
 cmake/externals/glew/CMakeLists.txt           |   5 +-
 cmake/macros/SetupHifiPlugin.cmake            |  33 +++++
 interface/src/Application.cpp                 |   1 -
 interface/src/PluginContainerProxy.cpp        |   1 -
 libraries/display-plugins/CMakeLists.txt      |   7 +-
 .../AbstractHMDScriptingInterface.cpp         |   5 +-
 .../Basic2DWindowOpenGLDisplayPlugin.cpp      |  22 +--
 .../src/display-plugins/DisplayPlugin.cpp     |  12 --
 .../src/display-plugins/DisplayPlugin.h       | 131 +---------------
 .../src/display-plugins/NullDisplayPlugin.cpp |   2 +-
 .../src/display-plugins/NullDisplayPlugin.h   |   2 +-
 .../display-plugins/OpenGLDisplayPlugin.cpp   |   1 +
 .../WindowOpenGLDisplayPlugin.cpp             |   2 +-
 .../openvr/OpenVrDisplayPlugin.cpp            |   4 +-
 .../stereo/StereoDisplayPlugin.cpp            |  10 +-
 .../src/input-plugins/InputPlugin.h           |  12 +-
 .../src/input-plugins/SixenseManager.cpp      |  10 +-
 .../input-plugins/ViveControllerManager.cpp   |   8 +-
 libraries/plugins/src/plugins/DisplayPlugin.h | 140 ++++++++++++++++++
 libraries/plugins/src/plugins/Forward.h       |   1 +
 libraries/plugins/src/plugins/InputPlugin.h   |  23 +++
 libraries/plugins/src/plugins/Plugin.cpp      |   4 +-
 libraries/plugins/src/plugins/Plugin.h        |   6 +-
 .../plugins/src/plugins/PluginManager.cpp     |  73 ++++++++-
 libraries/plugins/src/plugins/PluginManager.h |   1 +
 libraries/plugins/src/plugins/RuntimePlugin.h |  36 +++++
 plugins/CMakeLists.txt                        |  18 +++
 plugins/oculus/CMakeLists.txt                 |  22 +++
 .../oculus/src}/OculusBaseDisplayPlugin.cpp   |   8 +
 .../oculus/src}/OculusBaseDisplayPlugin.h     |   3 +-
 .../oculus/src}/OculusDebugDisplayPlugin.cpp  |   0
 .../oculus/src}/OculusDebugDisplayPlugin.h    |   0
 .../oculus/src}/OculusDisplayPlugin.cpp       |  13 +-
 .../oculus/src}/OculusDisplayPlugin.h         |   0
 .../oculus/src}/OculusHelpers.cpp             |   0
 .../oculus/src}/OculusHelpers.h               |   0
 plugins/oculus/src/OculusProvider.cpp         |  54 +++++++
 plugins/oculus/src/oculus.json                |   1 +
 plugins/oculusLegacy/CMakeLists.txt           |  22 +++
 plugins/oculusLegacy/src/OculusHelpers.cpp    |   9 ++
 plugins/oculusLegacy/src/OculusHelpers.h      |  85 +++++++++++
 .../src}/OculusLegacyDisplayPlugin.cpp        |  34 +----
 .../src}/OculusLegacyDisplayPlugin.h          |   2 +-
 plugins/oculusLegacy/src/OculusProvider.cpp   |  45 ++++++
 plugins/oculusLegacy/src/oculus.json          |   1 +
 tests/controllers/src/main.cpp                |   3 -
 47 files changed, 631 insertions(+), 242 deletions(-)
 create mode 100644 cmake/macros/SetupHifiPlugin.cmake
 create mode 100644 libraries/plugins/src/plugins/DisplayPlugin.h
 create mode 100644 libraries/plugins/src/plugins/InputPlugin.h
 create mode 100644 libraries/plugins/src/plugins/RuntimePlugin.h
 create mode 100644 plugins/CMakeLists.txt
 create mode 100644 plugins/oculus/CMakeLists.txt
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusBaseDisplayPlugin.cpp (95%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusBaseDisplayPlugin.h (96%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusDebugDisplayPlugin.cpp (100%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusDebugDisplayPlugin.h (100%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusDisplayPlugin.cpp (97%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusDisplayPlugin.h (100%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusHelpers.cpp (100%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusHelpers.h (100%)
 create mode 100644 plugins/oculus/src/OculusProvider.cpp
 create mode 100644 plugins/oculus/src/oculus.json
 create mode 100644 plugins/oculusLegacy/CMakeLists.txt
 create mode 100644 plugins/oculusLegacy/src/OculusHelpers.cpp
 create mode 100644 plugins/oculusLegacy/src/OculusHelpers.h
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculusLegacy/src}/OculusLegacyDisplayPlugin.cpp (90%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculusLegacy/src}/OculusLegacyDisplayPlugin.h (97%)
 create mode 100644 plugins/oculusLegacy/src/OculusProvider.cpp
 create mode 100644 plugins/oculusLegacy/src/oculus.json

diff --git a/CMakeLists.txt b/CMakeLists.txt
index efe99b550b..d1c69e4f6b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -203,6 +203,7 @@ if (NOT ANDROID)
   add_subdirectory(interface)
   set_target_properties(interface PROPERTIES FOLDER "Apps")
   add_subdirectory(tests)
+  add_subdirectory(plugins)
   add_subdirectory(tools)
 endif ()
 
diff --git a/cmake/externals/glew/CMakeLists.txt b/cmake/externals/glew/CMakeLists.txt
index 5f59cc2377..0a4a0abe71 100644
--- a/cmake/externals/glew/CMakeLists.txt
+++ b/cmake/externals/glew/CMakeLists.txt
@@ -7,14 +7,15 @@ endif ()
 include(ExternalProject)
 ExternalProject_Add(
   ${EXTERNAL_NAME}
-  URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple.zip
-  URL_MD5 0507dc08337a82a5e7ecbc5417f92cc1
+  URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple2.zip
+  URL_MD5 f05d858e8203c32b689da208ad8b39db
   CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
   LOG_DOWNLOAD 1
   LOG_CONFIGURE 1
   LOG_BUILD 1
 )
 
+
 # Hide this external target (for ide users)
 set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
 
diff --git a/cmake/macros/SetupHifiPlugin.cmake b/cmake/macros/SetupHifiPlugin.cmake
new file mode 100644
index 0000000000..0ee94c7816
--- /dev/null
+++ b/cmake/macros/SetupHifiPlugin.cmake
@@ -0,0 +1,33 @@
+#
+#  Created by Bradley Austin Davis on 2015/10/25
+#  Copyright 2015 High Fidelity, Inc.
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
+#
+macro(SETUP_HIFI_PLUGIN)
+    set(${TARGET_NAME}_SHARED 1)
+    setup_hifi_library(${ARGV})
+    add_dependencies(interface ${TARGET_NAME})
+    set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Plugins")
+    
+    if (APPLE) 
+        set(PLUGIN_PATH "interface.app/Contents/MacOS/plugins")
+    else()
+        set(PLUGIN_PATH "plugins")
+    endif()
+    
+    # create the destination for the plugin binaries
+    add_custom_command(
+        TARGET ${TARGET_NAME} POST_BUILD
+        COMMAND "${CMAKE_COMMAND}" -E make_directory
+        "${CMAKE_BINARY_DIR}/interface/$<CONFIGURATION>/${PLUGIN_PATH}/"
+    )
+    
+    add_custom_command(TARGET ${DIR} POST_BUILD
+        COMMAND "${CMAKE_COMMAND}" -E copy
+        "$<TARGET_FILE:${TARGET_NAME}>"
+        "${CMAKE_BINARY_DIR}/interface/$<CONFIGURATION>/${PLUGIN_PATH}/"
+    )
+
+endmacro()
\ No newline at end of file
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index dc2eee000d..653f9cf906 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -392,7 +392,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     _entityClipboard->createRootElement();
 
     _pluginContainer = new PluginContainerProxy();
-    Plugin::setContainer(_pluginContainer);
 #ifdef Q_OS_WIN
     installNativeEventFilter(&MyNativeEventFilter::getInstance());
 #endif
diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp
index 079d6d0bea..2e5c883897 100644
--- a/interface/src/PluginContainerProxy.cpp
+++ b/interface/src/PluginContainerProxy.cpp
@@ -13,7 +13,6 @@
 #include "ui/DialogsManager.h"
 
 PluginContainerProxy::PluginContainerProxy() {
-    Plugin::setContainer(this);
 }
 
 PluginContainerProxy::~PluginContainerProxy() {
diff --git a/libraries/display-plugins/CMakeLists.txt b/libraries/display-plugins/CMakeLists.txt
index 14aa03de44..fad244fa5f 100644
--- a/libraries/display-plugins/CMakeLists.txt
+++ b/libraries/display-plugins/CMakeLists.txt
@@ -1,6 +1,6 @@
 set(TARGET_NAME display-plugins)
 setup_hifi_library(OpenGL)
-link_hifi_libraries(shared plugins gpu gl)
+link_hifi_libraries(shared plugins gl)
 
 target_opengl()
 
@@ -8,11 +8,6 @@ GroupSources("src/display-plugins")
 
 target_oglplus()
 
-add_dependency_external_projects(LibOVR)
-find_package(LibOVR REQUIRED)
-target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
-target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
-
 if (WIN32)
   add_dependency_external_projects(OpenVR)
   find_package(OpenVR REQUIRED)
diff --git a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp
index 9987ae345c..4b8d957e5f 100644
--- a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp
+++ b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp
@@ -12,7 +12,6 @@
 
 #include "DisplayPlugin.h"
 #include <plugins/PluginContainer.h>
-#include <OVR_CAPI_Keys.h>
 
 static Setting::Handle<float> IPD_SCALE_HANDLE("hmd.ipdScale", 1.0f);
 
@@ -26,12 +25,12 @@ float AbstractHMDScriptingInterface::getIPD() const {
 
 float AbstractHMDScriptingInterface::getEyeHeight() const {
     // FIXME update the display plugin interface to expose per-plugin settings
-    return OVR_DEFAULT_EYE_HEIGHT;
+    return getPlayerHeight() - 0.10f;
 }
 
 float AbstractHMDScriptingInterface::getPlayerHeight() const {
     // FIXME update the display plugin interface to expose per-plugin settings
-    return OVR_DEFAULT_PLAYER_HEIGHT;
+    return 1.755f;
 }
 
 float AbstractHMDScriptingInterface::getIPDScale() const {
diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
index 914d30d58a..9366ec4403 100644
--- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
@@ -35,36 +35,36 @@ QAction* _vsyncAction{ nullptr };
 
 void Basic2DWindowOpenGLDisplayPlugin::activate() {
     _framerateActions.clear();
-    CONTAINER->addMenuItem(MENU_PATH(), FULLSCREEN,
+    _container->addMenuItem(MENU_PATH(), FULLSCREEN,
         [this](bool clicked) {
             if (clicked) {
-                CONTAINER->setFullscreen(getFullscreenTarget());
+                _container->setFullscreen(getFullscreenTarget());
             } else {
-                CONTAINER->unsetFullscreen();
+                _container->unsetFullscreen();
             }
         }, true, false);
-    CONTAINER->addMenu(FRAMERATE);
+    _container->addMenu(FRAMERATE);
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED,
             [this](bool) { updateFramerate(); }, true, true, FRAMERATE));
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_60,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_60,
             [this](bool) { updateFramerate(); }, true, false, FRAMERATE));
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_50,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_50,
             [this](bool) { updateFramerate(); }, true, false, FRAMERATE));
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_40,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_40,
             [this](bool) { updateFramerate(); }, true, false, FRAMERATE));
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_30,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_30,
             [this](bool) { updateFramerate(); }, true, false, FRAMERATE));
 
     WindowOpenGLDisplayPlugin::activate();
 
     // Vsync detection happens in the parent class activate, so we need to check after that
     if (_vsyncSupported) {
-        _vsyncAction = CONTAINER->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true);
+        _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true);
     } else {
         _vsyncAction = nullptr;
     }
@@ -107,7 +107,7 @@ int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const {
 bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
     static const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Menu.h
 
-    bool shouldThrottle = (!CONTAINER->isForeground() && CONTAINER->isOptionChecked(ThrottleFPSIfNotFocus));
+    bool shouldThrottle = (!_container->isForeground() && _container->isOptionChecked(ThrottleFPSIfNotFocus));
     
     if (_isThrottled != shouldThrottle) {
         _isThrottled = shouldThrottle;
diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp
index 4af45d299b..8155d69826 100644
--- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp
@@ -15,9 +15,6 @@
 #include "Basic2DWindowOpenGLDisplayPlugin.h"
 
 #include "openvr/OpenVrDisplayPlugin.h"
-#include "oculus/OculusDisplayPlugin.h"
-#include "oculus/OculusDebugDisplayPlugin.h"
-#include "oculus/OculusLegacyDisplayPlugin.h"
 
 const QString& DisplayPlugin::MENU_PATH() {
     static const QString value = "Display";
@@ -40,15 +37,6 @@ DisplayPluginList getDisplayPlugins() {
         new InterleavedStereoDisplayPlugin(),
 
         // HMDs
-
-        // Windows Oculus SDK
-        new OculusDisplayPlugin(),
-        // Windows Oculus Simulator... uses head tracking and the same rendering 
-        // as the connected hardware, but without using the SDK to display to the 
-        // Rift.  Useful for debugging Rift performance with nSight.
-        new OculusDebugDisplayPlugin(),
-        // Mac/Linux Oculus SDK (0.5)
-        new OculusLegacyDisplayPlugin(),
 #ifdef Q_OS_WIN
         // SteamVR SDK
         new OpenVrDisplayPlugin(),
diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h
index b2176e0bd1..84c6592c53 100644
--- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h
@@ -5,135 +5,6 @@
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
-#pragma once
 
-#include "plugins/Plugin.h"
-#include <QSize>
-#include <QPoint>
-#include <functional>
-
-#include <gl/Config.h>
-#include <GLMHelpers.h>
-
-#include <glm/glm.hpp>
-#include <glm/gtc/quaternion.hpp>
-#include <RegisteredMetaTypes.h>
-
-enum Eye {
-    Left,
-    Right,
-    Mono
-};
-
-/*
- * Helper method to iterate over each eye
- */
-template <typename F>
-void for_each_eye(F f) {
-    f(Left);
-    f(Right);
-}
-
-/*
- * Helper method to iterate over each eye, with an additional lambda to take action between the eyes
- */
-template <typename F, typename FF>
-void for_each_eye(F f, FF ff) {
-    f(Eye::Left);
-    ff();
-    f(Eye::Right);
-}
-
-class QWindow;
-
-#define AVERAGE_HUMAN_IPD 0.064f
-
-class DisplayPlugin : public Plugin {
-    Q_OBJECT
-public:
-    virtual bool isHmd() const { return false; }
-    virtual int getHmdScreen() const { return -1; }
-    /// By default, all HMDs are stereo
-    virtual bool isStereo() const { return isHmd(); }
-    virtual bool isThrottled() const { return false; }
-
-    // Rendering support
-
-    // Stop requesting renders, but don't do full deactivation
-    // needed to work around the issues caused by Oculus 
-    // processing messages in the middle of submitFrame
-    virtual void stop() = 0;
-
-    /**
-     *  Called by the application before the frame rendering.  Can be used for
-     *  render timing related calls (for instance, the Oculus begin frame timing
-     *  call)
-     */
-    virtual void preRender() = 0;
-    /**
-     *  Called by the application immediately before calling the display function.
-     *  For OpenGL based plugins, this is the best place to put activate the output
-     *  OpenGL context
-     */
-    virtual void preDisplay() = 0;
-
-    /**
-     *  Sends the scene texture to the display plugin.
-     */
-    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) = 0;
-
-    /**
-     *  Called by the application immeidately after display.  For OpenGL based
-     *  displays, this is the best place to put the buffer swap
-     */
-    virtual void finishFrame() = 0;
-
-    // Does the rendering surface have current focus?
-    virtual bool hasFocus() const = 0;
-
-    // The size of the rendering target (may be larger than the device size due to distortion)
-    virtual glm::uvec2 getRecommendedRenderSize() const = 0;
-
-    // The size of the UI
-    virtual glm::uvec2 getRecommendedUiSize() const {
-        return getRecommendedRenderSize();
-    }
-
-    // By default the aspect ratio is just the render size
-    virtual float getRecommendedAspectRatio() const {
-        return aspect(getRecommendedRenderSize());
-    }
-
-    // Stereo specific methods
-    virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const {
-        return baseProjection;
-    }
-
-    // HMD specific methods
-    // TODO move these into another class?
-    virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
-        static const glm::mat4 transform; return transform;
-    }
-
-    virtual glm::mat4 getHeadPose() const {
-        static const glm::mat4 pose; return pose;
-    }
-
-    // Needed for timewarp style features
-    virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) {
-        // NOOP
-    }
-
-    virtual float getIPD() const { return AVERAGE_HUMAN_IPD; }
-
-    virtual void abandonCalibration() {}
-    virtual void resetSensors() {}
-    virtual float devicePixelRatio() { return 1.0;  }
-
-
-    static const QString& MENU_PATH();
-signals:
-    void recommendedFramebufferSizeChanged(const QSize & size);
-    void requestRender();
-};
+#include <plugins/DisplayPlugin.h>
 
diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
index 914f80d983..ce512962ff 100644
--- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
@@ -25,6 +25,6 @@ bool NullDisplayPlugin::hasFocus() const {
 
 void NullDisplayPlugin::preRender() {}
 void NullDisplayPlugin::preDisplay() {}
-void NullDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) {}
+void NullDisplayPlugin::display(uint32_t sceneTexture, const glm::uvec2& sceneSize) {}
 void NullDisplayPlugin::finishFrame() {}
 void NullDisplayPlugin::stop() {}
diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
index 4f2cc77b8f..8cd5c2bc37 100644
--- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
@@ -21,7 +21,7 @@ public:
     virtual bool hasFocus() const override;
     virtual void preRender() override;
     virtual void preDisplay() override;
-    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
+    virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
     virtual void finishFrame() override;
 
 private:
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
index 3791375c9e..3ef882fe76 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
@@ -9,6 +9,7 @@
 #include <QOpenGLContext>
 #include <QCoreApplication>
 
+#include <gl/Config.h>
 #include <gl/GlWindow.h>
 #include <GLMHelpers.h>
 
diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp
index ffea6605af..6ddc791503 100644
--- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp
@@ -42,7 +42,7 @@ bool WindowOpenGLDisplayPlugin::hasFocus() const {
 
 void WindowOpenGLDisplayPlugin::activate() {
     OpenGLDisplayPlugin::activate();
-    _window = CONTAINER->getPrimarySurface();
+    _window = _container->getPrimarySurface();
     _window->makeCurrent();
     customizeContext();
     _window->doneCurrent();
diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp
index 245fd11ef7..174bf1bf36 100644
--- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp
@@ -89,7 +89,7 @@ bool OpenVrDisplayPlugin::isSupported() const {
 }
 
 void OpenVrDisplayPlugin::activate() {
-    CONTAINER->setIsOptionChecked(StandingHMDSensorMode, true);
+    _container->setIsOptionChecked(StandingHMDSensorMode, true);
 
     hmdRefCount++;
     vr::HmdError eError = vr::HmdError_None;
@@ -132,7 +132,7 @@ void OpenVrDisplayPlugin::activate() {
 }
 
 void OpenVrDisplayPlugin::deactivate() {
-    CONTAINER->setIsOptionChecked(StandingHMDSensorMode, false);
+    _container->setIsOptionChecked(StandingHMDSensorMode, false);
 
     hmdRefCount--;
 
diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp
index 4f7b0a1a78..f7e71313df 100644
--- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp
@@ -74,21 +74,21 @@ void StereoDisplayPlugin::activate() {
         if (screen == qApp->primaryScreen()) {
             checked = true;
         }
-        auto action = CONTAINER->addMenuItem(MENU_PATH(), name,
+        auto action = _container->addMenuItem(MENU_PATH(), name,
             [this](bool clicked) { updateScreen(); }, true, checked, "Screens");
         _screenActions[i] = action;
     }
 
-    CONTAINER->removeMenu(FRAMERATE);
+    _container->removeMenu(FRAMERATE);
 
-    CONTAINER->setFullscreen(qApp->primaryScreen());
+    _container->setFullscreen(qApp->primaryScreen());
     WindowOpenGLDisplayPlugin::activate();
 }
 
 void StereoDisplayPlugin::updateScreen() {
     for (uint32_t i = 0; i < _screenActions.size(); ++i) {
         if (_screenActions[i]->isChecked()) {
-            CONTAINER->setFullscreen(qApp->screens().at(i));
+            _container->setFullscreen(qApp->screens().at(i));
             break;
         }
     }
@@ -96,7 +96,7 @@ void StereoDisplayPlugin::updateScreen() {
 
 void StereoDisplayPlugin::deactivate() {
     _screenActions.clear();
-    CONTAINER->unsetFullscreen();
+    _container->unsetFullscreen();
     WindowOpenGLDisplayPlugin::deactivate();
 }
 
diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.h b/libraries/input-plugins/src/input-plugins/InputPlugin.h
index 787922e04c..d03f884ec7 100644
--- a/libraries/input-plugins/src/input-plugins/InputPlugin.h
+++ b/libraries/input-plugins/src/input-plugins/InputPlugin.h
@@ -10,14 +10,4 @@
 //
 #pragma once
 
-#include <plugins/Plugin.h>
-
-class InputPlugin : public Plugin {
-public:
-    virtual bool isJointController() const = 0;
-
-    virtual void pluginFocusOutEvent() = 0;
-
-    virtual void pluginUpdate(float deltaTime, bool jointsCaptured) = 0;
-};
-
+#include <plugins/InputPlugin.h>
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 5e0f3277b1..024eb86182 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -94,8 +94,8 @@ void SixenseManager::activate() {
     _calibrationState = CALIBRATION_STATE_IDLE;
     _avatarPosition = DEFAULT_AVATAR_POSITION;
 
-    CONTAINER->addMenu(MENU_PATH);
-    CONTAINER->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
+    _container->addMenu(MENU_PATH);
+    _container->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
                            [this] (bool clicked) { this->setSixenseFilter(clicked); },
                            true, true);
 
@@ -136,8 +136,8 @@ void SixenseManager::deactivate() {
     InputPlugin::deactivate();
 
 #ifdef HAVE_SIXENSE
-    CONTAINER->removeMenuItem(MENU_NAME, TOGGLE_SMOOTH);
-    CONTAINER->removeMenu(MENU_PATH);
+    _container->removeMenuItem(MENU_NAME, TOGGLE_SMOOTH);
+    _container->removeMenu(MENU_PATH);
 
     _poseStateMap.clear();
     _collectedSamples.clear();
@@ -319,7 +319,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
                 _avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis)));
                 const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f;
                 _avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR;
-                CONTAINER->requestReset();
+                _container->requestReset();
                 qCDebug(inputplugins, "succeess: sixense calibration");
             }
             break;
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index e90006e014..69b2b5b2c6 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -75,8 +75,8 @@ bool ViveControllerManager::isSupported() const {
 void ViveControllerManager::activate() {
     InputPlugin::activate();
 #ifdef Q_OS_WIN
-    CONTAINER->addMenu(MENU_PATH);
-    CONTAINER->addMenuItem(MENU_PATH, RENDER_CONTROLLERS,
+    _container->addMenu(MENU_PATH);
+    _container->addMenuItem(MENU_PATH, RENDER_CONTROLLERS,
         [this] (bool clicked) { this->setRenderControllers(clicked); },
         true, true);
 
@@ -146,8 +146,8 @@ void ViveControllerManager::deactivate() {
     InputPlugin::deactivate();
 
 #ifdef Q_OS_WIN
-    CONTAINER->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
-    CONTAINER->removeMenu(MENU_PATH);
+    _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
+    _container->removeMenu(MENU_PATH);
 
     hmdRefCount--;
 
diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h
new file mode 100644
index 0000000000..5b00391f09
--- /dev/null
+++ b/libraries/plugins/src/plugins/DisplayPlugin.h
@@ -0,0 +1,140 @@
+//
+//  Created by Bradley Austin Davis on 2015/05/29
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#pragma once
+
+#include <functional>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/quaternion.hpp>
+
+#include <QtCore/QSize>
+#include <QtCore/QPoint>
+
+#include <GLMHelpers.h>
+#include <RegisteredMetaTypes.h>
+
+#include "Plugin.h"
+
+enum Eye {
+    Left,
+    Right,
+    Mono
+};
+
+/*
+ * Helper method to iterate over each eye
+ */
+template <typename F>
+void for_each_eye(F f) {
+    f(Left);
+    f(Right);
+}
+
+/*
+ * Helper method to iterate over each eye, with an additional lambda to take action between the eyes
+ */
+template <typename F, typename FF>
+void for_each_eye(F f, FF ff) {
+    f(Eye::Left);
+    ff();
+    f(Eye::Right);
+}
+
+class QWindow;
+
+#define AVERAGE_HUMAN_IPD 0.064f
+
+class DisplayPlugin : public Plugin {
+    Q_OBJECT
+public:
+    virtual bool isHmd() const { return false; }
+    virtual int getHmdScreen() const { return -1; }
+    /// By default, all HMDs are stereo
+    virtual bool isStereo() const { return isHmd(); }
+    virtual bool isThrottled() const { return false; }
+
+    // Rendering support
+
+    // Stop requesting renders, but don't do full deactivation
+    // needed to work around the issues caused by Oculus 
+    // processing messages in the middle of submitFrame
+    virtual void stop() = 0;
+
+    /**
+     *  Called by the application before the frame rendering.  Can be used for
+     *  render timing related calls (for instance, the Oculus begin frame timing
+     *  call)
+     */
+    virtual void preRender() = 0;
+    /**
+     *  Called by the application immediately before calling the display function.
+     *  For OpenGL based plugins, this is the best place to put activate the output
+     *  OpenGL context
+     */
+    virtual void preDisplay() = 0;
+
+    /**
+     *  Sends the scene texture to the display plugin.
+     */
+    virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0;
+
+    /**
+     *  Called by the application immeidately after display.  For OpenGL based
+     *  displays, this is the best place to put the buffer swap
+     */
+    virtual void finishFrame() = 0;
+
+    // Does the rendering surface have current focus?
+    virtual bool hasFocus() const = 0;
+
+    // The size of the rendering target (may be larger than the device size due to distortion)
+    virtual glm::uvec2 getRecommendedRenderSize() const = 0;
+
+    // The size of the UI
+    virtual glm::uvec2 getRecommendedUiSize() const {
+        return getRecommendedRenderSize();
+    }
+
+    // By default the aspect ratio is just the render size
+    virtual float getRecommendedAspectRatio() const {
+        return aspect(getRecommendedRenderSize());
+    }
+
+    // Stereo specific methods
+    virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const {
+        return baseProjection;
+    }
+
+    // HMD specific methods
+    // TODO move these into another class?
+    virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
+        static const glm::mat4 transform; return transform;
+    }
+
+    virtual glm::mat4 getHeadPose() const {
+        static const glm::mat4 pose; return pose;
+    }
+
+    // Needed for timewarp style features
+    virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) {
+        // NOOP
+    }
+
+    virtual float getIPD() const { return AVERAGE_HUMAN_IPD; }
+
+    virtual void abandonCalibration() {}
+    virtual void resetSensors() {}
+    virtual float devicePixelRatio() { return 1.0;  }
+
+
+    static const QString& MENU_PATH();
+signals:
+    void recommendedFramebufferSizeChanged(const QSize & size);
+    void requestRender();
+};
+
diff --git a/libraries/plugins/src/plugins/Forward.h b/libraries/plugins/src/plugins/Forward.h
index 1a9298d13c..78ec8fdcb3 100644
--- a/libraries/plugins/src/plugins/Forward.h
+++ b/libraries/plugins/src/plugins/Forward.h
@@ -21,3 +21,4 @@ using DisplayPluginPointer = QSharedPointer<DisplayPlugin>;
 using DisplayPluginList = QVector<DisplayPluginPointer>;
 using InputPluginPointer = QSharedPointer<InputPlugin>;
 using InputPluginList = QVector<InputPluginPointer>;
+
diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h
new file mode 100644
index 0000000000..e9d8ac8d86
--- /dev/null
+++ b/libraries/plugins/src/plugins/InputPlugin.h
@@ -0,0 +1,23 @@
+//
+//  InputPlugin.h
+//  input-plugins/src/input-plugins
+//
+//  Created by Sam Gondelman on 7/13/2015
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#pragma once
+
+#include "Plugin.h"
+
+class InputPlugin : public Plugin {
+public:
+    virtual bool isJointController() const = 0;
+
+    virtual void pluginFocusOutEvent() = 0;
+
+    virtual void pluginUpdate(float deltaTime, bool jointsCaptured) = 0;
+};
+
diff --git a/libraries/plugins/src/plugins/Plugin.cpp b/libraries/plugins/src/plugins/Plugin.cpp
index 2c0b9fa5cf..7c30f252c9 100644
--- a/libraries/plugins/src/plugins/Plugin.cpp
+++ b/libraries/plugins/src/plugins/Plugin.cpp
@@ -7,12 +7,10 @@
 //
 #include "Plugin.h"
 
-PluginContainer* Plugin::CONTAINER{ nullptr };
-
 QString Plugin::UNKNOWN_PLUGIN_ID("unknown");
 
 void Plugin::setContainer(PluginContainer* container) {
-    CONTAINER = container;
+    _container = container;
 }
 
 bool Plugin::isSupported() const { return true; }
diff --git a/libraries/plugins/src/plugins/Plugin.h b/libraries/plugins/src/plugins/Plugin.h
index f53d309e97..c030b1073f 100644
--- a/libraries/plugins/src/plugins/Plugin.h
+++ b/libraries/plugins/src/plugins/Plugin.h
@@ -24,7 +24,7 @@ public:
 
     virtual bool isSupported() const;
     
-    static void setContainer(PluginContainer* container);
+    void setContainer(PluginContainer* container);
 
     /// Called when plugin is initially loaded, typically at application start
     virtual void init();
@@ -57,8 +57,8 @@ public:
     virtual void loadSettings() {}
 
 protected:
-    bool _active{ false };
-    static PluginContainer* CONTAINER;
+    bool _active { false };
+    PluginContainer* _container { nullptr };
     static QString UNKNOWN_PLUGIN_ID;
 
 };
diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp
index 2deb41fb13..27e326fcba 100644
--- a/libraries/plugins/src/plugins/PluginManager.cpp
+++ b/libraries/plugins/src/plugins/PluginManager.cpp
@@ -6,15 +6,54 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 #include "PluginManager.h"
+
 #include <mutex>
 
-#include "Forward.h"
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QPluginLoader>
+
+#include "RuntimePlugin.h"
+#include "DisplayPlugin.h"
+#include "InputPlugin.h"
+#include "PluginContainer.h"
+
 
 PluginManager* PluginManager::getInstance() {
     static PluginManager _manager;
     return &_manager;
 }
 
+using Loader = QSharedPointer<QPluginLoader>;
+using LoaderList = QList<Loader>;
+
+const LoaderList& getLoadedPlugins() {
+    static std::once_flag once;
+    static LoaderList loadedPlugins;
+    std::call_once(once, [&] {
+        QString pluginPath = QCoreApplication::applicationDirPath() + "/plugins/";
+        QDir pluginDir(pluginPath);
+        pluginDir.setFilter(QDir::Files);
+        if (pluginDir.exists()) {
+            qDebug() << "Loading runtime plugins from " << pluginPath;
+            auto candidates = pluginDir.entryList();
+            for (auto plugin : candidates) {
+                qDebug() << "Attempting plugins " << plugin;
+                QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin));
+                if (loader->load()) {
+                    qDebug() << "Plugins " << plugin << " success";
+                    loadedPlugins.push_back(loader);
+                }
+            }
+        }
+    });
+    return loadedPlugins;
+}
+
+PluginManager::PluginManager() {
+}
+
 // TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
 extern DisplayPluginList getDisplayPlugins();
 extern InputPluginList getInputPlugins();
@@ -23,8 +62,25 @@ extern void saveInputPluginSettings(const InputPluginList& plugins);
 const DisplayPluginList& PluginManager::getDisplayPlugins() {
     static DisplayPluginList displayPlugins;
     static std::once_flag once;
+
     std::call_once(once, [&] {
+        // Grab the built in plugins
         displayPlugins = ::getDisplayPlugins();
+
+        // Now grab the dynamic plugins
+        for (auto loader : getLoadedPlugins()) {
+            DisplayProvider* displayProvider = qobject_cast<DisplayProvider*>(loader->instance());
+            if (displayProvider) {
+                for (auto displayPlugin : displayProvider->getDisplayPlugins()) {
+                    displayPlugins.push_back(displayPlugin);
+                }
+            }
+        }
+        auto& container = PluginContainer::getInstance();
+        for (auto plugin : displayPlugins) {
+            plugin->setContainer(&container);
+        }
+
     });
     return displayPlugins;
 }
@@ -34,6 +90,21 @@ const InputPluginList& PluginManager::getInputPlugins() {
     static std::once_flag once;
     std::call_once(once, [&] {
         inputPlugins = ::getInputPlugins();
+
+        // Now grab the dynamic plugins
+        for (auto loader : getLoadedPlugins()) {
+            InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance());
+            if (inputProvider) {
+                for (auto inputPlugin : inputProvider->getInputPlugins()) {
+                    inputPlugins.push_back(inputPlugin);
+                }
+            }
+        }
+
+        auto& container = PluginContainer::getInstance();
+        for (auto plugin : inputPlugins) {
+            plugin->setContainer(&container);
+        }
     });
     return inputPlugins;
 }
diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h
index 09dcc9d107..17619a93c0 100644
--- a/libraries/plugins/src/plugins/PluginManager.h
+++ b/libraries/plugins/src/plugins/PluginManager.h
@@ -12,6 +12,7 @@
 class PluginManager : public QObject {
 public:
   static PluginManager* getInstance();
+  PluginManager();
 
   const DisplayPluginList& getDisplayPlugins();
   const InputPluginList& getInputPlugins();
diff --git a/libraries/plugins/src/plugins/RuntimePlugin.h b/libraries/plugins/src/plugins/RuntimePlugin.h
new file mode 100644
index 0000000000..d7bf31ea28
--- /dev/null
+++ b/libraries/plugins/src/plugins/RuntimePlugin.h
@@ -0,0 +1,36 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/24
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#pragma once
+
+#include <assert.h>
+
+#include <QString>
+#include <QObject>
+
+#include "Forward.h"
+
+class DisplayProvider {
+public:
+    virtual ~DisplayProvider() {}
+
+    virtual DisplayPluginList getDisplayPlugins() = 0;
+};
+
+#define DisplayProvider_iid "com.highfidelity.plugins.display"
+Q_DECLARE_INTERFACE(DisplayProvider, DisplayProvider_iid)
+
+
+class InputProvider {
+public:
+    virtual ~InputProvider() {}
+    virtual InputPluginList getInputPlugins() = 0;
+};
+
+#define InputProvider_iid "com.highfidelity.plugins.input"
+Q_DECLARE_INTERFACE(InputProvider, InputProvider_iid)
+
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
new file mode 100644
index 0000000000..55b18b122c
--- /dev/null
+++ b/plugins/CMakeLists.txt
@@ -0,0 +1,18 @@
+#
+#  Created by Bradley Austin Davis on 2015/10/25
+#  Copyright 2015 High Fidelity, Inc.
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
+#
+
+# add the plugin directories
+file(GLOB PLUGIN_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/*")
+list(REMOVE_ITEM PLUGIN_SUBDIRS "CMakeFiles")
+
+foreach(DIR ${PLUGIN_SUBDIRS})
+  if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${DIR}")
+    add_subdirectory(${DIR})
+  endif()
+endforeach()
+
diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt
new file mode 100644
index 0000000000..62999cbb7e
--- /dev/null
+++ b/plugins/oculus/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+#  Created by Bradley Austin Davis on 2015/10/25
+#  Copyright 2015 High Fidelity, Inc.
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
+#
+
+if (WIN32)
+
+    set(TARGET_NAME oculus)
+    setup_hifi_plugin()
+    link_hifi_libraries(shared gl plugins display-plugins)
+    
+    include_hifi_library_headers(octree)
+    
+    add_dependency_external_projects(LibOVR)
+    find_package(LibOVR REQUIRED)
+    target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
+    target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
+
+endif()
\ No newline at end of file
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp
similarity index 95%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp
rename to plugins/oculus/src/OculusBaseDisplayPlugin.cpp
index 859a4a810a..4c80b9a51d 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp
+++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp
@@ -61,6 +61,14 @@ bool OculusBaseDisplayPlugin::isSupported() const {
 #endif
 }
 
+// DLL based display plugins MUST initialize GLEW inside the DLL code.
+void OculusBaseDisplayPlugin::customizeContext() {
+    glewExperimental = true;
+    GLenum err = glewInit();
+    glGetError();
+    WindowOpenGLDisplayPlugin::customizeContext();
+}
+
 void OculusBaseDisplayPlugin::init() {
 }
 
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h
similarity index 96%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h
rename to plugins/oculus/src/OculusBaseDisplayPlugin.h
index 6307f6bbf9..ba1924bfff 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h
+++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h
@@ -7,7 +7,7 @@
 //
 #pragma once
 
-#include "../WindowOpenGLDisplayPlugin.h"
+#include <display-plugins/WindowOpenGLDisplayPlugin.h>
 
 #include <QTimer>
 
@@ -35,6 +35,7 @@ public:
     virtual float getIPD() const override final;
 
 protected:
+    virtual void customizeContext() override;
     virtual void preRender() override final;
     virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
 
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusDebugDisplayPlugin.cpp b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusDebugDisplayPlugin.cpp
rename to plugins/oculus/src/OculusDebugDisplayPlugin.cpp
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusDebugDisplayPlugin.h b/plugins/oculus/src/OculusDebugDisplayPlugin.h
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusDebugDisplayPlugin.h
rename to plugins/oculus/src/OculusDebugDisplayPlugin.h
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp
similarity index 97%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.cpp
rename to plugins/oculus/src/OculusDisplayPlugin.cpp
index 3e2290f104..923b8bde6e 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.cpp
+++ b/plugins/oculus/src/OculusDisplayPlugin.cpp
@@ -7,11 +7,14 @@
 //
 #include "OculusDisplayPlugin.h"
 
-#include <QGLWidget>
+#include <QtOpenGL/QGLWidget>
+
+// FIXME get rid of this
+#include <gl/Config.h>
+#include <plugins/PluginContainer.h>
 
 #include "OculusHelpers.h"
 
-#include <plugins/PluginContainer.h>
 
 #if (OVR_MAJOR_VERSION >= 6)
 
@@ -142,16 +145,16 @@ static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate";
 
 void OculusDisplayPlugin::activate() {
 
-    CONTAINER->addMenuItem(MENU_PATH(), MONO_PREVIEW,
+    _container->addMenuItem(MENU_PATH(), MONO_PREVIEW,
         [this](bool clicked) {
             _monoPreview = clicked;
         }, true, true);
-    CONTAINER->removeMenu(FRAMERATE);
+    _container->removeMenu(FRAMERATE);
     OculusBaseDisplayPlugin::activate();
 }
 
 void OculusDisplayPlugin::customizeContext() {
-    WindowOpenGLDisplayPlugin::customizeContext();
+    OculusBaseDisplayPlugin::customizeContext();
 #if (OVR_MAJOR_VERSION >= 6)
     _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd));
     _sceneFbo->Init(getRecommendedRenderSize());
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.h
rename to plugins/oculus/src/OculusDisplayPlugin.h
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.cpp
rename to plugins/oculus/src/OculusHelpers.cpp
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h b/plugins/oculus/src/OculusHelpers.h
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h
rename to plugins/oculus/src/OculusHelpers.h
diff --git a/plugins/oculus/src/OculusProvider.cpp b/plugins/oculus/src/OculusProvider.cpp
new file mode 100644
index 0000000000..40dfb9df9a
--- /dev/null
+++ b/plugins/oculus/src/OculusProvider.cpp
@@ -0,0 +1,54 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <mutex>
+
+#include <QtCore/QObject>
+#include <QtCore/QtPlugin>
+#include <QtCore/QStringList>
+
+#include <plugins/RuntimePlugin.h>
+#include <plugins/DisplayPlugin.h>
+
+#include "OculusDisplayPlugin.h"
+#include "OculusDebugDisplayPlugin.h"
+
+class OculusProvider : public QObject, public DisplayProvider
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID DisplayProvider_iid FILE "oculus.json")
+    Q_INTERFACES(DisplayProvider)
+
+public:
+    OculusProvider(QObject* parent = nullptr) : QObject(parent) {}
+    virtual ~OculusProvider() {}
+
+    virtual DisplayPluginList getDisplayPlugins() override {
+        static std::once_flag once;
+        std::call_once(once, [&] {
+            DisplayPluginPointer plugin(new OculusDisplayPlugin());
+            if (plugin->isSupported()) {
+                _displayPlugins.push_back(plugin);
+            }
+
+            // Windows Oculus Simulator... uses head tracking and the same rendering 
+            // as the connected hardware, but without using the SDK to display to the 
+            // Rift.  Useful for debugging Rift performance with nSight.
+            plugin = DisplayPluginPointer(new OculusDebugDisplayPlugin());
+            if (plugin->isSupported()) {
+                _displayPlugins.push_back(plugin);
+            }
+        });
+        return _displayPlugins;
+    }
+
+private:
+    DisplayPluginList _displayPlugins;
+};
+
+#include "OculusProvider.moc"
diff --git a/plugins/oculus/src/oculus.json b/plugins/oculus/src/oculus.json
new file mode 100644
index 0000000000..0967ef424b
--- /dev/null
+++ b/plugins/oculus/src/oculus.json
@@ -0,0 +1 @@
+{}
diff --git a/plugins/oculusLegacy/CMakeLists.txt b/plugins/oculusLegacy/CMakeLists.txt
new file mode 100644
index 0000000000..bf9d22410d
--- /dev/null
+++ b/plugins/oculusLegacy/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+#  Created by Bradley Austin Davis on 2015/10/25
+#  Copyright 2015 High Fidelity, Inc.
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
+#
+
+if (NOT WIN32)
+
+    set(TARGET_NAME oculusLegacy)
+    setup_hifi_plugin()
+    link_hifi_libraries(shared gl plugins display-plugins)
+    
+    include_hifi_library_headers(octree)
+    
+    add_dependency_external_projects(LibOVR)
+    find_package(LibOVR REQUIRED)
+    target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
+    target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
+
+endif()
\ No newline at end of file
diff --git a/plugins/oculusLegacy/src/OculusHelpers.cpp b/plugins/oculusLegacy/src/OculusHelpers.cpp
new file mode 100644
index 0000000000..fff2a38344
--- /dev/null
+++ b/plugins/oculusLegacy/src/OculusHelpers.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis on 2015/08/08
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "OculusHelpers.h"
diff --git a/plugins/oculusLegacy/src/OculusHelpers.h b/plugins/oculusLegacy/src/OculusHelpers.h
new file mode 100644
index 0000000000..b4bcdc1511
--- /dev/null
+++ b/plugins/oculusLegacy/src/OculusHelpers.h
@@ -0,0 +1,85 @@
+//
+//  Created by Bradley Austin Davis on 2015/05/26
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#pragma once
+
+#include <OVR_CAPI_GL.h>
+#include <GLMHelpers.h>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+
+// Convenience method for looping over each eye with a lambda
+template <typename Function>
+inline void ovr_for_each_eye(Function function) {
+    for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
+        eye < ovrEyeType::ovrEye_Count;
+        eye = static_cast<ovrEyeType>(eye + 1)) {
+        function(eye);
+    }
+}
+
+inline glm::mat4 toGlm(const ovrMatrix4f & om) {
+    return glm::transpose(glm::make_mat4(&om.M[0][0]));
+}
+
+inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
+    return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
+}
+
+inline glm::vec3 toGlm(const ovrVector3f & ov) {
+    return glm::make_vec3(&ov.x);
+}
+
+inline glm::vec2 toGlm(const ovrVector2f & ov) {
+    return glm::make_vec2(&ov.x);
+}
+
+inline glm::uvec2 toGlm(const ovrSizei & ov) {
+    return glm::uvec2(ov.w, ov.h);
+}
+
+inline glm::quat toGlm(const ovrQuatf & oq) {
+    return glm::make_quat(&oq.x);
+}
+
+inline glm::mat4 toGlm(const ovrPosef & op) {
+    glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
+    glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
+    return translation * orientation;
+}
+
+inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
+    ovrMatrix4f result;
+    glm::mat4 transposed(glm::transpose(m));
+    memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
+    return result;
+}
+
+inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
+    return{ v.x, v.y, v.z };
+}
+
+inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
+    return{ v.x, v.y };
+}
+
+inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
+    return{ (int)v.x, (int)v.y };
+}
+
+inline ovrQuatf ovrFromGlm(const glm::quat & q) {
+    return{ q.x, q.y, q.z, q.w };
+}
+
+inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) {
+    glm::vec3 translation = glm::vec3(m[3]) / m[3].w;
+    glm::quat orientation = glm::quat_cast(m);
+    ovrPosef result;
+    result.Orientation = ovrFromGlm(orientation);
+    result.Position = ovrFromGlm(translation);
+    return result; 
+}
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
similarity index 90%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp
rename to plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
index 205444397f..5a253cdbbf 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
@@ -42,10 +42,8 @@ uvec2 OculusLegacyDisplayPlugin::getRecommendedRenderSize() const {
 }
 
 void OculusLegacyDisplayPlugin::preRender() {
-#if (OVR_MAJOR_VERSION == 5)
     ovrHmd_GetEyePoses(_hmd, _frameIndex, _eyeOffsets, _eyePoses, &_trackingState);
     ovrHmd_BeginFrame(_hmd, _frameIndex);
-#endif
     WindowOpenGLDisplayPlugin::preRender();
 }
 
@@ -54,32 +52,21 @@ glm::mat4 OculusLegacyDisplayPlugin::getProjection(Eye eye, const glm::mat4& bas
 }
 
 void OculusLegacyDisplayPlugin::resetSensors() {
-#if (OVR_MAJOR_VERSION == 5)
     ovrHmd_RecenterPose(_hmd);
-#endif
 }
 
 glm::mat4 OculusLegacyDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
-#if (OVR_MAJOR_VERSION == 5)
     return toGlm(_eyePoses[eye]);
-#else
-    return WindowOpenGLDisplayPlugin::getEyeToHeadTransform(eye);
-#endif
 }
 
 // Should NOT be used for rendering as this will mess up timewarp.  Use the getModelview() method above for
 // any use of head poses for rendering, ensuring you use the correct eye
 glm::mat4 OculusLegacyDisplayPlugin::getHeadPose() const {
-#if (OVR_MAJOR_VERSION == 5)
     return toGlm(_trackingState.HeadPose.ThePose);
-#else
-    return WindowOpenGLDisplayPlugin::getHeadPose();
-#endif
 }
 
 
 bool OculusLegacyDisplayPlugin::isSupported() const {
-#if (OVR_MAJOR_VERSION == 5)
     if (!ovr_Initialize(nullptr)) {
         return false;
     }
@@ -104,14 +91,10 @@ bool OculusLegacyDisplayPlugin::isSupported() const {
   
     ovr_Shutdown();
     return result;
-#else 
-    return false;
-#endif
 }
 
 void OculusLegacyDisplayPlugin::activate() {
-#if (OVR_MAJOR_VERSION == 5)
-    if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
+    if (!(ovr_Initialize(nullptr))) {
         Q_ASSERT(false);
         qFatal("Failed to Initialize SDK");
     }
@@ -149,8 +132,8 @@ void OculusLegacyDisplayPlugin::activate() {
 
     _frameIndex = 0;
 
-    if (!OVR_SUCCESS(ovrHmd_ConfigureTracking(_hmd,
-        ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) {
+    if (!ovrHmd_ConfigureTracking(_hmd,
+        ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0)) {
         qFatal("Could not attach to sensor device");
     }
 
@@ -158,7 +141,7 @@ void OculusLegacyDisplayPlugin::activate() {
 
     int screen = getHmdScreen();
     if (screen != -1) {
-        CONTAINER->setFullscreen(qApp->screens()[screen]);
+        _container->setFullscreen(qApp->screens()[screen]);
     }
     
     _window->installEventFilter(this);
@@ -189,11 +172,9 @@ void OculusLegacyDisplayPlugin::activate() {
     #endif
         ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
     Q_ASSERT(result);
-#endif
 }
 
 void OculusLegacyDisplayPlugin::deactivate() {
-#if (OVR_MAJOR_VERSION == 5)
     _window->removeEventFilter(this);
 
     WindowOpenGLDisplayPlugin::deactivate();
@@ -202,12 +183,11 @@ void OculusLegacyDisplayPlugin::deactivate() {
     if (_hmdScreen >= 0) {
         riftScreen = qApp->screens()[_hmdScreen];
     }
-    CONTAINER->unsetFullscreen(riftScreen);
+    _container->unsetFullscreen(riftScreen);
     
     ovrHmd_Destroy(_hmd);
     _hmd = nullptr;
     ovr_Shutdown();
-#endif
 }
 
 void OculusLegacyDisplayPlugin::preDisplay() {
@@ -216,17 +196,14 @@ void OculusLegacyDisplayPlugin::preDisplay() {
 
 void OculusLegacyDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
     ++_frameIndex;
-#if (OVR_MAJOR_VERSION == 5)
     ovr_for_each_eye([&](ovrEyeType eye) {
         reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]).OGL.TexId = finalTexture;
     });
     ovrHmd_EndFrame(_hmd, _eyePoses, _eyeTextures);
-#endif
 }
 
 // Pass input events on to the application
 bool OculusLegacyDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
-#if (OVR_MAJOR_VERSION == 5)
     if (!_hswDismissed && (event->type() == QEvent::KeyPress)) {
         static ovrHSWDisplayState hswState;
         ovrHmd_GetHSWDisplayState(_hmd, &hswState);
@@ -236,7 +213,6 @@ bool OculusLegacyDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
             _hswDismissed = true;
         }
     }    
-#endif
     return WindowOpenGLDisplayPlugin::eventFilter(receiver, event);
 }
 
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h
similarity index 97%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h
rename to plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h
index 9e2e47f434..2e95cee9bb 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h
@@ -7,7 +7,7 @@
 //
 #pragma once
 
-#include "../WindowOpenGLDisplayPlugin.h"
+#include <display-plugins/WindowOpenGLDisplayPlugin.h>
 
 #include <QTimer>
 
diff --git a/plugins/oculusLegacy/src/OculusProvider.cpp b/plugins/oculusLegacy/src/OculusProvider.cpp
new file mode 100644
index 0000000000..606563e0ad
--- /dev/null
+++ b/plugins/oculusLegacy/src/OculusProvider.cpp
@@ -0,0 +1,45 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/25
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include <mutex>
+
+#include <QtCore/QObject>
+#include <QtCore/QtPlugin>
+#include <QtCore/QStringList>
+
+#include <plugins/RuntimePlugin.h>
+#include <plugins/DisplayPlugin.h>
+
+#include "OculusLegacyDisplayPlugin.h"
+
+class OculusProvider : public QObject, public DisplayProvider
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID DisplayProvider_iid FILE "oculus.json")
+    Q_INTERFACES(DisplayProvider)
+
+public:
+    OculusProvider(QObject* parent = nullptr) : QObject(parent) {}
+    virtual ~OculusProvider() {}
+
+    virtual DisplayPluginList getDisplayPlugins() override {
+        static std::once_flag once;
+        std::call_once(once, [&] {
+            DisplayPluginPointer plugin(new OculusLegacyDisplayPlugin());
+            if (plugin->isSupported()) {
+                _displayPlugins.push_back(plugin);
+            }
+        });
+        return _displayPlugins;
+    }
+
+private:
+    DisplayPluginList _displayPlugins;
+};
+
+#include "OculusProvider.moc"
diff --git a/plugins/oculusLegacy/src/oculus.json b/plugins/oculusLegacy/src/oculus.json
new file mode 100644
index 0000000000..0967ef424b
--- /dev/null
+++ b/plugins/oculusLegacy/src/oculus.json
@@ -0,0 +1 @@
+{}
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index a7b1be15ca..139d9b282c 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -80,9 +80,6 @@ using namespace controller;
 class PluginContainerProxy : public QObject, PluginContainer {
     Q_OBJECT
 public:
-    PluginContainerProxy() {
-        Plugin::setContainer(this);
-    }
     virtual ~PluginContainerProxy() {}
     virtual void addMenu(const QString& menuName) override {}
     virtual void removeMenu(const QString& menuName) override {}

From 43df5b55fe5adf6c3fefdc61c431225fe7587668 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sun, 1 Nov 2015 11:55:55 -0800
Subject: [PATCH 294/301] fix linker warnings

---
 .../controllers/src/controllers/DeviceProxy.cpp      | 11 +++++++----
 .../controllers/src/controllers/impl/Endpoint.cpp    | 12 +++++++-----
 .../controllers/src/controllers/impl/Mapping.cpp     |  9 ++++++++-
 libraries/controllers/src/controllers/impl/Route.cpp |  8 +++++++-
 .../impl/conditionals/EndpointConditional.cpp        |  8 +++++++-
 .../controllers/impl/conditionals/NotConditional.cpp |  8 +++++++-
 .../src/controllers/impl/endpoints/ArrayEndpoint.cpp |  8 +++++++-
 .../src/controllers/impl/endpoints/JSEndpoint.cpp    |  8 +++++++-
 .../controllers/impl/endpoints/StandardEndpoint.cpp  |  8 +++++++-
 .../impl/filters/ConstrainToIntegerFilter.cpp        |  8 +++++++-
 .../filters/ConstrainToPositiveIntegerFilter.cpp     |  8 +++++++-
 .../src/controllers/impl/filters/InvertFilter.cpp    |  8 +++++++-
 12 files changed, 85 insertions(+), 19 deletions(-)

diff --git a/libraries/controllers/src/controllers/DeviceProxy.cpp b/libraries/controllers/src/controllers/DeviceProxy.cpp
index f3e9526080..f03354c52d 100644
--- a/libraries/controllers/src/controllers/DeviceProxy.cpp
+++ b/libraries/controllers/src/controllers/DeviceProxy.cpp
@@ -7,8 +7,11 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "DeviceProxy.h"
-
-namespace controller {
-}
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "DeviceProxy.h"
 
diff --git a/libraries/controllers/src/controllers/impl/Endpoint.cpp b/libraries/controllers/src/controllers/impl/Endpoint.cpp
index 9e9b13f8ea..e771b1916f 100644
--- a/libraries/controllers/src/controllers/impl/Endpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/Endpoint.cpp
@@ -6,9 +6,11 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "Endpoint.h"
-
-namespace controller {
-
-}
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "Endpoint.h"
 
diff --git a/libraries/controllers/src/controllers/impl/Mapping.cpp b/libraries/controllers/src/controllers/impl/Mapping.cpp
index 68c43da393..dd8e1c1d48 100644
--- a/libraries/controllers/src/controllers/impl/Mapping.cpp
+++ b/libraries/controllers/src/controllers/impl/Mapping.cpp
@@ -5,4 +5,11 @@
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
-#include "Mapping.h"
+
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "Mapping.h"
diff --git a/libraries/controllers/src/controllers/impl/Route.cpp b/libraries/controllers/src/controllers/impl/Route.cpp
index 56590e564a..c74f809195 100644
--- a/libraries/controllers/src/controllers/impl/Route.cpp
+++ b/libraries/controllers/src/controllers/impl/Route.cpp
@@ -6,4 +6,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "Route.h"
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "Route.h"
diff --git a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp
index 03e16b8cf9..f833eedb60 100644
--- a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp
+++ b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp
@@ -6,4 +6,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "EndpointConditional.h"
\ No newline at end of file
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "EndpointConditional.h"
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/impl/conditionals/NotConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.cpp
index 0c8d602b9e..e30b060985 100644
--- a/libraries/controllers/src/controllers/impl/conditionals/NotConditional.cpp
+++ b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.cpp
@@ -6,4 +6,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "NotConditional.h"
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "NotConditional.h"
diff --git a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp
index c083a7147d..5dea1de34e 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp
@@ -6,4 +6,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "ArrayEndpoint.h"
\ No newline at end of file
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "ArrayEndpoint.h"
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp
index 4560741d12..7f0e80cbae 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp
@@ -6,4 +6,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "JSEndpoint.h"
\ No newline at end of file
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "JSEndpoint.h"
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp
index 09920d249c..89bbe5d777 100644
--- a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp
+++ b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp
@@ -6,4 +6,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "StandardEndpoint.h"
\ No newline at end of file
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "StandardEndpoint.h"
\ No newline at end of file
diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp
index 78ffb47693..8bd3d2db89 100644
--- a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp
+++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp
@@ -6,4 +6,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "ConstrainToIntegerFilter.h"
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "ConstrainToIntegerFilter.h"
diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp
index d78942b18f..f1abc8cecd 100644
--- a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp
+++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp
@@ -6,4 +6,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "ConstrainToPositiveIntegerFilter.h"
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "ConstrainToPositiveIntegerFilter.h"
diff --git a/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp b/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp
index db582b84cc..5407c6dd1d 100644
--- a/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp
+++ b/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp
@@ -6,4 +6,10 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include "InvertFilter.h"
+// NOTE: we don't need to include this header unless/until we add additional symbols.
+//       By removing this header we prevent these warnings on windows:
+//
+//           warning LNK4221: This object file does not define any previously undefined public symbols, 
+//           so it will not be used by any link operation that consumes this library
+//
+//#include "InvertFilter.h"

From 4a08329d22cd094b984622ab575a898b6a1de78b Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sun, 1 Nov 2015 12:10:42 -0800
Subject: [PATCH 295/301] fix unix warnings for comparing enums to enums

---
 .../src/input-plugins/SDL2Manager.cpp         | 42 +++++++++----------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
index ec2fa2ed07..c6f5491a5a 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
@@ -20,27 +20,27 @@
 
 #ifdef HAVE_SDL2
 static_assert(
-    controller::A == SDL_CONTROLLER_BUTTON_A &&
-    controller::B == SDL_CONTROLLER_BUTTON_B &&
-    controller::X == SDL_CONTROLLER_BUTTON_X &&
-    controller::Y == SDL_CONTROLLER_BUTTON_Y &&
-    controller::BACK == SDL_CONTROLLER_BUTTON_BACK &&
-    controller::GUIDE == SDL_CONTROLLER_BUTTON_GUIDE &&
-    controller::START == SDL_CONTROLLER_BUTTON_START &&
-    controller::LS == SDL_CONTROLLER_BUTTON_LEFTSTICK &&
-    controller::RS == SDL_CONTROLLER_BUTTON_RIGHTSTICK &&
-    controller::LB == SDL_CONTROLLER_BUTTON_LEFTSHOULDER &&
-    controller::RB == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER &&
-    controller::DU == SDL_CONTROLLER_BUTTON_DPAD_UP &&
-    controller::DD == SDL_CONTROLLER_BUTTON_DPAD_DOWN &&
-    controller::DL == SDL_CONTROLLER_BUTTON_DPAD_LEFT &&
-    controller::DR == SDL_CONTROLLER_BUTTON_DPAD_RIGHT &&
-    controller::LX == SDL_CONTROLLER_AXIS_LEFTX &&
-    controller::LY == SDL_CONTROLLER_AXIS_LEFTY &&
-    controller::RX == SDL_CONTROLLER_AXIS_RIGHTX &&
-    controller::RY == SDL_CONTROLLER_AXIS_RIGHTY &&
-    controller::LT == SDL_CONTROLLER_AXIS_TRIGGERLEFT &&
-    controller::RT == SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
+    (int)controller::A == (int)SDL_CONTROLLER_BUTTON_A &&
+    (int)controller::B == (int)SDL_CONTROLLER_BUTTON_B &&
+    (int)controller::X == (int)SDL_CONTROLLER_BUTTON_X &&
+    (int)controller::Y == (int)SDL_CONTROLLER_BUTTON_Y &&
+    (int)controller::BACK == (int)SDL_CONTROLLER_BUTTON_BACK &&
+    (int)controller::GUIDE == (int)SDL_CONTROLLER_BUTTON_GUIDE &&
+    (int)controller::START == (int)SDL_CONTROLLER_BUTTON_START &&
+    (int)controller::LS == (int)SDL_CONTROLLER_BUTTON_LEFTSTICK &&
+    (int)controller::RS == (int)SDL_CONTROLLER_BUTTON_RIGHTSTICK &&
+    (int)controller::LB == (int)SDL_CONTROLLER_BUTTON_LEFTSHOULDER &&
+    (int)controller::RB == (int)SDL_CONTROLLER_BUTTON_RIGHTSHOULDER &&
+    (int)controller::DU == (int)SDL_CONTROLLER_BUTTON_DPAD_UP &&
+    (int)controller::DD == (int)SDL_CONTROLLER_BUTTON_DPAD_DOWN &&
+    (int)controller::DL == (int)SDL_CONTROLLER_BUTTON_DPAD_LEFT &&
+    (int)controller::DR == (int)SDL_CONTROLLER_BUTTON_DPAD_RIGHT &&
+    (int)controller::LX == (int)SDL_CONTROLLER_AXIS_LEFTX &&
+    (int)controller::LY == (int)SDL_CONTROLLER_AXIS_LEFTY &&
+    (int)controller::RX == (int)SDL_CONTROLLER_AXIS_RIGHTX &&
+    (int)controller::RY == (int)SDL_CONTROLLER_AXIS_RIGHTY &&
+    (int)controller::LT == (int)SDL_CONTROLLER_AXIS_TRIGGERLEFT &&
+    (int)controller::RT == (int)SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
     "SDL2 equvalence: Enums and values from StandardControls.h are assumed to match enums from SDL_gamecontroller.h");
 #endif
 

From e0ac48fe27b442efb7ef1a28ac4ce130b5aedb2a Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 1 Nov 2015 11:28:38 -0800
Subject: [PATCH 296/301] PR comments

---
 BUILD.md                      | 17 +++++++++++++----
 cmake/macros/TargetZlib.cmake | 11 ++++++++---
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/BUILD.md b/BUILD.md
index 7ad2ddeee0..72dfa5725e 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -5,15 +5,24 @@
 * [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1m
   * IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities.
 * [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
-* [zlib](http://www.zlib.net/)
 
 ####CMake External Project Dependencies
 
+* [boostconfig](https://github.com/boostorg/config) ~> 1.58
 * [Bullet Physics Engine](https://code.google.com/p/bullet/downloads/list) ~> 2.82
-* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
+* [Faceshift](http://www.faceshift.com/) ~> 4.3
+* [GLEW](http://glew.sourceforge.net/)
 * [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4
 * [gverb](https://github.com/highfidelity/gverb)
+* [Oculus SDK](https://developer.oculus.com/downloads/) ~> 0.6 (Win32) / 0.5 (Mac / Linux)
+* [oglplus](http://oglplus.org/) ~> 0.63
+* [OpenVR](https://github.com/ValveSoftware/openvr) ~> 0.91 (Win32 only)
+* [Polyvox](http://www.volumesoffun.com/) ~> 0.2.1
 * [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3
+* [soxr](http://soxr.sourceforge.net) ~> 0.1.1
+* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
+* [Sixense](http://sixense.com/) ~> 071615 
+* [zlib](http://www.zlib.net/) ~> 1.28 (Win32 only)
 
 The above dependencies will be downloaded, built, linked and included automatically by CMake where we require them. The CMakeLists files that handle grabbing each of the following external dependencies can be found in the [cmake/externals folder](cmake/externals). The resulting downloads, source files and binaries will be placed in the `build/ext` folder in each of the subfolders for each external project. 
 
@@ -59,7 +68,7 @@ For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generat
 
 ####Finding Dependencies
 
-The following applies for dependencies we do not grab via CMake ExternalProject (OpenSSL is an example), or for dependencies you have opted not to grab as a CMake ExternalProject (via -DGET_$NAME=0). The list of dependencies we grab by default as external projects can be found in [the CMake External Project Dependencies section](#cmake-external-project-dependencies).
+The following applies for dependencies we do not grab via CMake ExternalProject (OpenSSL is an example), or for dependencies you have opted not to grab as a CMake ExternalProject (via -DUSE_LOCAL_$NAME=0). The list of dependencies we grab by default as external projects can be found in [the CMake External Project Dependencies section](#cmake-external-project-dependencies).
 
 You can point our [Cmake find modules](cmake/modules/) to the correct version of dependencies by setting one of the three following variables to the location of the correct version of the dependency.
 
@@ -73,5 +82,5 @@ In the examples below the variable $NAME would be replaced by the name of the de
 
 ####Devices
 
-You can support external input/output devices such as Oculus Rift, Leap Motion, Faceshift, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
+You can support external input/output devices such as Leap Motion, MIDI, and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
 
diff --git a/cmake/macros/TargetZlib.cmake b/cmake/macros/TargetZlib.cmake
index 11eb8c132e..3eb0322ea0 100644
--- a/cmake/macros/TargetZlib.cmake
+++ b/cmake/macros/TargetZlib.cmake
@@ -6,12 +6,17 @@
 #  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 # 
 macro(TARGET_ZLIB)
+
     if (WIN32)
         add_dependency_external_projects(zlib)
-        add_paths_to_fixup_libs(${ZLIB_DLL_PATH})
-    else()
-        find_package(ZLIB REQUIRED)
     endif()
+
+    find_package(ZLIB REQUIRED)
+
+    if (WIN32)
+        add_paths_to_fixup_libs(${ZLIB_DLL_PATH})
+    endif()
+
     target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${ZLIB_INCLUDE_DIRS})
     target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
 endmacro()

From 13e805ac15f4ccf8ccefc51e9d722344adc8b8e4 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sun, 1 Nov 2015 13:18:53 -0800
Subject: [PATCH 297/301] replace copy_resolved_item_into_bundle with a version
 that doesn't report warnings for a status case

---
 cmake/templates/FixupBundlePostBuild.cmake.in | 30 +++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/cmake/templates/FixupBundlePostBuild.cmake.in b/cmake/templates/FixupBundlePostBuild.cmake.in
index 7d98e9796c..4afe4de403 100644
--- a/cmake/templates/FixupBundlePostBuild.cmake.in
+++ b/cmake/templates/FixupBundlePostBuild.cmake.in
@@ -10,5 +10,35 @@
 # 
 
 include(BundleUtilities)
+
+
+# replace copy_resolved_item_into_bundle 
+#
+# The official version of copy_resolved_item_into_bundle will print out a "warning:" when
+# the resolved item matches the resolved embedded item. This not not really an issue that
+# should rise to the level of a "warning" so we replace this message with a "status:"
+#
+function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
+    if(WIN32)
+        # ignore case on Windows
+        string(TOLOWER "${resolved_item}" resolved_item_compare)
+        string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
+    else()
+        set(resolved_item_compare "${resolved_item}")
+        set(resolved_embedded_item_compare "${resolved_embedded_item}")
+    endif()
+
+    if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
+        # this is our only change from the original version
+        message(STATUS "status: resolved_item == resolved_embedded_item - not copying...")
+    else()
+        #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
+        execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
+        if(UNIX AND NOT APPLE)
+            file(RPATH_REMOVE FILE "${resolved_embedded_item}")
+        endif()
+    endif()
+endfunction()
+
 message(STATUS "FIXUP_LIBS for fixup_bundle called for bundle ${BUNDLE_EXECUTABLE} are @FIXUP_LIBS@")
 fixup_bundle("${BUNDLE_EXECUTABLE}" "" "@FIXUP_LIBS@")
\ No newline at end of file

From 1e47a536031829dfad3a527b428447f3df96c0af Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 1 Nov 2015 14:34:03 -0800
Subject: [PATCH 298/301] Fixing mac oculus crash

---
 plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 8 ++++++++
 plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h   | 1 +
 2 files changed, 9 insertions(+)

diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
index 5a253cdbbf..0120bcf2aa 100644
--- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
@@ -190,6 +190,14 @@ void OculusLegacyDisplayPlugin::deactivate() {
     ovr_Shutdown();
 }
 
+// DLL based display plugins MUST initialize GLEW inside the DLL code.
+void OculusLegacyDisplayPlugin::customizeContext() {
+    glewExperimental = true;
+    GLenum err = glewInit();
+    glGetError();
+    WindowOpenGLDisplayPlugin::customizeContext();
+}
+
 void OculusLegacyDisplayPlugin::preDisplay() {
     _window->makeCurrent();
 }
diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h
index 2e95cee9bb..6e3f864aee 100644
--- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h
@@ -35,6 +35,7 @@ public:
     virtual glm::mat4 getHeadPose() const override;
 
 protected:
+    virtual void customizeContext() override;
     virtual void preRender() override;
     virtual void preDisplay() override;
     virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;

From b9d60e803b566dbcd8ae00c98202d8fc96936a20 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sun, 1 Nov 2015 15:13:28 -0800
Subject: [PATCH 299/301] fix mac warning

---
 plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
index 0120bcf2aa..d8dc3667ae 100644
--- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
@@ -193,7 +193,7 @@ void OculusLegacyDisplayPlugin::deactivate() {
 // DLL based display plugins MUST initialize GLEW inside the DLL code.
 void OculusLegacyDisplayPlugin::customizeContext() {
     glewExperimental = true;
-    GLenum err = glewInit();
+    glewInit();
     glGetError();
     WindowOpenGLDisplayPlugin::customizeContext();
 }

From 92bcd9ca9eb583252b63fbcd0c397390521a5779 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Sun, 1 Nov 2015 15:48:01 -0800
Subject: [PATCH 300/301] make oculus plugin use static glew

---
 plugins/oculus/CMakeLists.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt
index 62999cbb7e..fe1a87d6b6 100644
--- a/plugins/oculus/CMakeLists.txt
+++ b/plugins/oculus/CMakeLists.txt
@@ -8,6 +8,9 @@
 
 if (WIN32)
 
+    # we're using static GLEW, so define GLEW_STATIC
+    add_definitions(-DGLEW_STATIC)
+
     set(TARGET_NAME oculus)
     setup_hifi_plugin()
     link_hifi_libraries(shared gl plugins display-plugins)

From 70b9aa5ff198f074fd9b5ae1989bec1fff033626 Mon Sep 17 00:00:00 2001
From: Brad Hefta-Gaub <brad@highfidelity.io>
Date: Mon, 2 Nov 2015 07:42:52 -0800
Subject: [PATCH 301/301] remove right click context menu until we can make it
 work with camera move better

---
 interface/resources/controllers/keyboardMouse.json | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json
index 9c3ba79d76..8af6b1dc98 100644
--- a/interface/resources/controllers/keyboardMouse.json
+++ b/interface/resources/controllers/keyboardMouse.json
@@ -81,7 +81,6 @@
 
         { "from": "Keyboard.Space", "to": "Actions.SHIFT" },
         { "from": "Keyboard.R", "to": "Actions.ACTION1" },
-        { "from": "Keyboard.T", "to": "Actions.ACTION2" },
-        { "from": "Keyboard.RightMouseClick", "to": "Actions.ContextMenu" }
+        { "from": "Keyboard.T", "to": "Actions.ACTION2" }
     ]
 }