Merge pull request #7960 from howard-stearns/fix-hand-controllers-after-input-changes

Fix hand controller pointer after input changes.
This commit is contained in:
Brad Hefta-Gaub 2016-05-26 12:16:23 -07:00
commit 88813c47f0
7 changed files with 59 additions and 86 deletions

View file

@ -16,8 +16,10 @@
{ "from": "Hydra.L0", "to": "Standard.Back" }, { "from": "Hydra.L0", "to": "Standard.Back" },
{ "from": "Hydra.R0", "to": "Standard.Start" }, { "from": "Hydra.R0", "to": "Standard.Start" },
{ "from": [ "Hydra.L1", "Hydra.L2", "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" }, { "from": [ "Hydra.L1", "Hydra.L3" ], "to": "Standard.LeftPrimaryThumb" },
{ "from": [ "Hydra.R1", "Hydra.R2", "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" }, { "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.LeftHand", "to": "Standard.LeftHand" },
{ "from": "Hydra.RightHand", "to": "Standard.RightHand" } { "from": "Hydra.RightHand", "to": "Standard.RightHand" }

View file

@ -1,7 +1,7 @@
{ {
"name": "Neuron to Standard", "name": "Neuron to Standard",
"channels": [ "channels": [
{ "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, { "from": "Neuron.LeftHand", "to": "Standard.LeftHand" },
{ "from": "Hydra.RightHand", "to": "Standard.RightHand" } { "from": "Neuron.RightHand", "to": "Standard.RightHand" }
] ]
} }

View file

@ -1,24 +1,26 @@
{ {
"name": "Vive to Standard", "name": "Vive to Standard",
"channels": [ "channels": [
{ "from": "Vive.LY", "when": "Vive.LS", "filters": ["invert" ,{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LY" }, { "from": "Vive.LY", "when": "Vive.LSOuter", "filters": ["invert"], "to": "Standard.LY" },
{ "from": "Vive.LX", "when": "Vive.LS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LX" }, { "from": "Vive.LX", "when": "Vive.LSOuter", "to": "Standard.LX" },
{ "from": "Vive.LT", "to": "Standard.LT" }, { "from": "Vive.LT", "to": "Standard.LT" },
{ "from": "Vive.LeftGrip", "to": "Standard.LB" }, { "from": "Vive.LeftGrip", "to": "Standard.LB" },
{ "from": "Vive.LS", "to": "Standard.LS" }, { "from": "Vive.LS", "to": "Standard.LS" },
{ "from": "Vive.LSTouch", "to": "Standard.LSTouch" }, { "from": "Vive.LSTouch", "to": "Standard.LSTouch" },
{ "from": "Vive.RY", "when": "Vive.RS", "filters": ["invert", { "type": "deadZone", "min": 0.6 }], "to": "Standard.RY" }, { "from": "Vive.RY", "when": "Vive.RSOuter", "filters": ["invert"], "to": "Standard.RY" },
{ "from": "Vive.RX", "when": "Vive.RS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.RX" }, { "from": "Vive.RX", "when": "Vive.RSOuter", "to": "Standard.RX" },
{ "from": "Vive.RT", "to": "Standard.RT" }, { "from": "Vive.RT", "to": "Standard.RT" },
{ "from": "Vive.RightGrip", "to": "Standard.RB" }, { "from": "Vive.RightGrip", "to": "Standard.RB" },
{ "from": "Vive.RS", "to": "Standard.RS" }, { "from": "Vive.RS", "to": "Standard.RS" },
{ "from": "Vive.RSTouch", "to": "Standard.RSTouch" }, { "from": "Vive.RSTouch", "to": "Standard.RSTouch" },
{ "from": "Vive.LeftApplicationMenu", "to": "Standard.Back" }, { "from": "Vive.LSCenter", "to": "Standard.LeftPrimaryThumb" },
{ "from": "Vive.RightApplicationMenu", "to": "Standard.Start" }, { "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.LeftHand", "to": "Standard.LeftHand" },
{ "from": "Vive.RightHand", "to": "Standard.RightHand" } { "from": "Vive.RightHand", "to": "Standard.RightHand" }

View file

@ -43,6 +43,8 @@ namespace controller {
LEFT_SECONDARY_THUMB_TOUCH, LEFT_SECONDARY_THUMB_TOUCH,
LS_TOUCH, LS_TOUCH,
LEFT_THUMB_UP, LEFT_THUMB_UP,
LS_CENTER,
LS_OUTER,
RIGHT_PRIMARY_THUMB, RIGHT_PRIMARY_THUMB,
RIGHT_SECONDARY_THUMB, RIGHT_SECONDARY_THUMB,
@ -50,6 +52,8 @@ namespace controller {
RIGHT_SECONDARY_THUMB_TOUCH, RIGHT_SECONDARY_THUMB_TOUCH,
RS_TOUCH, RS_TOUCH,
RIGHT_THUMB_UP, RIGHT_THUMB_UP,
RS_CENTER,
RS_OUTER,
LEFT_PRIMARY_INDEX, LEFT_PRIMARY_INDEX,
LEFT_SECONDARY_INDEX, LEFT_SECONDARY_INDEX,

View file

@ -282,10 +282,25 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u
for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) {
handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand); 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);
}
}
void ViveControllerManager::InputDevice::focusOutEvent() { void ViveControllerManager::InputDevice::focusOutEvent() {
_axisStateMap.clear(); _axisStateMap.clear();
_buttonPressedMap.clear(); _buttonPressedMap.clear();
@ -443,6 +458,11 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI
// touch pad press // touch pad press
makePair(LS, "LS"), makePair(LS, "LS"),
makePair(RS, "RS"), 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 // triggers
makePair(LT, "LT"), makePair(LT, "LT"),

View file

@ -61,6 +61,7 @@ private:
void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand); void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand);
void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand); const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand);
void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int outerPseudoButton);
class FilteredStick { class FilteredStick {
public: public:

View file

@ -22,10 +22,7 @@
// (For now, the thumb buttons on both controllers are always on.) // (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. // 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. // 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 ------------- // UTILITIES -------------
@ -269,76 +266,24 @@ function toggleHand() {
} }
} }
// Create clickMappings as needed, on demand. var clickMapping = Controller.newMapping(Script.resolvePath('') + '-click');
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); Script.scriptEnding.connect(clickMapping.disable);
function mapToAction(button, action) {
clickMapping.from(Controller.Hardware[hardware][button]).peek().to(Controller.Actions[action]); clickMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(Controller.Actions.ReticleClick);
} clickMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(Controller.Actions.ReticleClick);
function makeHandToggle(button, hand, optionalWhen) { clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(Controller.Actions.ContextMenu);
var whenThunk = optionalWhen || function () { clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(Controller.Actions.ContextMenu);
return true; clickMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(function (on) {
}; if (on && (activeHand !== Controller.Standard.RightHand)) {
function maybeToggle() {
if (activeHand !== Controller.Standard[hand]) {
toggleHand(); toggleHand();
} }
});
clickMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(function (on) {
if (on && (activeHand !== Controller.Standard.LeftHand)) {
toggleHand();
} }
clickMapping.from(Controller.Hardware[hardware][button]).peek().when(whenThunk).to(maybeToggle); });
} clickMapping.enable();
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);
}
checkHardware();
// VISUAL AID ----------- // VISUAL AID -----------
// Same properties as handControllerGrab search sphere // Same properties as handControllerGrab search sphere
@ -415,8 +360,8 @@ function update() {
return turnOffVisualization(); return turnOffVisualization();
} }
var controllerPose = Controller.getPoseValue(activeHand); var controllerPose = Controller.getPoseValue(activeHand);
// Vive is effectively invalid when not in HMD // Valid if any plugged-in hand controller is "on". (uncradled Hydra, green-lighted Vive...)
if (!controllerPose.valid || ((hardware === 'Vive') && !HMD.active)) { if (!controllerPose.valid) {
return turnOffVisualization(); return turnOffVisualization();
} // Controller is cradled. } // Controller is cradled.
var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation), 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 var SETTINGS_CHANGE_RECHECK_INTERVAL = 10 * 1000; // milliseconds
function checkSettings() { function checkSettings() {
updateFieldOfView(); updateFieldOfView();
checkHardware();
} }
checkSettings(); checkSettings();
var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL); var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL);