From 2e9a8e2b33689bf483c8bcb1d9ec63f0ca7abd2d Mon Sep 17 00:00:00 2001
From: David Rowe <david@ctrlaltstudio.com>
Date: Sat, 27 Jun 2020 15:14:21 +1200
Subject: [PATCH] Add option to enable Vive PRO Eye eye tracking

---
 .../qml/hifi/tablet/OpenVrConfiguration.qml   | 77 ++++++++++++++++++-
 plugins/openvr/src/ViveControllerManager.cpp  | 12 ++-
 plugins/openvr/src/ViveControllerManager.h    |  1 +
 3 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml
index a9d67fec35..3690dc3f4a 100644
--- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml
+++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml
@@ -71,6 +71,7 @@ Flickable {
 
             property int state: buttonState.disabled
             property var lastConfiguration:  null
+            property bool isConfiguring: false
 
             HifiConstants { id: hifi }
 
@@ -840,9 +841,72 @@ Flickable {
                 }
             }
 
+
+            HifiControls.CheckBox {
+                id: eyeTracking
+                width: 15
+                height: 15
+                boxRadius: 7
+
+                anchors.top: viveInDesktop.bottom
+                anchors.topMargin: 5
+                anchors.left: openVrConfiguration.left
+                anchors.leftMargin: leftMargin + 10
+
+                onClicked: {
+                    sendConfigurationSettings();
+                }
+            }
+
+            RalewayBold {
+                id: eyeTrackingLabel
+                size: 12
+                text: "Use eye tracking (if available)."
+                color: hifi.colors.lightGrayText
+                anchors {
+                    left: eyeTracking.right
+                    leftMargin: 5
+                    verticalCenter: eyeTracking.verticalCenter
+                }
+            }
+
+            RalewayRegular {
+                id: privacyStatement
+                text: "Privacy Statement"
+                color: hifi.colors.blueHighlight
+                size: 12
+                anchors {
+                    left: eyeTrackingLabel.right
+                    leftMargin: 10
+                    verticalCenter: eyeTrackingLabel.verticalCenter
+                }
+
+                Rectangle {
+                    id: privacyStatementUnderline
+                    color: hifi.colors.blueHighlight
+                    width: privacyStatement.width
+                    height: 1
+                    anchors {
+                        top: privacyStatement.bottom
+                        topMargin: 1
+                        left: privacyStatement.left
+                    }
+                    visible: false
+                }
+
+                MouseArea {
+                    anchors.fill: parent;
+                    hoverEnabled: true
+                    onEntered: privacyStatementUnderline.visible = true;
+                    onExited: privacyStatementUnderline.visible = false;
+                    onClicked: HiFiAbout.openUrl("https://vircadia.com/");  // FIXME: URL for privacy statement.
+                }
+            }
+
+
             Row {
                 id: outOfRangeDataStrategyRow
-                anchors.top: viveInDesktop.bottom
+                anchors.top: eyeTracking.bottom
                 anchors.topMargin: 5
                 anchors.left: openVrConfiguration.left
                 anchors.leftMargin: leftMargin + 10
@@ -966,6 +1030,8 @@ Flickable {
             }
 
             function displayConfiguration() {
+                isConfiguring = true;
+
                 var settings = InputConfiguration.configurationSettings(openVrConfiguration.pluginName);
                 var configurationType = settings["trackerConfiguration"];
                 displayTrackerConfiguration(configurationType);
@@ -982,6 +1048,7 @@ Flickable {
                 var viveController = settings["handController"];
                 var desktopMode = settings["desktopMode"];
                 var hmdDesktopPosition = settings["hmdDesktopTracking"];
+                var eyeTrackingEnabled = settings["eyeTrackingEnabled"];
 
                 armCircumference.realValue = settings.armCircumference;
                 shoulderWidth.realValue = settings.shoulderWidth;
@@ -1004,6 +1071,7 @@ Flickable {
 
                 viveInDesktop.checked = desktopMode;
                 hmdInDesktop.checked = hmdDesktopPosition;
+                eyeTracking.checked = eyeTrackingEnabled;
                 outOfRangeDataStrategyComboBox.currentIndex = outOfRangeDataStrategyComboBox.model.indexOf(settings.outOfRangeDataStrategy);
 
                 initializeButtonState();
@@ -1014,6 +1082,8 @@ Flickable {
                 };
 
                 UserActivityLogger.logAction("mocap_ui_open_dialog", data);
+
+                isConfiguring = false;
             }
 
             function displayTrackerConfiguration(type) {
@@ -1170,6 +1240,7 @@ Flickable {
                     "shoulderWidth": shoulderWidth.realValue,
                     "desktopMode": viveInDesktop.checked,
                     "hmdDesktopTracking": hmdInDesktop.checked,
+                    "eyeTrackingEnabled": eyeTracking.checked,
                     "outOfRangeDataStrategy": outOfRangeDataStrategyComboBox.model[outOfRangeDataStrategyComboBox.currentIndex]
                 }
 
@@ -1177,6 +1248,10 @@ Flickable {
             }
 
             function sendConfigurationSettings() {
+                if (isConfiguring) {
+                    // Ignore control value changes during dialog initialization.
+                    return;
+                }
                 var settings = composeConfigurationSettings();
                 InputConfiguration.setConfigurationSettings(settings, openVrConfiguration.pluginName);
                 updateCalibrationButton();
diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp
index a2312b3247..a47d7218e2 100644
--- a/plugins/openvr/src/ViveControllerManager.cpp
+++ b/plugins/openvr/src/ViveControllerManager.cpp
@@ -279,6 +279,10 @@ void ViveControllerManager::setConfigurationSettings(const QJsonObject configura
             _hmdDesktopTracking = configurationSettings["hmdDesktopTracking"].toBool();
         }
 
+        if (configurationSettings.contains("eyeTrackingEnabled")) {
+            _eyeTrackingEnabled = configurationSettings["eyeTrackingEnabled"].toBool();
+        }
+
         _inputDevice->configureCalibrationSettings(configurationSettings);
         saveSettings();
     }
@@ -289,6 +293,7 @@ QJsonObject ViveControllerManager::configurationSettings() {
         QJsonObject configurationSettings = _inputDevice->configurationSettings();
         configurationSettings["desktopMode"] = _desktopMode;
         configurationSettings["hmdDesktopTracking"] = _hmdDesktopTracking;
+        configurationSettings["eyeTrackingEnabled"] = _eyeTrackingEnabled;
         return configurationSettings;
     }
 
@@ -801,7 +806,7 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
         _registeredWithInputMapper = true;
     }
 
-    if (_viveProEye) {
+    if (_viveProEye && _eyeTrackingEnabled) {
         updateEyeTracker(deltaTime, inputCalibrationData);
     }
 
@@ -821,6 +826,9 @@ void ViveControllerManager::loadSettings() {
             _inputDevice->_shoulderWidth = settings.value("shoulderWidth", QVariant(DEFAULT_SHOULDER_WIDTH)).toDouble();
             _inputDevice->_outOfRangeDataStrategy = stringToOutOfRangeDataStrategy(settings.value("outOfRangeDataStrategy", QVariant(DEFAULT_OUT_OF_RANGE_STRATEGY)).toString());
         }
+
+        const bool DEFAULT_EYE_TRACKING_ENABLED = false;
+        _eyeTrackingEnabled = settings.value("eyeTrackingEnabled", QVariant(DEFAULT_EYE_TRACKING_ENABLED)).toBool();
     }
     settings.endGroup();
 }
@@ -835,6 +843,8 @@ void ViveControllerManager::saveSettings() const {
             settings.setValue(QString("shoulderWidth"), _inputDevice->_shoulderWidth);
             settings.setValue(QString("outOfRangeDataStrategy"), outOfRangeDataStrategyToString(_inputDevice->_outOfRangeDataStrategy));
         }
+
+        settings.setValue(QString("eyeTrackingEnabled"), _eyeTrackingEnabled);
     }
     settings.endGroup();
 }
diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h
index 714be87842..f2eaa3fbff 100644
--- a/plugins/openvr/src/ViveControllerManager.h
+++ b/plugins/openvr/src/ViveControllerManager.h
@@ -253,6 +253,7 @@ private:
     std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_system) };
 
     bool _viveProEye { false };
+    bool _eyeTrackingEnabled { false };
     std::shared_ptr<ViveProEyeReadThread> _viveProEyeReadThread;
     EyeDataBuffer _prevEyeData;