diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index e97b0c7585..e040833e01 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -76,7 +76,6 @@
 #include <InfoView.h>
 #include <input-plugins/InputPlugin.h>
 #include <input-plugins/Joystick.h> // this should probably be removed
-#include <input-plugins/SixenseManager.h> // this definitely should be removed
 #include <LogHandler.h>
 #include <MainWindow.h>
 #include <MessageDialog.h>
@@ -2130,7 +2129,7 @@ void Application::setEnableVRMode(bool enableVRMode) {
 #endif
 
 void Application::setLowVelocityFilter(bool lowVelocityFilter) {
-    SixenseManager::getInstance().setLowVelocityFilter(lowVelocityFilter);
+    InputDevice::setLowVelocityFilter(lowVelocityFilter);
 }
 
 bool Application::mouseOnScreen() const {
@@ -2364,18 +2363,7 @@ void Application::init() {
     DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
 
     qCDebug(interfaceapp) << "Loaded settings";
-
-#ifdef __APPLE__
-    if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseEnabled)) {
-        // on OS X we only setup sixense if the user wants it on - this allows running without the hid_init crash
-        // if hydra support is temporarily not required
-        SixenseManager::getInstance().toggleSixense(true);
-    }
-#else
-    // setup sixense
-    SixenseManager::getInstance().toggleSixense(true);
-#endif
-
+    
     Leapmotion::init();
     RealSense::init();
 
@@ -2683,12 +2671,17 @@ void Application::update(float deltaTime) {
     userInputMapper->setSensorToWorldMat(_myAvatar->getSensorToWorldMatrix());
     userInputMapper->update(deltaTime);
 
+    // This needs to go after userInputMapper->update() because of the keyboard
+    bool jointsCaptured = false;
     auto inputPlugins = getInputPlugins();
     foreach(auto inputPlugin, inputPlugins) {
         QString name = inputPlugin->getName();
         QAction* action = Menu::getInstance()->getActionForOption(name);
         if (action->isChecked()) {
-            inputPlugin->pluginUpdate(deltaTime); // add flag to prevent multiple devices from modifying joints
+            inputPlugin->pluginUpdate(deltaTime, jointsCaptured);
+            if (inputPlugin->isJointController()) {
+                jointsCaptured = true;
+            }
         }
     }
 
@@ -2716,8 +2709,8 @@ void Application::update(float deltaTime) {
     UserInputMapper::PoseValue leftHand = userInputMapper->getPoseState(UserInputMapper::LEFT_HAND);
     UserInputMapper::PoseValue rightHand = userInputMapper->getPoseState(UserInputMapper::RIGHT_HAND);
     Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
-    setPalmData(hand, leftHand, LEFT_HAND_INDEX);
-    setPalmData(hand, rightHand, RIGHT_HAND_INDEX);
+    setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX);
+    setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX);
     if (Menu::getInstance()->isOptionChecked(MenuOption::HandMouseInput)) {
         emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK),
             userInputMapper->getActionState(UserInputMapper::SHIFT), LEFT_HAND_INDEX);
@@ -2869,7 +2862,7 @@ void Application::update(float deltaTime) {
     _myAvatar->updateSensorToWorldMatrix();
 }
 
-void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, int index) {
+void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index) {
     PalmData* palm;
     bool foundHand = false;
     for (size_t j = 0; j < hand->getNumPalms(); j++) {
@@ -2887,12 +2880,54 @@ void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, int i
     }
     
     palm->setActive(pose.isValid());
+
+    glm::vec3 position = pose.getTranslation();
+    glm::quat rotation = pose.getRotation();
+
+    // TODO: velocity and tip position information should be converted to model space
+    //  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
     
-    // TODO: velocity filters, tip velocities, etc.
-    // see SixenseManager
+    //  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 (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);
+    }
+
+    // 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, 0.0f, FINGER_LENGTH);
+    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);
 
     // transform from sensor space, to world space, to avatar model space.
-    glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation());
+    glm::mat4 poseMat = createMatFromQuatAndPos(rotation, position);
     glm::mat4 sensorToWorldMat = _myAvatar->getSensorToWorldMatrix();
     glm::mat4 modelMat = createMatFromQuatAndPos(_myAvatar->getOrientation(), _myAvatar->getPosition());
     glm::mat4 objectPose = glm::inverse(modelMat) * sensorToWorldMat * poseMat;
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 1ff56b37ed..46d1ecf39e 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -475,7 +475,7 @@ private:
 
     void update(float deltaTime);
 
-    void setPalmData(Hand* hand, UserInputMapper::PoseValue pose, int index);
+    void setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index);
     void emulateMouse(Hand* hand, float click, float shift, int index);
 
     // Various helper functions called during update()
diff --git a/interface/src/InputPlugins.h b/interface/src/InputPlugins.h
index 14ed808df4..ce1beeb708 100644
--- a/interface/src/InputPlugins.h
+++ b/interface/src/InputPlugins.h
@@ -7,6 +7,8 @@
 //
 #pragma once
 
+#include <plugins/PluginContainer.h>
+
 class InputPlugin;
 
 #include <QVector>
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index bb1f6e6528..9c89db4353 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -464,26 +464,17 @@ Menu::Menu() {
     addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
     addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandMouseInput, 0, true);
     addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandLasers, 0, false);
+    addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::LowVelocityFilter, 0, true,
+                                           qApp, SLOT(setLowVelocityFilter(bool)));
     addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false);
 
     MenuWrapper* sixenseOptionsMenu = handOptionsMenu->addMenu("Sixense");
-    addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu,
-                                           MenuOption::SixenseEnabled,
-                                           0, false,
-                                           &SixenseManager::getInstance(),
-                                           SLOT(toggleSixense(bool)));
     addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu,
                                            MenuOption::FilterSixense,
                                            0,
                                            true,
                                            &SixenseManager::getInstance(),
                                            SLOT(setFilter(bool)));
-    addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu,
-                                           MenuOption::LowVelocityFilter,
-                                           0,
-                                           true,
-                                           qApp,
-                                           SLOT(setLowVelocityFilter(bool)));
 
     MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion");
     addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false);
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 8cafc152f4..a1c0a0a512 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -181,8 +181,9 @@ void PreferencesDialog::loadPreferences() {
     ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationCompositor().getHmdUIAngularSize());
 #endif
 
-    SixenseManager& sixense = SixenseManager::getInstance();
     ui.sixenseReticleMoveSpeedSpin->setValue(InputDevice::getReticleMoveSpeed());
+
+    SixenseManager& sixense = SixenseManager::getInstance();
     ui.invertSixenseButtonsCheckBox->setChecked(sixense.getInvertButtons());
 
     // LOD items
diff --git a/libraries/input-plugins/src/input-plugins/InputDevice.cpp b/libraries/input-plugins/src/input-plugins/InputDevice.cpp
index 8f0f2449ca..057fb7ddf1 100644
--- a/libraries/input-plugins/src/input-plugins/InputDevice.cpp
+++ b/libraries/input-plugins/src/input-plugins/InputDevice.cpp
@@ -7,6 +7,8 @@
 //
 #include "InputDevice.h"
 
+bool InputDevice::_lowVelocityFilter = false;
+
 const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
 float InputDevice::reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
 
diff --git a/libraries/input-plugins/src/input-plugins/InputDevice.h b/libraries/input-plugins/src/input-plugins/InputDevice.h
index 4776766312..17f28c1bd8 100644
--- a/libraries/input-plugins/src/input-plugins/InputDevice.h
+++ b/libraries/input-plugins/src/input-plugins/InputDevice.h
@@ -34,7 +34,7 @@ public:
 
     // Update call MUST be called once per simulation loop
     // It takes care of updating the action states and deltas
-    virtual void update(float deltaTime) = 0;
+    virtual void update(float deltaTime, bool jointsCaptured) = 0;
 
     virtual void focusOutEvent() = 0;
 
@@ -44,6 +44,11 @@ public:
     static float getReticleMoveSpeed() { return reticleMoveSpeed; }
     static void setReticleMoveSpeed(float sixenseReticleMoveSpeed) { reticleMoveSpeed = sixenseReticleMoveSpeed; }
 
+    static bool getLowVelocityFilter() { return _lowVelocityFilter; };
+
+public slots:
+    static void setLowVelocityFilter(bool newLowVelocityFilter) { _lowVelocityFilter = newLowVelocityFilter; };
+
 protected:
     int _deviceID = 0;
 
@@ -53,6 +58,8 @@ protected:
     AxisStateMap _axisStateMap;
     PoseStateMap _poseStateMap;
 
+    static bool _lowVelocityFilter;
+
 private:
     static float reticleMoveSpeed;
 };
\ No newline at end of file
diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.h b/libraries/input-plugins/src/input-plugins/InputPlugin.h
index 776ece8b8a..d12ba4652f 100644
--- a/libraries/input-plugins/src/input-plugins/InputPlugin.h
+++ b/libraries/input-plugins/src/input-plugins/InputPlugin.h
@@ -15,6 +15,6 @@ public:
 
     virtual void pluginFocusOutEvent() = 0;
 
-    virtual void pluginUpdate(float deltaTime) = 0;
+    virtual void pluginUpdate(float deltaTime, bool jointsCaptured) = 0;
 };
 
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp
index a652bee227..a29b74ac40 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.cpp
+++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp
@@ -41,7 +41,7 @@ void Joystick::closeJoystick() {
 #endif
 }
 
-void Joystick::update(float deltaTime) {
+void Joystick::update(float deltaTime, bool jointsCaptured) {
     for (auto axisState : _axisStateMap) {
         if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
             _axisStateMap[axisState.first] = 0.0f;
diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h
index f8f98ca661..d78aef34d6 100644
--- a/libraries/input-plugins/src/input-plugins/Joystick.h
+++ b/libraries/input-plugins/src/input-plugins/Joystick.h
@@ -49,7 +49,7 @@ public:
     // Device functions
     virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
     virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
-    virtual void update(float deltaTime) override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
     
     Joystick() : InputDevice("Joystick") {}
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
index 66751cc542..a6edfc392d 100644
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp
@@ -13,7 +13,7 @@
 
 const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse";
 
-void KeyboardMouseDevice::update(float deltaTime) {
+void KeyboardMouseDevice::update(float deltaTime, bool jointsCaptured) {
     _axisStateMap.clear();
 
     // For touch event, we need to check that the last event is not too long ago
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
index 727920630b..85f9c3679e 100644
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
@@ -65,12 +65,12 @@ public:
     virtual void deactivate() override {};
 
     virtual void pluginFocusOutEvent() override { focusOutEvent(); }
-    virtual void pluginUpdate(float deltaTime) override { update(deltaTime); }
+    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 update(float deltaTime) override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
  
     void keyPressEvent(QKeyEvent* event);
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
index c5e56457b3..e8cae6be54 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp
@@ -89,12 +89,12 @@ void SDL2Manager::pluginFocusOutEvent() {
 #endif
 }
 
-void SDL2Manager::pluginUpdate(float deltaTime) {
+void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) {
 #ifdef HAVE_SDL2
     if (_isInitialized) {
         auto userInputMapper = DependencyManager::get<UserInputMapper>();
         for (auto joystick : _openJoysticks) {
-            joystick->update(deltaTime);
+            joystick->update(deltaTime, jointsCaptured);
         }
         
         PerformanceTimer perfTimer("SDL2Manager::update");
diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.h b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
index 123f8dc910..62b3f60d47 100644
--- a/libraries/input-plugins/src/input-plugins/SDL2Manager.h
+++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.h
@@ -38,7 +38,7 @@ public:
     virtual void deactivate() override {};
     
     virtual void pluginFocusOutEvent() override;
-    virtual void pluginUpdate(float deltaTime) override;
+    virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override;
     
 signals:
     void joystickAdded(Joystick* joystick);
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index d762d06558..8a535d636f 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -61,8 +61,6 @@ SixenseManager::SixenseManager() :
 #if defined(HAVE_SIXENSE) && defined(__APPLE__)
     _sixenseLibrary(NULL),
 #endif
-    _isInitialized(false),
-    _isEnabled(true),
     _hydrasConnected(false)
 {
 
@@ -76,59 +74,50 @@ bool SixenseManager::isSupported() const {
 #endif
 }
 
-void SixenseManager::init() {
+void SixenseManager::activate(PluginContainer* container) {
 #ifdef HAVE_SIXENSE
-
-    if (!_isInitialized) {
-        _lowVelocityFilter = false;
-        _calibrationState = CALIBRATION_STATE_IDLE;
-        // By default we assume the _neckBase (in orb frame) is as high above the orb
-        // as the "torso" is below it.
-        _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);
+    _calibrationState = CALIBRATION_STATE_IDLE;
+    // By default we assume the _neckBase (in orb frame) is as high above the orb
+    // as the "torso" is below it.
+    _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);
 
 #ifdef __APPLE__
 
-        if (!_sixenseLibrary) {
+    if (!_sixenseLibrary) {
 
 #ifdef SIXENSE_LIB_FILENAME
-            _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME);
+        _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME);
 #else
-            const QString SIXENSE_LIBRARY_NAME = "libsixense_x64";
-            QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/"
-                + SIXENSE_LIBRARY_NAME;
+        const QString SIXENSE_LIBRARY_NAME = "libsixense_x64";
+        QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/"
+            + SIXENSE_LIBRARY_NAME;
 
-            _sixenseLibrary = new QLibrary(frameworkSixenseLibrary);
+        _sixenseLibrary = new QLibrary(frameworkSixenseLibrary);
 #endif
-        }
-
-        if (_sixenseLibrary->load()){
-            qCDebug(interfaceapp) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName();
-        } else {
-            qCDebug(interfaceapp) << "Sixense library at" << _sixenseLibrary->fileName() << "failed to load."
-                << "Continuing without hydra support.";
-            return;
-        }
-
-        SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit");
-#endif
-        sixenseInit();
-
-        _isInitialized = true;
     }
 
+    if (_sixenseLibrary->load()){
+        qCDebug(interfaceapp) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName();
+    } else {
+        qCDebug(interfaceapp) << "Sixense library at" << _sixenseLibrary->fileName() << "failed to load."
+            << "Continuing without hydra support.";
+        return;
+    }
+
+    SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit");
+#endif
+    sixenseInit();
 #endif
 }
 
 void SixenseManager::deinit() {
 #ifdef HAVE_SIXENSE_
 
-    if (_isInitialized) {
 #ifdef __APPLE__
-        SixenseBaseFunction sixenseExit = (SixenseBaseFunction)_sixenseLibrary->resolve("sixenseExit");
+    SixenseBaseFunction sixenseExit = (SixenseBaseFunction)_sixenseLibrary->resolve("sixenseExit");
 #endif
 
-        sixenseExit();
-    }
+    sixenseExit();
 
 #ifdef __APPLE__
     delete _sixenseLibrary;
@@ -139,141 +128,101 @@ void SixenseManager::deinit() {
 
 void SixenseManager::setFilter(bool filter) {
 #ifdef HAVE_SIXENSE
-
-    if (_isInitialized) {
 #ifdef __APPLE__
-        SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled");
+    SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled");
 #endif
-
-        if (filter) {
-            sixenseSetFilterEnabled(1);
-        } else {
-            sixenseSetFilterEnabled(0);
-        }
-    }
-
+    int newFilter = filter ? 1 : 0;
+    sixenseSetFilterEnabled(newFilter);
 #endif
 }
 
-void SixenseManager::update(float deltaTime) {
+void SixenseManager::update(float deltaTime, bool jointsCaptured) {
 #ifdef HAVE_SIXENSE
-    //Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
-    if (_isInitialized && _isEnabled) {
-        _buttonPressedMap.clear();
+    _buttonPressedMap.clear();
 
 #ifdef __APPLE__
-        SixenseBaseFunction sixenseGetNumActiveControllers =
-        (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");
+    SixenseBaseFunction sixenseGetNumActiveControllers =
+    (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");
 #endif
 
-        auto userInputMapper = DependencyManager::get<UserInputMapper>();
+    auto userInputMapper = DependencyManager::get<UserInputMapper>();
 
-        if (sixenseGetNumActiveControllers() == 0) {
-            _hydrasConnected = false;
-            if (_deviceID != 0) {
-                userInputMapper->removeDevice(_deviceID);
-                _deviceID = 0;
+    if (sixenseGetNumActiveControllers() == 0) {
+        _hydrasConnected = false;
+        if (_deviceID != 0) {
+            userInputMapper->removeDevice(_deviceID);
+            _deviceID = 0;
+            _poseStateMap.clear();
+        }
+        return;
+    }
+
+    PerformanceTimer perfTimer("sixense");
+    if (!_hydrasConnected) {
+        _hydrasConnected = true;
+        registerToUserInputMapper(*userInputMapper);
+        assignDefaultInputMapping(*userInputMapper);
+        UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
+    }
+
+#ifdef __APPLE__
+    SixenseBaseFunction sixenseGetMaxControllers =
+    (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers");
+#endif
+
+    int maxControllers = sixenseGetMaxControllers();
+
+    // we only support two controllers
+    sixenseControllerData controllers[2];
+
+#ifdef __APPLE__
+    SixenseTakeIntFunction sixenseIsControllerEnabled =
+    (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled");
+
+    SixenseTakeIntAndSixenseControllerData sixenseGetNewestData =
+    (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData");
+#endif
+
+    int numActiveControllers = 0;
+    for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) {
+        if (!sixenseIsControllerEnabled(i)) {
+            continue;
+        }
+        sixenseControllerData* data = controllers + numActiveControllers;
+        ++numActiveControllers;
+        sixenseGetNewestData(i, data);
+
+        // 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;
+            
+        // 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);
+
+            //  Rotation of Palm
+            glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]);
+            rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation;
+
+            if (!jointsCaptured) {
+                handlePoseEvent(position, rotation, numActiveControllers - 1);
+            } else {
                 _poseStateMap.clear();
             }
-            return;
+        } else {
+            _poseStateMap[(numActiveControllers - 1) == 0 ? LEFT_HAND : RIGHT_HAND] = UserInputMapper::PoseValue();
         }
-
-        PerformanceTimer perfTimer("sixense");
-        if (!_hydrasConnected) {
-            _hydrasConnected = true;
-            registerToUserInputMapper(*userInputMapper);
-            getInstance().assignDefaultInputMapping(*userInputMapper);
-            UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
-        }
-
-#ifdef __APPLE__
-        SixenseBaseFunction sixenseGetMaxControllers =
-        (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers");
-#endif
-
-        int maxControllers = sixenseGetMaxControllers();
-
-        // we only support two controllers
-        sixenseControllerData controllers[2];
-
-#ifdef __APPLE__
-        SixenseTakeIntFunction sixenseIsControllerEnabled =
-        (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled");
-
-        SixenseTakeIntAndSixenseControllerData sixenseGetNewestData =
-        (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData");
-#endif
-        int numControllersAtBase = 0;
-        int numActiveControllers = 0;
-        for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) {
-            if (!sixenseIsControllerEnabled(i)) {
-                continue;
-            }
-            sixenseControllerData* data = controllers + numActiveControllers;
-            ++numActiveControllers;
-            sixenseGetNewestData(i, data);
-
-            //  Set palm position and normal based on Hydra position/orientation
-
-//            // Either find a palm matching the sixense controller, or make a new one
-//            PalmData* palm;
-//            bool foundHand = false;
-//            for (size_t j = 0; j < hand->getNumPalms(); j++) {
-//                if (hand->getPalms()[j].getSixenseID() == data->controller_index) {
-//                    palm = &(hand->getPalms()[j]);
-//                    _prevPalms[numActiveControllers - 1] = palm;
-//                    foundHand = true;
-//                }
-//            }
-//            if (!foundHand) {
-//                PalmData newPalm(hand);
-//                hand->getPalms().push_back(newPalm);
-//                palm = &(hand->getPalms()[hand->getNumPalms() - 1]);
-//                palm->setSixenseID(data->controller_index);
-//                _prevPalms[numActiveControllers - 1] = palm;
-//                qCDebug(interfaceapp, "Found new Sixense controller, ID %i", data->controller_index);
-//            }
-            // 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;
             
-            // 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);
-
-                //  Rotation of Palm
-                glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]);
-                rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation;
-
-                handlePoseEvent(position, rotation, numActiveControllers - 1);
-            }
-
-//            // Disable the hands (and return to default pose) if both controllers are at base station
-//            if (foundHand) {
-//                palm->setActive(!_controllersAtBase);
-//            } else {
-//                palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive
-//            }
-
 //            //  Read controller buttons and joystick into the hand
 //            palm->setControllerButtons(data->buttons);
 //            palm->setTrigger(data->trigger);
 //            palm->setJoystick(data->joystick_x, data->joystick_y);
+    }
 
-            //handleButtonEvent(data->buttons, numActiveControllers - 1);
-            //handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1);
-
-//            // Emulate the mouse so we can use scripts
-//            if (Menu::getInstance()->isOptionChecked(MenuOption::HandMouseInput) && !_controllersAtBase) {
-//                emulateMouse(palm, numActiveControllers - 1);
-//            }
-        }
-
-        if (numActiveControllers == 2) {
-            updateCalibration(controllers);
-        }
+    if (numActiveControllers == 2) {
+        updateCalibration(controllers);
     }
     
     for (auto axisState : _axisStateMap) {
@@ -284,15 +233,6 @@ void SixenseManager::update(float deltaTime) {
 #endif  // HAVE_SIXENSE
 }
 
-void SixenseManager::toggleSixense(bool shouldEnable) {
-    if (shouldEnable && !isInitialized()) {
-        init();
-        //setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense));
-        //setLowVelocityFilter(Menu::getInstance()->isOptionChecked(MenuOption::LowVelocityFilter));
-    }
-    setIsEnabled(shouldEnable);
-}
-
 #ifdef HAVE_SIXENSE
 
 // the calibration sequence is:
@@ -483,56 +423,10 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int
     neck.y = 0.0f;
     position = _orbRotation * (position - neck);
     
-//    //  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
-    
     // adjustment for hydra controllers fit into hands
     float sign = (index == 0) ? -1.0f : 1.0f;
     rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.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 (_lowVelocityFilter) {
-//        //  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);
-//    } else {
-//        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, 0.0f, FINGER_LENGTH);
-//    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);
-    
     _poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation);
 #endif // HAVE_SIXENSE
 }
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index fd18b77148..37b0acd51e 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -62,24 +62,19 @@ public:
     virtual bool isJointController() const override { return true; }
     const QString& getName() const { return NAME; }
 
-    virtual void init() override;
     virtual void deinit() override;
-    virtual void activate(PluginContainer * container) override {};
-    virtual void deactivate() override { _poseStateMap.clear(); };
+    virtual void activate(PluginContainer * container) override;
+    virtual void deactivate() override { _poseStateMap.clear(); }
 
     virtual void pluginFocusOutEvent() override { focusOutEvent(); }
-    virtual void pluginUpdate(float deltaTime) override { update(deltaTime); }
+    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 update(float deltaTime) override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
-    bool isInitialized() const { return _isInitialized; }
-    
-    void setIsEnabled(bool isEnabled) { _isEnabled = isEnabled; }
-    
     bool getInvertButtons() const { return _invertButtons; }
     void setInvertButtons(bool invertSixenseButtons) { _invertButtons = invertSixenseButtons; }
     
@@ -88,9 +83,7 @@ public:
     UserInputMapper::Input makeInput(JointChannel joint);
     
 public slots:
-    void toggleSixense(bool shouldEnable);
     void setFilter(bool filter);
-    void setLowVelocityFilter(bool lowVelocityFilter) { _lowVelocityFilter = lowVelocityFilter; };
 
 private:    
     void handleButtonEvent(unsigned int buttons, int index);
@@ -122,11 +115,7 @@ private:
 #endif
     
 #endif
-    bool _isInitialized;
-    bool _isEnabled;
     bool _hydrasConnected;
-    
-    bool _lowVelocityFilter;
 
     bool _invertButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS;
 
diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
index b8aa52a508..fc959650ba 100755
--- a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
+++ b/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp
@@ -192,7 +192,9 @@ void UserInputMapper::update(float deltaTime) {
                     break;
                 }
                 case ChannelType::POSE: {
-                    _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
+                    if (!_poseStates[channelInput.first].isValid()) {
+                        _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
+                    }
                     break;
                 }
                 default: {
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index f81e058b1e..825eb96789 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -186,7 +186,8 @@ void ViveControllerManager::renderHand(UserInputMapper::PoseValue pose, gpu::Bat
     batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
 }
 
-void ViveControllerManager::update(float deltaTime) {
+void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
+    _poseStateMap.clear();
     // TODO: This shouldn't be necessary
     if (!_hmd) {
         return;
@@ -216,8 +217,10 @@ void ViveControllerManager::update(float deltaTime) {
         numTrackedControllers++;
             
         const mat4& mat = _trackedDevicePoseMat4[device];
-                        
-        handlePoseEvent(mat, numTrackedControllers - 1);
+                  
+        if (!jointsCaptured) {
+            handlePoseEvent(mat, numTrackedControllers - 1);
+        }
             
         // handle inputs
         vr::VRControllerState_t controllerState = vr::VRControllerState_t();
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
index 81f8d0d729..9ba90a5ca8 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h
@@ -59,12 +59,12 @@ public:
     virtual void deactivate() override;
 
     virtual void pluginFocusOutEvent() override { focusOutEvent(); }
-    virtual void pluginUpdate(float deltaTime) override { update(deltaTime); }
+    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 update(float deltaTime) override;
+    virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
     void updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges);
diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h
index 937c4e99e4..a72e5d1c8d 100644
--- a/libraries/plugins/src/plugins/PluginContainer.h
+++ b/libraries/plugins/src/plugins/PluginContainer.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <QString>
+#include <functional>
 
 class GlWindow;