From fdcd667d3c4f54c8958de1c89c9007adf8130582 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 23 May 2016 13:33:42 -0700 Subject: [PATCH 1/2] Fix hand controller pointer after input changes. --- interface/resources/controllers/hydra.json | 8 +- interface/resources/controllers/vive.json | 4 +- .../controllers/handControllerPointer.js | 112 ++++++------------ 3 files changed, 46 insertions(+), 78 deletions(-) diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json index 42237033af..8233685763 100644 --- a/interface/resources/controllers/hydra.json +++ b/interface/resources/controllers/hydra.json @@ -16,8 +16,12 @@ { "from": "Hydra.L0", "to": "Standard.Back" }, { "from": "Hydra.R0", "to": "Standard.Start" }, - { "from": [ "Hydra.L1", "Hydra.L2", "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" }, - { "from": [ "Hydra.R1", "Hydra.R2", "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" }, + { "from": [ "Hydra.L1", "Hydra.L2" ], "to": "Standard.LeftPrimaryThumb" }, + { "from": [ "Hydra.R1", "Hydra.R2" ], "to": "Standard.RightPrimaryThumb" }, + { "from": [ "Hydra.L3" ], "to": "Standard.L3" }, + { "from": [ "Hydra.R3" ], "to": "Standard.R3" }, + { "from": [ "Hydra.R4" ], "to": "Standard.RightSecondaryThumb" }, + { "from": [ "Hydra.L4" ], "to": "Standard.LeftSecondaryThumb" }, { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, { "from": "Hydra.RightHand", "to": "Standard.RightHand" } diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json index 4085d71c27..fec93c9132 100644 --- a/interface/resources/controllers/vive.json +++ b/interface/resources/controllers/vive.json @@ -17,8 +17,8 @@ { "from": "Vive.RS", "to": "Standard.RS" }, { "from": "Vive.RSTouch", "to": "Standard.RSTouch" }, - { "from": "Vive.LeftApplicationMenu", "to": "Standard.Back" }, - { "from": "Vive.RightApplicationMenu", "to": "Standard.Start" }, + { "from": "Vive.LeftApplicationMenu", "to": "Standard.LeftSecondaryThumb" }, + { "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" }, { "from": "Vive.LeftHand", "to": "Standard.LeftHand" }, { "from": "Vive.RightHand", "to": "Standard.RightHand" } diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index f4e4492a88..e7be3af5dd 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -22,10 +22,7 @@ // (For now, the thumb buttons on both controllers are always on.) // When over a HUD element, the reticle is shown where the active hand controller beam intersects the HUD. // Otherwise, the active hand controller shows a red ball where a click will act. -// -// Bugs: -// On Windows, the upper left corner of Interface must be in the upper left corner of the screen, and the title bar must be 50px high. (System bug.) -// While hardware mouse move switches to mouse move, hardware mouse click (without amove) does not. + // UTILITIES ------------- @@ -270,75 +267,43 @@ function toggleHand() { } // Create clickMappings as needed, on demand. -var clickMappings = {}, clickMapping, clickMapToggle; -var hardware; // undefined -function checkHardware() { - var newHardware = Controller.Hardware.Hydra ? 'Hydra' : (Controller.Hardware.Vive ? 'Vive' : null); // not undefined - if (hardware === newHardware) { - return; - } - print('Setting mapping for new controller hardware:', newHardware); - if (clickMapToggle) { - clickMapToggle.setState(false); - } - hardware = newHardware; - if (clickMappings[hardware]) { - clickMapping = clickMappings[hardware]; - } else { - clickMapping = Controller.newMapping(Script.resolvePath('') + '-click-' + hardware); - Script.scriptEnding.connect(clickMapping.disable); - function mapToAction(button, action) { - clickMapping.from(Controller.Hardware[hardware][button]).peek().to(Controller.Actions[action]); - } - function makeHandToggle(button, hand, optionalWhen) { - var whenThunk = optionalWhen || function () { - return true; - }; - function maybeToggle() { - if (activeHand !== Controller.Standard[hand]) { - toggleHand(); - } +var clickMapping = Controller.newMapping(Script.resolvePath('') + '-click'); +Script.scriptEnding.connect(clickMapping.disable); - } - clickMapping.from(Controller.Hardware[hardware][button]).peek().when(whenThunk).to(maybeToggle); - } - function makeViveWhen(click, x, y) { - var viveClick = Controller.Hardware.Vive[click], - viveX = Controller.Standard[x], // Standard after filtering by mapping - viveY = Controller.Standard[y]; - return function () { - var clickValue = Controller.getValue(viveClick); - var xValue = Controller.getValue(viveX); - var yValue = Controller.getValue(viveY); - return clickValue && !xValue && !yValue; - }; - } - switch (hardware) { - case 'Hydra': - makeHandToggle('R3', 'RightHand'); - makeHandToggle('L3', 'LeftHand'); - - mapToAction('R3', 'ReticleClick'); - mapToAction('L3', 'ReticleClick'); - mapToAction('R4', 'ContextMenu'); - mapToAction('L4', 'ContextMenu'); - break; - case 'Vive': - // When touchpad click is NOT treated as movement, treat as left click - makeHandToggle('RS', 'RightHand', makeViveWhen('RS', 'RX', 'RY')); - makeHandToggle('LS', 'LeftHand', makeViveWhen('LS', 'LX', 'LY')); - clickMapping.from(Controller.Hardware.Vive.RS).when(makeViveWhen('RS', 'RX', 'RY')).to(Controller.Actions.ReticleClick); - clickMapping.from(Controller.Hardware.Vive.LS).when(makeViveWhen('LS', 'LX', 'LY')).to(Controller.Actions.ReticleClick); - mapToAction('RightApplicationMenu', 'ContextMenu'); - mapToAction('LeftApplicationMenu', 'ContextMenu'); - break; - } - clickMappings[hardware] = clickMapping; - } - clickMapToggle = new LatchedToggle(clickMapping.enable, clickMapping.disable); - clickMapToggle.setState(true); +// Move these to vive.json +function makeCenterClickWhen(click, x, y) { + var clickKey = Controller.Standard[click], + xKey = Controller.Standard[x], // Standard after filtering by mapping + yKey = Controller.Standard[y]; + return function () { + var clickValue = Controller.getValue(clickKey); + var xValue = Controller.getValue(xKey); + var yValue = Controller.getValue(yKey); + var answer = clickValue && !xValue && !yValue; + return answer; + }; } -checkHardware(); +if (Controller.Hardware.Vive) { + clickMapping.from(Controller.Hardware.Vive.RS).when(makeCenterClickWhen('RS', 'RX', 'RY')).to(Controller.Standard.R3); + clickMapping.from(Controller.Hardware.Vive.LS).when(makeCenterClickWhen('LS', 'LX', 'LY')).to(Controller.Standard.L3); +} + + +clickMapping.from(Controller.Standard.R3).peek().to(Controller.Actions.ReticleClick); +clickMapping.from(Controller.Standard.L3).peek().to(Controller.Actions.ReticleClick); +clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(Controller.Actions.ContextMenu); +clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(Controller.Actions.ContextMenu); +clickMapping.from(Controller.Standard.R3).peek().to(function (on) { + if (on && (activeHand !== Controller.Standard.RightHand)) { + toggleHand(); + } +}); +clickMapping.from(Controller.Standard.L3).peek().to(function (on) { + if (on && (activeHand !== Controller.Standard.LeftHand)) { + toggleHand(); + } +}); +clickMapping.enable(); // VISUAL AID ----------- // Same properties as handControllerGrab search sphere @@ -415,8 +380,8 @@ function update() { return turnOffVisualization(); } var controllerPose = Controller.getPoseValue(activeHand); - // Vive is effectively invalid when not in HMD - if (!controllerPose.valid || ((hardware === 'Vive') && !HMD.active)) { + // Valid if any plugged-in hand controller is "on". (uncradled Hydra, green-lighted Vive...) + if (!controllerPose.valid) { return turnOffVisualization(); } // Controller is cradled. var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation), @@ -458,7 +423,6 @@ Script.scriptEnding.connect(function () { var SETTINGS_CHANGE_RECHECK_INTERVAL = 10 * 1000; // milliseconds function checkSettings() { updateFieldOfView(); - checkHardware(); } checkSettings(); var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL); From a3f1ece978987b203b50e438628b417fdfa1823e Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 24 May 2016 16:10:12 -0700 Subject: [PATCH 2/2] Do button mapping in C++ and simplify vive.json accordingly. Vive and Hydra now use PrimaryThumb and SecondaryThumb. Fix warnings for Neuron. --- interface/resources/controllers/hydra.json | 10 +++---- interface/resources/controllers/neuron.json | 4 +-- interface/resources/controllers/vive.json | 10 ++++--- .../src/controllers/StandardControls.h | 4 +++ plugins/openvr/src/ViveControllerManager.cpp | 22 ++++++++++++++- plugins/openvr/src/ViveControllerManager.h | 1 + .../controllers/handControllerPointer.js | 28 +++---------------- 7 files changed, 42 insertions(+), 37 deletions(-) diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json index 8233685763..066676140c 100644 --- a/interface/resources/controllers/hydra.json +++ b/interface/resources/controllers/hydra.json @@ -16,12 +16,10 @@ { "from": "Hydra.L0", "to": "Standard.Back" }, { "from": "Hydra.R0", "to": "Standard.Start" }, - { "from": [ "Hydra.L1", "Hydra.L2" ], "to": "Standard.LeftPrimaryThumb" }, - { "from": [ "Hydra.R1", "Hydra.R2" ], "to": "Standard.RightPrimaryThumb" }, - { "from": [ "Hydra.L3" ], "to": "Standard.L3" }, - { "from": [ "Hydra.R3" ], "to": "Standard.R3" }, - { "from": [ "Hydra.R4" ], "to": "Standard.RightSecondaryThumb" }, - { "from": [ "Hydra.L4" ], "to": "Standard.LeftSecondaryThumb" }, + { "from": [ "Hydra.L1", "Hydra.L3" ], "to": "Standard.LeftPrimaryThumb" }, + { "from": [ "Hydra.R1", "Hydra.R3" ], "to": "Standard.RightPrimaryThumb" }, + { "from": [ "Hydra.R2", "Hydra.R4" ], "to": "Standard.RightSecondaryThumb" }, + { "from": [ "Hydra.L2", "Hydra.L4" ], "to": "Standard.LeftSecondaryThumb" }, { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, { "from": "Hydra.RightHand", "to": "Standard.RightHand" } diff --git a/interface/resources/controllers/neuron.json b/interface/resources/controllers/neuron.json index 2d61f80c35..d0962c72db 100644 --- a/interface/resources/controllers/neuron.json +++ b/interface/resources/controllers/neuron.json @@ -1,7 +1,7 @@ { "name": "Neuron to Standard", "channels": [ - { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, - { "from": "Hydra.RightHand", "to": "Standard.RightHand" } + { "from": "Neuron.LeftHand", "to": "Standard.LeftHand" }, + { "from": "Neuron.RightHand", "to": "Standard.RightHand" } ] } diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json index fec93c9132..60a46ba3ce 100644 --- a/interface/resources/controllers/vive.json +++ b/interface/resources/controllers/vive.json @@ -1,23 +1,25 @@ { "name": "Vive to Standard", "channels": [ - { "from": "Vive.LY", "when": "Vive.LS", "filters": ["invert" ,{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LY" }, - { "from": "Vive.LX", "when": "Vive.LS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LX" }, + { "from": "Vive.LY", "when": "Vive.LSOuter", "filters": ["invert"], "to": "Standard.LY" }, + { "from": "Vive.LX", "when": "Vive.LSOuter", "to": "Standard.LX" }, { "from": "Vive.LT", "to": "Standard.LT" }, { "from": "Vive.LeftGrip", "to": "Standard.LB" }, { "from": "Vive.LS", "to": "Standard.LS" }, { "from": "Vive.LSTouch", "to": "Standard.LSTouch" }, - { "from": "Vive.RY", "when": "Vive.RS", "filters": ["invert", { "type": "deadZone", "min": 0.6 }], "to": "Standard.RY" }, - { "from": "Vive.RX", "when": "Vive.RS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.RX" }, + { "from": "Vive.RY", "when": "Vive.RSOuter", "filters": ["invert"], "to": "Standard.RY" }, + { "from": "Vive.RX", "when": "Vive.RSOuter", "to": "Standard.RX" }, { "from": "Vive.RT", "to": "Standard.RT" }, { "from": "Vive.RightGrip", "to": "Standard.RB" }, { "from": "Vive.RS", "to": "Standard.RS" }, { "from": "Vive.RSTouch", "to": "Standard.RSTouch" }, + { "from": "Vive.LSCenter", "to": "Standard.LeftPrimaryThumb" }, { "from": "Vive.LeftApplicationMenu", "to": "Standard.LeftSecondaryThumb" }, + { "from": "Vive.RSCenter", "to": "Standard.RightPrimaryThumb" }, { "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" }, { "from": "Vive.LeftHand", "to": "Standard.LeftHand" }, diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h index f101ba6c51..79c23bc6ee 100644 --- a/libraries/controllers/src/controllers/StandardControls.h +++ b/libraries/controllers/src/controllers/StandardControls.h @@ -43,6 +43,8 @@ namespace controller { LEFT_SECONDARY_THUMB_TOUCH, LS_TOUCH, LEFT_THUMB_UP, + LS_CENTER, + LS_OUTER, RIGHT_PRIMARY_THUMB, RIGHT_SECONDARY_THUMB, @@ -50,6 +52,8 @@ namespace controller { RIGHT_SECONDARY_THUMB_TOUCH, RS_TOUCH, RIGHT_THUMB_UP, + RS_CENTER, + RS_OUTER, LEFT_PRIMARY_INDEX, LEFT_SECONDARY_INDEX, diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 12567b10d1..6e75454b5f 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -282,7 +282,22 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand); } - } + + // pseudo buttons the depend on both of the above for-loops + partitionTouchpad(controller::LS, controller::LX, controller::LY, controller::LS_CENTER, controller::LS_OUTER); + partitionTouchpad(controller::RS, controller::RX, controller::RY, controller::RS_CENTER, controller::RS_OUTER); + } + } +} + +void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPseudoButton, int outerPseudoButton) { + // Populate the L/RS_CENTER/OUTER pseudo buttons, corresponding to a partition of the L/RS space based on the X/Y values. + const float CENTER_DEADBAND = 0.6f; + if (_buttonPressedMap.find(sButton) != _buttonPressedMap.end()) { + float absX = abs(_axisStateMap[xAxis]); + float absY = abs(_axisStateMap[yAxis]); + bool isCenter = (absX < CENTER_DEADBAND) && (absY < CENTER_DEADBAND); // square deadband + _buttonPressedMap.insert(isCenter ? centerPseudoButton : outerPseudoButton); } } @@ -443,6 +458,11 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI // touch pad press makePair(LS, "LS"), makePair(RS, "RS"), + // Differentiate where we are in the touch pad click + makePair(LS_CENTER, "LSCenter"), + makePair(LS_OUTER, "LSOuter"), + makePair(RS_CENTER, "RSCenter"), + makePair(RS_OUTER, "RSOuter"), // triggers makePair(LT, "LT"), diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 672ad59cfe..bd5d4a39f4 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -61,6 +61,7 @@ private: void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand); void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand); + void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int outerPseudoButton); class FilteredStick { public: diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index e7be3af5dd..ca3b5e8cf2 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -266,39 +266,19 @@ function toggleHand() { } } -// Create clickMappings as needed, on demand. var clickMapping = Controller.newMapping(Script.resolvePath('') + '-click'); Script.scriptEnding.connect(clickMapping.disable); -// Move these to vive.json -function makeCenterClickWhen(click, x, y) { - var clickKey = Controller.Standard[click], - xKey = Controller.Standard[x], // Standard after filtering by mapping - yKey = Controller.Standard[y]; - return function () { - var clickValue = Controller.getValue(clickKey); - var xValue = Controller.getValue(xKey); - var yValue = Controller.getValue(yKey); - var answer = clickValue && !xValue && !yValue; - return answer; - }; -} -if (Controller.Hardware.Vive) { - clickMapping.from(Controller.Hardware.Vive.RS).when(makeCenterClickWhen('RS', 'RX', 'RY')).to(Controller.Standard.R3); - clickMapping.from(Controller.Hardware.Vive.LS).when(makeCenterClickWhen('LS', 'LX', 'LY')).to(Controller.Standard.L3); -} - - -clickMapping.from(Controller.Standard.R3).peek().to(Controller.Actions.ReticleClick); -clickMapping.from(Controller.Standard.L3).peek().to(Controller.Actions.ReticleClick); +clickMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(Controller.Actions.ReticleClick); +clickMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(Controller.Actions.ReticleClick); clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(Controller.Actions.ContextMenu); clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(Controller.Actions.ContextMenu); -clickMapping.from(Controller.Standard.R3).peek().to(function (on) { +clickMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(function (on) { if (on && (activeHand !== Controller.Standard.RightHand)) { toggleHand(); } }); -clickMapping.from(Controller.Standard.L3).peek().to(function (on) { +clickMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(function (on) { if (on && (activeHand !== Controller.Standard.LeftHand)) { toggleHand(); }