Merge pull request #6156 from jherico/controllers

Minor cleanup and fix for broken conditional strafe
This commit is contained in:
Brad Hefta-Gaub 2015-10-22 18:16:47 -07:00
commit 978d248c9e
8 changed files with 126 additions and 61 deletions

View file

@ -23,6 +23,11 @@ Rectangle {
function update() {
value = Controller.getValue(controlId);
if (log) {
var log = Math.log(10) / Math.log(Math.abs(value));
var sign = Math.sign(value);
value = log * sign;
}
canvas.requestPaint();
}

View file

@ -91,8 +91,7 @@ HifiControls.VrDialog {
Hydra { device: root.hydra; width: 180 }
}
Grid {
columns: 6
Row {
spacing: 4
ScrollingGraph {
controlId: Controller.Actions.Yaw
@ -117,13 +116,41 @@ HifiControls.VrDialog {
max: 2.0
size: 64
}
ScrollingGraph {
controlId: Controller.Actions.StepYaw
label: "StepYaw"
min: -20.0
max: 20.0
size: 64
}
}
Row {
ScrollingGraph {
controlId: Controller.Actions.TranslateZ
label: "TranslateZ"
min: -2.0
max: 2.0
size: 64
}
ScrollingGraph {
controlId: Controller.Actions.Forward
label: "Forward"
min: -2.0
max: 2.0
size: 64
}
ScrollingGraph {
controlId: Controller.Actions.Backward
label: "Backward"
min: -2.0
max: 2.0
size: 64
}
}
}
} // dialog

View file

@ -48,18 +48,6 @@ namespace controller {
makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateX"),
makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateY"),
makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateZ"),
makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),
makeAxisPair(Action::LONGITUDINAL_FORWARD, "Forward"),
makeAxisPair(Action::LATERAL_LEFT, "StrafeLeft"),
makeAxisPair(Action::LATERAL_RIGHT, "StrafeRight"),
makeAxisPair(Action::VERTICAL_DOWN, "Down"),
makeAxisPair(Action::VERTICAL_UP, "Up"),
makeAxisPair(Action::YAW_LEFT, "YawLeft"),
makeAxisPair(Action::YAW_RIGHT, "YawRight"),
makeAxisPair(Action::PITCH_DOWN, "PitchDown"),
makeAxisPair(Action::PITCH_UP, "PitchUp"),
makeAxisPair(Action::BOOM_IN, "BoomIn"),
makeAxisPair(Action::BOOM_OUT, "BoomOut"),
makePosePair(Action::LEFT_HAND, "LeftHand"),
makePosePair(Action::RIGHT_HAND, "RightHand"),
@ -73,6 +61,20 @@ namespace controller {
makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"),
makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"),
// Aliases and bisected versions
makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),
makeAxisPair(Action::LONGITUDINAL_FORWARD, "Forward"),
makeAxisPair(Action::LATERAL_LEFT, "StrafeLeft"),
makeAxisPair(Action::LATERAL_RIGHT, "StrafeRight"),
makeAxisPair(Action::VERTICAL_DOWN, "Down"),
makeAxisPair(Action::VERTICAL_UP, "Up"),
makeAxisPair(Action::YAW_LEFT, "YawLeft"),
makeAxisPair(Action::YAW_RIGHT, "YawRight"),
makeAxisPair(Action::PITCH_DOWN, "PitchDown"),
makeAxisPair(Action::PITCH_UP, "PitchUp"),
makeAxisPair(Action::BOOM_IN, "BoomIn"),
makeAxisPair(Action::BOOM_OUT, "BoomOut"),
// Deprecated aliases
// FIXME remove after we port all scripts
makeAxisPair(Action::LONGITUDINAL_BACKWARD, "LONGITUDINAL_BACKWARD"),

View file

@ -24,6 +24,8 @@ namespace controller {
Endpoint::Pointer destination;
Conditional::Pointer conditional;
Filter::List filters;
QString json;
bool debug { false };
using Pointer = std::shared_ptr<Route>;
using List = std::list<Pointer>;

View file

@ -73,10 +73,26 @@ void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
availableInputs.append(makePair(LT, "LT"));
availableInputs.append(makePair(RT, "RT"));
// Finger abstractions
availableInputs.append(makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"));
availableInputs.append(makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"));
availableInputs.append(makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"));
availableInputs.append(makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"));
availableInputs.append(makePair(LEFT_PRIMARY_INDEX, "LeftPrimaryIndex"));
availableInputs.append(makePair(LEFT_SECONDARY_INDEX, "LeftSecondaryIndex"));
availableInputs.append(makePair(RIGHT_PRIMARY_INDEX, "RightPrimaryIndex"));
availableInputs.append(makePair(RIGHT_SECONDARY_INDEX, "RightSecondaryIndex"));
availableInputs.append(makePair(LEFT_GRIP, "LeftGrip"));
availableInputs.append(makePair(RIGHT_GRIP, "RightGrip"));
// Poses
availableInputs.append(makePair(LEFT_HAND, "LeftHand"));
availableInputs.append(makePair(RIGHT_HAND, "RightHand"));
// Aliases, PlayStation style names
availableInputs.append(makePair(LB, "L1"));
availableInputs.append(makePair(RB, "R1"));
@ -95,10 +111,6 @@ void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
availableInputs.append(makePair(DR, "Right"));
availableInputs.append(makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"));
availableInputs.append(makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"));
availableInputs.append(makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"));
availableInputs.append(makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"));
return availableInputs;
};

View file

@ -42,6 +42,14 @@ namespace controller {
RIGHT_PRIMARY_THUMB,
RIGHT_SECONDARY_THUMB,
LEFT_PRIMARY_INDEX,
LEFT_SECONDARY_INDEX,
RIGHT_PRIMARY_INDEX,
RIGHT_SECONDARY_INDEX,
LEFT_GRIP,
RIGHT_GRIP,
NUM_STANDARD_BUTTONS
};

View file

@ -655,8 +655,6 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
void UserInputMapper::runMappings() {
static auto deviceNames = getDeviceNames();
_overrides.clear();
for (auto endpointEntry : this->_endpointsByInput) {
endpointEntry.second->reset();
}
@ -675,60 +673,59 @@ void UserInputMapper::runMappings() {
}
applyRoute(route);
}
}
void UserInputMapper::applyRoute(const Route::Pointer& route) {
if (route->debug) {
qCDebug(controllers) << "Applying route " << route->json;
}
if (route->conditional) {
if (!route->conditional->satisfied()) {
if (route->debug) {
qCDebug(controllers) << "Conditional failed";
}
return;
}
}
auto source = route->source;
if (_overrides.count(source)) {
source = _overrides[source];
}
// Endpoints can only be read once (though a given mapping can route them to
// Most endpoints can only be read once (though a given mapping can route them to
// multiple places). Consider... If the default is to wire the A button to JUMP
// and someone else wires it to CONTEXT_MENU, I don't want both to occur when
// I press the button. The exception is if I'm wiring a control back to itself
// in order to adjust my interface, like inverting the Y axis on an analog stick
if (!source->readable()) {
if (route->debug) {
qCDebug(controllers) << "Source unreadable";
}
return;
}
auto input = source->getInput();
float value = source->value();
if (value != 0.0) {
int i = 0;
}
auto destination = route->destination;
// THis could happen if the route destination failed to create
// FIXME: Maybe do not create the route if the destination failed and avoid this case ?
if (!destination) {
if (route->debug) {
qCDebug(controllers) << "Bad Destination";
}
return;
}
// FIXME?, should come before or after the override logic?
if (!destination->writeable()) {
if (route->debug) {
qCDebug(controllers) << "Destination unwritable";
}
return;
}
// Only consume the input if the route isn't a loopback.
// This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
bool loopback = (source->getInput() == destination->getInput()) && (source->getInput() != Input::INVALID_INPUT);
// Each time we loop back we re-write the override
if (loopback) {
_overrides[source] = destination = std::make_shared<StandardEndpoint>(source->getInput());
}
// Fetch the value, may have been overriden by previous loopback routes
if (source->isPose()) {
if (route->debug) {
qCDebug(controllers) << "Applying pose";
}
Pose value = getPose(source);
// no filters yet for pose
destination->apply(value, Pose(), source);
@ -736,11 +733,18 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
// Fetch the value, may have been overriden by previous loopback routes
float value = getValue(source);
if (route->debug) {
qCDebug(controllers) << "Value was " << value;
}
// Apply each of the filters.
for (const auto& filter : route->filters) {
value = filter->apply(value);
}
if (route->debug) {
qCDebug(controllers) << "Filtered value was " << value;
}
destination->apply(value, 0, source);
}
}
@ -850,11 +854,6 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const {
Locker locker(_lock);
auto valuesIterator = _overrides.find(endpoint);
if (_overrides.end() != valuesIterator) {
return valuesIterator->second->value();
}
return endpoint->value();
}
@ -900,6 +899,7 @@ Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) {
static const QString JSON_NAME = QStringLiteral("name");
static const QString JSON_CHANNELS = QStringLiteral("channels");
static const QString JSON_CHANNEL_FROM = QStringLiteral("from");
static const QString JSON_CHANNEL_DEBUG = QStringLiteral("debug");
static const QString JSON_CHANNEL_WHEN = QStringLiteral("when");
static const QString JSON_CHANNEL_TO = QStringLiteral("to");
static const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
@ -1052,9 +1052,12 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
return Route::Pointer();
}
const auto& obj = value.toObject();
auto obj = value.toObject();
Route::Pointer result = std::make_shared<Route>();
result->json = QString(QJsonDocument(obj).toJson());
result->source = parseSource(obj[JSON_CHANNEL_FROM]);
result->debug = obj[JSON_CHANNEL_DEBUG].toBool();
if (!result->source) {
qWarning() << "Invalid route source " << obj[JSON_CHANNEL_FROM];
return Route::Pointer();
@ -1067,6 +1070,11 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
return Route::Pointer();
}
if (result->source == result->destination) {
qWarning() << "Loopback routes not supported " << obj;
return Route::Pointer();
}
if (obj.contains(JSON_CHANNEL_WHEN)) {
auto conditionalsValue = obj[JSON_CHANNEL_WHEN];
result->conditional = parseConditional(conditionalsValue);
@ -1138,26 +1146,28 @@ void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
// are processed in order so this ensures that the standard -> action processing
// takes place after all of the hardware -> standard or hardware -> action processing
// because standard -> action is the first set of routes added.
for (auto route : mapping->routes) {
if (route->source->getInput().device == STANDARD_DEVICE) {
_standardRoutes.push_front(route);
} else {
_deviceRoutes.push_front(route);
}
}
Route::List standardRoutes = mapping->routes;
standardRoutes.remove_if([](const Route::Pointer& value) {
return (value->source->getInput().device == STANDARD_DEVICE);
});
_standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end());
Route::List deviceRoutes = mapping->routes;
deviceRoutes.remove_if([](const Route::Pointer& value) {
return (value->source->getInput().device != STANDARD_DEVICE);
});
_deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
}
void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
Locker locker(_lock);
const auto& deviceRoutes = mapping->routes;
std::set<Route::Pointer> routeSet(deviceRoutes.begin(), deviceRoutes.end());
// FIXME this seems to result in empty route pointers... need to find a better way to remove them.
std::remove_if(_deviceRoutes.begin(), _deviceRoutes.end(), [&](Route::Pointer route)->bool {
return routeSet.count(route) != 0;
_deviceRoutes.remove_if([&](const Route::Pointer& value){
return routeSet.count(value) != 0;
});
std::remove_if(_standardRoutes.begin(), _standardRoutes.end(), [&](Route::Pointer route)->bool {
return routeSet.count(route) != 0;
_standardRoutes.remove_if([&](const Route::Pointer& value) {
return routeSet.count(value) != 0;
});
}

View file

@ -165,7 +165,6 @@ namespace controller {
EndpointToInputMap _inputsByEndpoint;
EndpointPairMap _compositeEndpoints;
EndpointOverrideMap _overrides;
MappingNameMap _mappingsByName;
MappingDeviceMap _mappingsByDevice;