diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json index 42237033af..066676140c 100644 --- a/interface/resources/controllers/hydra.json +++ b/interface/resources/controllers/hydra.json @@ -16,8 +16,10 @@ { "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.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 4085d71c27..60a46ba3ce 100644 --- a/interface/resources/controllers/vive.json +++ b/interface/resources/controllers/vive.json @@ -1,24 +1,26 @@ { "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.LeftApplicationMenu", "to": "Standard.Back" }, - { "from": "Vive.RightApplicationMenu", "to": "Standard.Start" }, + { "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" }, { "from": "Vive.RightHand", "to": "Standard.RightHand" } 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 f4e4492a88..ca3b5e8cf2 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 ------------- @@ -269,76 +266,24 @@ 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; +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.RightPrimaryThumb).peek().to(function (on) { + if (on && (activeHand !== Controller.Standard.RightHand)) { + toggleHand(); } - clickMapToggle = new LatchedToggle(clickMapping.enable, clickMapping.disable); - clickMapToggle.setState(true); -} -checkHardware(); +}); +clickMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(function (on) { + if (on && (activeHand !== Controller.Standard.LeftHand)) { + toggleHand(); + } +}); +clickMapping.enable(); // VISUAL AID ----------- // Same properties as handControllerGrab search sphere @@ -415,8 +360,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 +403,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);