diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 70cc189ad6..5f61c6d978 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2351,6 +2351,7 @@ void Application::saveSettings() {
 
     Menu::getInstance()->saveSettings();
     getMyAvatar()->saveData();
+    PluginManager::getInstance()->saveSettings();
 }
 
 bool Application::importEntities(const QString& urlOrFilename) {
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index f90bac234d..4ba248c76c 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -200,9 +200,6 @@ void PreferencesDialog::loadPreferences() {
 
     ui.sixenseReticleMoveSpeedSpin->setValue(InputDevice::getReticleMoveSpeed());
 
-    SixenseManager& sixense = SixenseManager::getInstance();
-    ui.invertSixenseButtonsCheckBox->setChecked(sixense.getInvertButtons());
-
     // LOD items
     auto lodManager = DependencyManager::get<LODManager>();
     ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS());
@@ -276,9 +273,7 @@ void PreferencesDialog::savePreferences() {
 
     qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
     
-    SixenseManager& sixense = SixenseManager::getInstance();
     InputDevice::setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
-    sixense.setInvertButtons(ui.invertSixenseButtonsCheckBox->isChecked());
 
     auto audio = DependencyManager::get<AudioClient>();
     MixedProcessedAudioStream& stream = audio->getReceivedAudioStream();
diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui
index 53b71fb507..a1137a2bf2 100644
--- a/interface/ui/preferencesDialog.ui
+++ b/interface/ui/preferencesDialog.ui
@@ -2768,40 +2768,6 @@
          </property>
         </widget>
        </item>
-       <item>
-        <layout class="QHBoxLayout" name="horizontalLayout_26">
-         <property name="topMargin">
-          <number>7</number>
-         </property>
-         <property name="bottomMargin">
-          <number>7</number>
-         </property>
-         <item>
-          <widget class="QCheckBox" name="invertSixenseButtonsCheckBox">
-           <property name="baseSize">
-            <size>
-             <width>0</width>
-             <height>40</height>
-            </size>
-           </property>
-           <property name="font">
-            <font>
-             <family>Arial</family>
-            </font>
-           </property>
-           <property name="text">
-            <string>Invert Mouse Buttons</string>
-           </property>
-           <property name="iconSize">
-            <size>
-             <width>0</width>
-             <height>0</height>
-            </size>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
        <item>
         <layout class="QHBoxLayout" name="horizontalLayout_16">
          <property name="spacing">
diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
index ea1639ec66..227bd12e1b 100644
--- a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
+++ b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
@@ -37,3 +37,9 @@ InputPluginList getInputPlugins() {
     }
     return result;
 }
+
+void saveInputPluginSettings(const InputPluginList& plugins) {
+    foreach (auto inputPlugin, plugins) {
+        inputPlugin->saveSettings();
+    }
+}
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index e900e8779e..bc64ec4ccc 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -16,6 +16,7 @@
 #include <GLMHelpers.h>
 #include <NumericalConstants.h>
 #include <PerfStat.h>
+#include <SettingHandle.h>
 #include <plugins/PluginContainer.h>
 
 #include "NumericalConstants.h"
@@ -38,7 +39,7 @@ const unsigned int RIGHT_MASK = 1U << 1;
 #ifdef HAVE_SIXENSE
 
 const int CALIBRATION_STATE_IDLE = 0;
-const int CALIBRATION_STATE_X = 1;
+const int CALIBRATION_STATE_IN_PROGRESS = 1;
 const int CALIBRATION_STATE_COMPLETE = 2;
 
 const glm::vec3 DEFAULT_AVATAR_POSITION(-0.25f, -0.35f, -0.3f); // in hydra frame
@@ -56,25 +57,23 @@ typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData
 #endif
 
 const QString SixenseManager::NAME = "Sixense";
+const QString SixenseManager::HYDRA_ID_STRING = "Razer Hydra";
 
 const QString MENU_PARENT = "Avatar";
 const QString MENU_NAME = "Sixense";
 const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
 const QString TOGGLE_SMOOTH = "Smooth Sixense Movement";
+const float DEFAULT_REACH_LENGTH = 1.5f;
 
-SixenseManager& SixenseManager::getInstance() {
-    static SixenseManager sharedInstance;
-    return sharedInstance;
-}
 
 SixenseManager::SixenseManager() :
     InputDevice("Hydra"),
 #ifdef __APPLE__
     _sixenseLibrary(NULL),
 #endif
+    _reachLength(DEFAULT_REACH_LENGTH),
     _hydrasConnected(false)
 {
-
 }
 
 bool SixenseManager::isSupported() const {
@@ -92,7 +91,7 @@ void SixenseManager::activate() {
 
     CONTAINER->addMenu(MENU_PATH);
     CONTAINER->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
-                           [this] (bool clicked) { this->setFilter(clicked); },
+                           [this] (bool clicked) { this->setSixenseFilter(clicked); },
                            true, true);
 
 #ifdef __APPLE__
@@ -120,6 +119,7 @@ void SixenseManager::activate() {
 
     SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit");
 #endif
+    loadSettings();
     sixenseInit();
 #endif
 }
@@ -144,7 +144,7 @@ void SixenseManager::deactivate() {
 #endif
 }
 
-void SixenseManager::setFilter(bool filter) {
+void SixenseManager::setSixenseFilter(bool filter) {
 #ifdef HAVE_SIXENSE
 #ifdef __APPLE__
     SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled");
@@ -282,6 +282,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
                 glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft);
                 glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, Vectors::UNIT_Y));
                 xAxis = glm::normalize(glm::cross(Vectors::UNIT_Y, zAxis));
+                _reachLength = glm::dot(xAxis, _reachRight - _reachLeft);
                 _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;
@@ -317,7 +318,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
             _lastDistance = reach;
             _lockExpiry = usecTimestampNow() + LOCK_DURATION;
             // move to next state
-            _calibrationState = CALIBRATION_STATE_X;
+            _calibrationState = CALIBRATION_STATE_IN_PROGRESS;
         }
         return;
     }
@@ -327,7 +328,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
     _averageLeft = 0.9f * _averageLeft + 0.1f * positionLeft;
     _averageRight = 0.9f * _averageRight + 0.1f * positionRight;
 
-    if (_calibrationState == CALIBRATION_STATE_X) {
+    if (_calibrationState == CALIBRATION_STATE_IN_PROGRESS) {
         // compute new sliding average
         float distance = glm::distance(_averageLeft, _averageRight);
         if (fabsf(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) {
@@ -340,7 +341,6 @@ void SixenseManager::updateCalibration(void* controllersX) {
             // lock has expired so clamp the data and move on
             _lockExpiry = now + LOCK_DURATION;
             _lastDistance = 0.0f;
-            _reachUp = 0.5f * (_reachLeft + _reachRight);
             _calibrationState = CALIBRATION_STATE_COMPLETE;
             qCDebug(inputplugins, "success: sixense calibration: left");
         }
@@ -543,6 +543,31 @@ void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
 
 }
 
+// virtual
+void SixenseManager::saveSettings() const {
+    Settings settings;
+    QString idString = getID();
+    settings.beginGroup(idString);
+    {
+        settings.setVec3Value(QString("avatarPosition"), _avatarPosition);
+        settings.setQuatValue(QString("avatarRotation"), _avatarRotation);
+        settings.setValue(QString("reachLength"), QVariant(_reachLength));
+    }
+    settings.endGroup();
+}
+
+void SixenseManager::loadSettings() {
+    Settings settings;
+    QString idString = getID();
+    settings.beginGroup(idString);
+    {
+        settings.getVec3ValueIfValid(QString("avatarPosition"), _avatarPosition);
+        settings.getQuatValueIfValid(QString("avatarRotation"), _avatarRotation);
+        settings.getFloatValueIfValid(QString("reachLength"), _reachLength);
+    }
+    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);
 }
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h
index 5e3815cd20..9fa7f84a86 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.h
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h
@@ -58,12 +58,11 @@ public:
 
     SixenseManager();
     
-    static SixenseManager& getInstance();
-
     // Plugin functions
     virtual bool isSupported() const override;
     virtual bool isJointController() const override { return true; }
     const QString& getName() const override { return NAME; }
+    const QString& getID() const override { return HYDRA_ID_STRING; }
 
     virtual void activate() override;
     virtual void deactivate() override;
@@ -77,15 +76,15 @@ public:
     virtual void update(float deltaTime, bool jointsCaptured) override;
     virtual void focusOutEvent() override;
 
-    bool getInvertButtons() const { return _invertButtons; }
-    void setInvertButtons(bool invertSixenseButtons) { _invertButtons = invertSixenseButtons; }
-    
     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;
+
 public slots:
-    void setFilter(bool filter);
+    void setSixenseFilter(bool filter);
 
 private:    
     void handleButtonEvent(unsigned int buttons, int index);
@@ -99,7 +98,7 @@ private:
     // these are calibration results
     glm::vec3 _avatarPosition; // in hydra-frame
     glm::quat _avatarRotation; // in hydra-frame
-    float _armLength;
+    float _reachLength;
 
     // these are measured values used to compute the calibration results
     quint64 _lockExpiry;
@@ -107,9 +106,8 @@ private:
     glm::vec3 _averageRight;
     glm::vec3 _reachLeft;
     glm::vec3 _reachRight;
-    glm::vec3 _reachUp;
-    glm::vec3 _reachForward;
     float _lastDistance;
+    bool _useSixenseFilter = true;
     
 #ifdef __APPLE__
     QLibrary* _sixenseLibrary;
@@ -117,9 +115,8 @@ private:
     
     bool _hydrasConnected;
 
-    bool _invertButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS;
-
     static const QString NAME;
+    static const QString HYDRA_ID_STRING;
 };
 
 #endif // hifi_SixenseManager_h
diff --git a/libraries/plugins/src/plugins/Plugin.cpp b/libraries/plugins/src/plugins/Plugin.cpp
index ffcc682ebd..2c0b9fa5cf 100644
--- a/libraries/plugins/src/plugins/Plugin.cpp
+++ b/libraries/plugins/src/plugins/Plugin.cpp
@@ -9,6 +9,8 @@
 
 PluginContainer* Plugin::CONTAINER{ nullptr };
 
+QString Plugin::UNKNOWN_PLUGIN_ID("unknown");
+
 void Plugin::setContainer(PluginContainer* container) {
     CONTAINER = container;
 }
diff --git a/libraries/plugins/src/plugins/Plugin.h b/libraries/plugins/src/plugins/Plugin.h
index eac355b47d..68e012b8e1 100644
--- a/libraries/plugins/src/plugins/Plugin.h
+++ b/libraries/plugins/src/plugins/Plugin.h
@@ -7,6 +7,8 @@
 //
 #pragma once
 
+#include <assert.h>
+
 #include <QString>
 #include <QObject>
 
@@ -14,7 +16,12 @@
 
 class Plugin : public QObject {
 public:
+    /// \return human-readable name
     virtual const QString& getName() const = 0;
+
+    /// \return string ID (not necessarily human-readable)
+    virtual const QString& getID() const { assert(false); return UNKNOWN_PLUGIN_ID; }
+
     virtual bool isSupported() const;
     
     static void setContainer(PluginContainer* container);
@@ -37,6 +44,11 @@ public:
      */
     virtual void idle();
 
+    virtual void saveSettings() const {}
+    virtual void loadSettings() {}
+
 protected:
     static PluginContainer* CONTAINER;
+    static QString UNKNOWN_PLUGIN_ID;
+
 };
diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp
index 3a71700c9e..2deb41fb13 100644
--- a/libraries/plugins/src/plugins/PluginManager.cpp
+++ b/libraries/plugins/src/plugins/PluginManager.cpp
@@ -8,6 +8,8 @@
 #include "PluginManager.h"
 #include <mutex>
 
+#include "Forward.h"
+
 PluginManager* PluginManager::getInstance() {
     static PluginManager _manager;
     return &_manager;
@@ -16,6 +18,7 @@ PluginManager* PluginManager::getInstance() {
 // TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
 extern DisplayPluginList getDisplayPlugins();
 extern InputPluginList getInputPlugins();
+extern void saveInputPluginSettings(const InputPluginList& plugins);
 
 const DisplayPluginList& PluginManager::getDisplayPlugins() {
     static DisplayPluginList displayPlugins;
@@ -35,3 +38,6 @@ const InputPluginList& PluginManager::getInputPlugins() {
     return inputPlugins;
 }
 
+void PluginManager::saveSettings() {
+    saveInputPluginSettings(getInputPlugins());
+}
diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h
index b7ec453814..09dcc9d107 100644
--- a/libraries/plugins/src/plugins/PluginManager.h
+++ b/libraries/plugins/src/plugins/PluginManager.h
@@ -15,4 +15,5 @@ public:
 
   const DisplayPluginList& getDisplayPlugins();
   const InputPluginList& getInputPlugins();
+  void saveSettings();
 };
diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp
new file mode 100644
index 0000000000..19239b3cf7
--- /dev/null
+++ b/libraries/shared/src/SettingHandle.cpp
@@ -0,0 +1,83 @@
+//
+//  SettingHandle.h
+//
+//
+//  Created by AndrewMeadows 2015.10.05
+//  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 "SettingHandle.h"
+
+#include <math.h>
+
+
+void Settings::getFloatValueIfValid(const QString& name, float& f) {
+    const QVariant badDefaultValue = NAN;
+    bool ok = true;
+    float tempFloat = value(name, badDefaultValue).toFloat(&ok);
+    if (ok && !isnan(tempFloat)) {
+        f = tempFloat;
+    }
+}
+
+void Settings::getBoolValue(const QString& name, bool& b) {
+    const QVariant defaultValue = false;
+    b = value(name, defaultValue).toBool();
+}
+
+
+void Settings::setVec3Value(const QString& name, const glm::vec3& v) {
+    beginGroup(name);
+    {
+        setValue(QString("x"), v.x);
+        setValue(QString("y"), v.y);
+        setValue(QString("z"), v.z);
+    }
+    endGroup();
+}
+
+void Settings::getVec3ValueIfValid(const QString& name, glm::vec3& v) {
+    beginGroup(name);
+    {
+        bool ok = true;
+        const QVariant badDefaultValue = NAN;
+        float x = value(QString("x"), badDefaultValue).toFloat(&ok);
+        float y = value(QString("y"), badDefaultValue).toFloat(&ok);
+        float z = value(QString("z"), badDefaultValue).toFloat(&ok);
+        if (ok && (!isnan(x) && !isnan(y) && !isnan(z))) {
+            v = glm::vec3(x, y, z);
+        }
+    }
+    endGroup();
+}
+
+void Settings::setQuatValue(const QString& name, const glm::quat& q) {
+    beginGroup(name);
+    {
+        setValue(QString("x"), q.x);
+        setValue(QString("y"), q.y);
+        setValue(QString("z"), q.z);
+        setValue(QString("w"), q.w);
+    }
+    endGroup();
+}
+
+void Settings::getQuatValueIfValid(const QString& name, glm::quat& q) {
+    beginGroup(name);
+    {
+        bool ok = true;
+        const QVariant badDefaultValue = NAN;
+        float x = value(QString("x"), badDefaultValue).toFloat(&ok);
+        float y = value(QString("y"), badDefaultValue).toFloat(&ok);
+        float z = value(QString("z"), badDefaultValue).toFloat(&ok);
+        float w = value(QString("w"), badDefaultValue).toFloat(&ok);
+        if (ok && (!isnan(x) && !isnan(y) && !isnan(z) && !isnan(w))) {
+            q = glm::quat(w, x, y, z);
+        }
+    }
+    endGroup();
+}
+
diff --git a/libraries/shared/src/SettingHandle.h b/libraries/shared/src/SettingHandle.h
index 761e41d321..b86422bcfb 100644
--- a/libraries/shared/src/SettingHandle.h
+++ b/libraries/shared/src/SettingHandle.h
@@ -18,11 +18,22 @@
 #include <QString>
 #include <QVariant>
 
+#include <glm/glm.hpp>
+#include <glm/gtc/quaternion.hpp>
+
 #include "SettingInterface.h"
 
 // TODO: remove
 class Settings : public QSettings {
-    
+public:
+    void getFloatValueIfValid(const QString& name, float& f);
+    void getBoolValue(const QString& name, bool& b);
+
+    void setVec3Value(const QString& name, const glm::vec3& v);
+    void getVec3ValueIfValid(const QString& name, glm::vec3& v);
+
+    void setQuatValue(const QString& name, const glm::quat& q);
+    void getQuatValueIfValid(const QString& name, glm::quat& q);
 };
 
 namespace Setting {
@@ -65,4 +76,4 @@ namespace Setting {
     }
 }
 
-#endif // hifi_SettingHandle_h
\ No newline at end of file
+#endif // hifi_SettingHandle_h