mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-11 00:26:35 +02:00
Wiring up step yaw
This commit is contained in:
parent
81df30d9e5
commit
637654adea
8 changed files with 210 additions and 207 deletions
|
@ -1,4 +1,12 @@
|
|||
ControllerTest = function() {
|
||||
var standard = Controller.Standard;
|
||||
var actions = Controller.Actions;
|
||||
this.mappingEnabled = false;
|
||||
this.mapping = Controller.newMapping();
|
||||
this.mapping.from(standard.RX).to(actions.StepYaw);
|
||||
this.mapping.enable();
|
||||
this.mappingEnabled = true;
|
||||
|
||||
|
||||
print("Actions");
|
||||
for (var prop in Controller.Actions) {
|
||||
|
@ -24,6 +32,9 @@ ControllerTest = function() {
|
|||
}
|
||||
|
||||
ControllerTest.prototype.onCleanup = function() {
|
||||
if (this.mappingEnabled) {
|
||||
this.mapping.disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,12 +3,12 @@ import QtQuick.Controls 1.0
|
|||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
Item {
|
||||
Rectangle {
|
||||
id: root
|
||||
property int size: 64
|
||||
width: size
|
||||
height: size
|
||||
|
||||
color: 'black'
|
||||
property int controlId: 0
|
||||
property real value: 0.5
|
||||
property int scrollWidth: 1
|
||||
|
@ -16,7 +16,7 @@ Item {
|
|||
property real max: 1.0
|
||||
property bool log: false
|
||||
property real range: max - min
|
||||
property color color: 'blue'
|
||||
property color lineColor: 'yellow'
|
||||
property bool bar: false
|
||||
property real lastHeight: -1
|
||||
property string label: ""
|
||||
|
@ -49,19 +49,21 @@ Item {
|
|||
Text {
|
||||
anchors.top: parent.top
|
||||
text: root.label
|
||||
|
||||
color: 'white'
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
text: root.max
|
||||
color: 'white'
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
text: root.min
|
||||
color: 'white'
|
||||
}
|
||||
|
||||
function scroll() {
|
||||
|
@ -92,7 +94,7 @@ Item {
|
|||
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 1
|
||||
ctx.strokeStyle = root.color
|
||||
ctx.strokeStyle = root.lineColor
|
||||
ctx.moveTo(canvas.width - root.scrollWidth, root.lastHeight).lineTo(canvas.width, currentHeight)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
|
|
|
@ -20,8 +20,20 @@ HifiControls.VrDialog {
|
|||
property var standard: Controller.Standard
|
||||
property var hydra: null
|
||||
property var testMapping: null
|
||||
property bool testMappingEnabled: false
|
||||
property var xbox: null
|
||||
|
||||
function buildMapping() {
|
||||
testMapping = Controller.newMapping();
|
||||
testMapping.from(standard.RY).invert().to(actions.Pitch);
|
||||
testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
|
||||
testMapping.from(standard.RX).to(actions.StepYaw);
|
||||
}
|
||||
|
||||
function toggleMapping() {
|
||||
testMapping.enable(!testMappingEnabled);
|
||||
testMappingEnabled = !testMappingEnabled;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
|
@ -49,110 +61,18 @@ HifiControls.VrDialog {
|
|||
|
||||
Row {
|
||||
spacing: 8
|
||||
Button {
|
||||
text: "Standard Mapping"
|
||||
onClicked: {
|
||||
var mapping = Controller.newMapping("Default");
|
||||
mapping.from(standard.LX).to(actions.TranslateX);
|
||||
mapping.from(standard.LY).to(actions.TranslateZ);
|
||||
mapping.from(standard.RY).to(actions.Pitch);
|
||||
mapping.from(standard.RX).to(actions.Yaw);
|
||||
mapping.from(standard.DU).scale(0.5).to(actions.LONGITUDINAL_FORWARD);
|
||||
mapping.from(standard.DD).scale(0.5).to(actions.LONGITUDINAL_BACKWARD);
|
||||
mapping.from(standard.DL).scale(0.5).to(actions.LATERAL_LEFT);
|
||||
mapping.from(standard.DR).scale(0.5).to(actions.LATERAL_RIGHT);
|
||||
mapping.from(standard.X).to(actions.VERTICAL_DOWN);
|
||||
mapping.from(standard.Y).to(actions.VERTICAL_UP);
|
||||
mapping.from(standard.RT).scale(0.1).to(actions.BOOM_IN);
|
||||
mapping.from(standard.LT).scale(0.1).to(actions.BOOM_OUT);
|
||||
mapping.from(standard.B).to(actions.ACTION1);
|
||||
mapping.from(standard.A).to(actions.ACTION2);
|
||||
mapping.from(standard.RB).to(actions.SHIFT);
|
||||
mapping.from(standard.Back).to(actions.TOGGLE_MUTE);
|
||||
mapping.from(standard.Start).to(actions.CONTEXT_MENU);
|
||||
Controller.enableMapping("Default");
|
||||
enabled = false;
|
||||
text = "Standard Built"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: root.xbox ? "XBox Mapping" : "XBox not found"
|
||||
property bool built: false
|
||||
enabled: root.xbox && !built
|
||||
text: !root.testMapping ? "Build Mapping" : (root.testMappingEnabled ? "Disable Mapping" : "Enable Mapping")
|
||||
onClicked: {
|
||||
var mapping = Controller.newMapping();
|
||||
mapping.from(xbox.A).to(standard.A);
|
||||
mapping.from(xbox.B).to(standard.B);
|
||||
mapping.from(xbox.X).to(standard.X);
|
||||
mapping.from(xbox.Y).to(standard.Y);
|
||||
mapping.from(xbox.Up).to(standard.DU);
|
||||
mapping.from(xbox.Down).to(standard.DD);
|
||||
mapping.from(xbox.Left).to(standard.DL);
|
||||
mapping.from(xbox.Right).to(standard.Right);
|
||||
mapping.from(xbox.LB).to(standard.LB);
|
||||
mapping.from(xbox.RB).to(standard.RB);
|
||||
mapping.from(xbox.LS).to(standard.LS);
|
||||
mapping.from(xbox.RS).to(standard.RS);
|
||||
mapping.from(xbox.Start).to(standard.Start);
|
||||
mapping.from(xbox.Back).to(standard.Back);
|
||||
mapping.from(xbox.LY).to(standard.LY);
|
||||
mapping.from(xbox.LX).to(standard.LX);
|
||||
mapping.from(xbox.RY).to(standard.RY);
|
||||
mapping.from(xbox.RX).to(standard.RX);
|
||||
mapping.from(xbox.LT).to(standard.LT);
|
||||
mapping.from(xbox.RT).to(standard.RT);
|
||||
mapping.enable();
|
||||
built = false;
|
||||
text = "XBox Built"
|
||||
|
||||
if (!root.testMapping) {
|
||||
root.buildMapping()
|
||||
} else {
|
||||
root.toggleMapping();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: root.hydra ? "Hydra Mapping" : "Hydra Not Found"
|
||||
property bool built: false
|
||||
enabled: root.hydra && !built
|
||||
onClicked: {
|
||||
var mapping = Controller.newMapping();
|
||||
mapping.from(hydra.LY).invert().to(standard.LY);
|
||||
mapping.from(hydra.LX).to(standard.LX);
|
||||
mapping.from(hydra.RY).invert().to(standard.RY);
|
||||
mapping.from(hydra.RX).to(standard.RX);
|
||||
mapping.from(hydra.LT).to(standard.LT);
|
||||
mapping.from(hydra.RT).to(standard.RT);
|
||||
mapping.enable();
|
||||
built = false;
|
||||
text = "Hydra Built"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Test Mapping"
|
||||
onClicked: {
|
||||
var mapping = Controller.newMapping();
|
||||
// Inverting a value
|
||||
mapping.from(standard.RY).invert().to(standard.RY);
|
||||
mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
|
||||
testMapping = mapping;
|
||||
enabled = false
|
||||
text = "Built"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Enable Mapping"
|
||||
onClicked: root.testMapping.enable()
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Disable Mapping"
|
||||
onClicked: root.testMapping.disable()
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Enable Mapping"
|
||||
onClicked: print(Controller.getValue(root.xbox.LY));
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
|
@ -170,25 +90,32 @@ HifiControls.VrDialog {
|
|||
ScrollingGraph {
|
||||
controlId: Controller.Actions.Yaw
|
||||
label: "Yaw"
|
||||
min: -3.0
|
||||
max: 3.0
|
||||
size: 128
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.YAW_LEFT
|
||||
controlId: Controller.Actions.YawLeft
|
||||
label: "Yaw Left"
|
||||
min: -3.0
|
||||
max: 3.0
|
||||
size: 128
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.YAW_RIGHT
|
||||
controlId: Controller.Actions.YawRight
|
||||
label: "Yaw Right"
|
||||
min: -3.0
|
||||
max: 3.0
|
||||
size: 128
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.StepYaw
|
||||
label: "StepYaw"
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ Item {
|
|||
// Left primary
|
||||
ToggleButton {
|
||||
x: parent.width - width; y: parent.height - height;
|
||||
controlId: root.device.RB
|
||||
controlId: root.device.RightPrimaryThumb
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,12 @@ namespace controller {
|
|||
makeAxisPair(Action::ROLL, "Roll"),
|
||||
makeAxisPair(Action::PITCH, "Pitch"),
|
||||
makeAxisPair(Action::YAW, "Yaw"),
|
||||
makeAxisPair(Action::STEP_YAW, "StepYaw"),
|
||||
makeAxisPair(Action::STEP_PITCH, "StepPitch"),
|
||||
makeAxisPair(Action::STEP_ROLL, "StepRoll"),
|
||||
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"),
|
||||
|
@ -67,7 +73,6 @@ namespace controller {
|
|||
makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"),
|
||||
makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"),
|
||||
|
||||
|
||||
// Deprecated aliases
|
||||
// FIXME remove after we port all scripts
|
||||
makeAxisPair(Action::LONGITUDINAL_BACKWARD, "LONGITUDINAL_BACKWARD"),
|
||||
|
|
|
@ -27,6 +27,16 @@ enum class Action {
|
|||
ROTATE_Y, YAW = ROTATE_Y,
|
||||
ROTATE_Z, ROLL = ROTATE_Z,
|
||||
|
||||
STEP_YAW,
|
||||
// FIXME does this have a use case?
|
||||
STEP_PITCH,
|
||||
// FIXME does this have a use case?
|
||||
STEP_ROLL,
|
||||
|
||||
STEP_TRANSLATE_X,
|
||||
STEP_TRANSLATE_Y,
|
||||
STEP_TRANSLATE_Z,
|
||||
|
||||
TRANSLATE_CAMERA_Z,
|
||||
NUM_COMBINED_AXES,
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace controller {
|
|||
|
||||
// Default contruct allocate the poutput size with the current hardcoded action channels
|
||||
controller::UserInputMapper::UserInputMapper() {
|
||||
_activeMappings.push_back(_defaultMapping);
|
||||
_standardController = std::make_shared<StandardController>();
|
||||
registerDevice(new ActionsDevice());
|
||||
registerDevice(_standardController.get());
|
||||
|
@ -317,6 +316,7 @@ int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
|
|||
}
|
||||
|
||||
void UserInputMapper::registerDevice(InputDevice* device) {
|
||||
Locker locker(_lock);
|
||||
if (device->_deviceID == Input::INVALID_DEVICE) {
|
||||
device->_deviceID = getFreeDeviceID();
|
||||
}
|
||||
|
@ -354,13 +354,7 @@ void UserInputMapper::registerDevice(InputDevice* device) {
|
|||
auto mapping = loadMapping(device->getDefaultMappingConfig());
|
||||
if (mapping) {
|
||||
_mappingsByDevice[deviceID] = mapping;
|
||||
auto& defaultRoutes = _defaultMapping->routes;
|
||||
|
||||
// New routes for a device get injected IN FRONT of existing routes. Routes
|
||||
// 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.
|
||||
defaultRoutes.insert(defaultRoutes.begin(), mapping->routes.begin(), mapping->routes.end());
|
||||
enableMapping(mapping);
|
||||
}
|
||||
|
||||
emit hardwareChanged();
|
||||
|
@ -368,6 +362,7 @@ void UserInputMapper::registerDevice(InputDevice* device) {
|
|||
|
||||
// FIXME remove the associated device mappings
|
||||
void UserInputMapper::removeDevice(int deviceID) {
|
||||
Locker locker(_lock);
|
||||
auto proxyEntry = _registeredDevices.find(deviceID);
|
||||
if (_registeredDevices.end() == proxyEntry) {
|
||||
qCWarning(controllers) << "Attempted to remove unknown device " << deviceID;
|
||||
|
@ -376,15 +371,7 @@ void UserInputMapper::removeDevice(int deviceID) {
|
|||
auto proxy = proxyEntry->second;
|
||||
auto mappingsEntry = _mappingsByDevice.find(deviceID);
|
||||
if (_mappingsByDevice.end() != mappingsEntry) {
|
||||
const auto& mapping = mappingsEntry->second;
|
||||
const auto& deviceRoutes = mapping->routes;
|
||||
std::set<Route::Pointer> routeSet(deviceRoutes.begin(), deviceRoutes.end());
|
||||
|
||||
auto& defaultRoutes = _defaultMapping->routes;
|
||||
std::remove_if(defaultRoutes.begin(), defaultRoutes.end(), [&](Route::Pointer route)->bool {
|
||||
return routeSet.count(route) != 0;
|
||||
});
|
||||
|
||||
disableMapping(mappingsEntry->second);
|
||||
_mappingsByDevice.erase(mappingsEntry);
|
||||
}
|
||||
|
||||
|
@ -395,6 +382,7 @@ void UserInputMapper::removeDevice(int deviceID) {
|
|||
|
||||
|
||||
DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
|
||||
Locker locker(_lock);
|
||||
auto device = _registeredDevices.find(input.getDevice());
|
||||
if (device != _registeredDevices.end()) {
|
||||
return (device->second);
|
||||
|
@ -404,6 +392,7 @@ DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
|
|||
}
|
||||
|
||||
QString UserInputMapper::getDeviceName(uint16 deviceID) {
|
||||
Locker locker(_lock);
|
||||
if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
|
||||
return _registeredDevices[deviceID]->_name;
|
||||
}
|
||||
|
@ -411,6 +400,7 @@ QString UserInputMapper::getDeviceName(uint16 deviceID) {
|
|||
}
|
||||
|
||||
int UserInputMapper::findDevice(QString name) const {
|
||||
Locker locker(_lock);
|
||||
for (auto device : _registeredDevices) {
|
||||
if (device.second->_name == name) {
|
||||
return device.first;
|
||||
|
@ -420,6 +410,7 @@ int UserInputMapper::findDevice(QString name) const {
|
|||
}
|
||||
|
||||
QVector<QString> UserInputMapper::getDeviceNames() {
|
||||
Locker locker(_lock);
|
||||
QVector<QString> result;
|
||||
for (auto device : _registeredDevices) {
|
||||
QString deviceName = device.second->_name.split(" (")[0];
|
||||
|
@ -433,6 +424,7 @@ int UserInputMapper::findAction(const QString& actionName) const {
|
|||
}
|
||||
|
||||
Input UserInputMapper::findDeviceInput(const QString& inputName) const {
|
||||
Locker locker(_lock);
|
||||
// Split the full input name as such: deviceName.inputName
|
||||
auto names = inputName.split('.');
|
||||
|
||||
|
@ -472,6 +464,7 @@ void fixBisectedAxis(float& full, float& negative, float& positive) {
|
|||
}
|
||||
|
||||
void UserInputMapper::update(float deltaTime) {
|
||||
Locker locker(_lock);
|
||||
// Reset the axis state for next loop
|
||||
for (auto& channel : _actionStates) {
|
||||
channel = 0.0f;
|
||||
|
@ -505,11 +498,13 @@ void UserInputMapper::update(float deltaTime) {
|
|||
}
|
||||
|
||||
Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const {
|
||||
Locker locker(_lock);
|
||||
auto iterator = _registeredDevices.find(deviceID);
|
||||
return iterator->second->getAvailabeInputs();
|
||||
}
|
||||
|
||||
QVector<Action> UserInputMapper::getAllActions() const {
|
||||
Locker locker(_lock);
|
||||
QVector<Action> actions;
|
||||
for (auto i = 0; i < toInt(Action::NUM_ACTIONS); i++) {
|
||||
actions.append(Action(i));
|
||||
|
@ -518,6 +513,7 @@ QVector<Action> UserInputMapper::getAllActions() const {
|
|||
}
|
||||
|
||||
QString UserInputMapper::getActionName(Action action) const {
|
||||
Locker locker(_lock);
|
||||
for (auto actionPair : getActionInputs()) {
|
||||
if (actionPair.first.channel == toInt(action)) {
|
||||
return actionPair.second;
|
||||
|
@ -528,6 +524,7 @@ QString UserInputMapper::getActionName(Action action) const {
|
|||
|
||||
|
||||
QVector<QString> UserInputMapper::getActionNames() const {
|
||||
Locker locker(_lock);
|
||||
QVector<QString> result;
|
||||
for (auto actionPair : getActionInputs()) {
|
||||
result << actionPair.second;
|
||||
|
@ -645,74 +642,87 @@ void UserInputMapper::runMappings() {
|
|||
}
|
||||
|
||||
// Now process the current values for each level of the stack
|
||||
for (auto& mapping : _activeMappings) {
|
||||
for (const auto& route : mapping->routes) {
|
||||
if (route->conditional) {
|
||||
if (!route->conditional->satisfied()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (const auto& route : _deviceRoutes) {
|
||||
if (!route) {
|
||||
continue;
|
||||
}
|
||||
applyRoute(route);
|
||||
}
|
||||
|
||||
auto source = route->source;
|
||||
if (_overrides.count(source)) {
|
||||
source = _overrides[source];
|
||||
}
|
||||
for (const auto& route : _standardRoutes) {
|
||||
if (!route) {
|
||||
continue;
|
||||
}
|
||||
applyRoute(route);
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME?, should come before or after the override logic?
|
||||
if (!destination->writeable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
Pose value = getPose(source);
|
||||
// no filters yet for pose
|
||||
destination->apply(value, Pose(), source);
|
||||
} else {
|
||||
// Fetch the value, may have been overriden by previous loopback routes
|
||||
float value = getValue(source);
|
||||
|
||||
// Apply each of the filters.
|
||||
for (const auto& filter : route->filters) {
|
||||
value = filter->apply(value);
|
||||
}
|
||||
|
||||
destination->apply(value, 0, source);
|
||||
}
|
||||
void UserInputMapper::applyRoute(const Route::Pointer& route) {
|
||||
if (route->conditional) {
|
||||
if (!route->conditional->satisfied()) {
|
||||
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
|
||||
// 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()) {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME?, should come before or after the override logic?
|
||||
if (!destination->writeable()) {
|
||||
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()) {
|
||||
Pose value = getPose(source);
|
||||
// no filters yet for pose
|
||||
destination->apply(value, Pose(), source);
|
||||
} else {
|
||||
// Fetch the value, may have been overriden by previous loopback routes
|
||||
float value = getValue(source);
|
||||
|
||||
// Apply each of the filters.
|
||||
for (const auto& filter : route->filters) {
|
||||
value = filter->apply(value);
|
||||
}
|
||||
|
||||
destination->apply(value, 0, source);
|
||||
}
|
||||
}
|
||||
|
||||
Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) {
|
||||
|
@ -744,6 +754,7 @@ Endpoint::Pointer UserInputMapper::endpointFor(const QScriptValue& endpoint) {
|
|||
}
|
||||
|
||||
Endpoint::Pointer UserInputMapper::endpointFor(const Input& inputId) const {
|
||||
Locker locker(_lock);
|
||||
auto iterator = _endpointsByInput.find(inputId);
|
||||
if (_endpointsByInput.end() == iterator) {
|
||||
qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
|
||||
|
@ -767,6 +778,7 @@ Endpoint::Pointer UserInputMapper::compositeEndpointFor(Endpoint::Pointer first,
|
|||
|
||||
|
||||
Mapping::Pointer UserInputMapper::newMapping(const QString& mappingName) {
|
||||
Locker locker(_lock);
|
||||
if (_mappingsByName.count(mappingName)) {
|
||||
qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
|
||||
}
|
||||
|
@ -799,8 +811,8 @@ Mapping::Pointer UserInputMapper::newMapping(const QString& mappingName) {
|
|||
// return result;
|
||||
//}
|
||||
|
||||
|
||||
void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
|
||||
Locker locker(_lock);
|
||||
qCDebug(controllers) << "Attempting to enable mapping " << mappingName;
|
||||
auto iterator = _mappingsByName.find(mappingName);
|
||||
if (_mappingsByName.end() == iterator) {
|
||||
|
@ -810,18 +822,14 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
|
|||
|
||||
auto mapping = iterator->second;
|
||||
if (enable) {
|
||||
_activeMappings.push_front(mapping);
|
||||
enableMapping(mapping);
|
||||
} else {
|
||||
auto activeIterator = std::find(_activeMappings.begin(), _activeMappings.end(), mapping);
|
||||
if (_activeMappings.end() == activeIterator) {
|
||||
qCWarning(controllers) << "Attempted to disable inactive mapping " << mappingName;
|
||||
return;
|
||||
}
|
||||
_activeMappings.erase(activeIterator);
|
||||
disableMapping(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const {
|
||||
Locker locker(_lock);
|
||||
auto valuesIterator = _overrides.find(endpoint);
|
||||
if (_overrides.end() != valuesIterator) {
|
||||
return valuesIterator->second->value();
|
||||
|
@ -854,6 +862,7 @@ Pose UserInputMapper::getPose(const Input& input) const {
|
|||
}
|
||||
|
||||
Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) {
|
||||
Locker locker(_lock);
|
||||
if (jsonFile.isEmpty()) {
|
||||
return Mapping::Pointer();
|
||||
}
|
||||
|
@ -1102,6 +1111,36 @@ Mapping::Pointer UserInputMapper::parseMapping(const QString& json) {
|
|||
return parseMapping(doc.object());
|
||||
}
|
||||
|
||||
|
||||
void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
|
||||
Locker locker(_lock);
|
||||
// New routes for a device get injected IN FRONT of existing routes. Routes
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
std::remove_if(_standardRoutes.begin(), _standardRoutes.end(), [&](Route::Pointer route)->bool {
|
||||
return routeSet.count(route) != 0;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "UserInputMapper.moc"
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <unordered_set>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include <QtQml/QJSValue>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
@ -119,10 +120,8 @@ namespace controller {
|
|||
void hardwareChanged();
|
||||
|
||||
protected:
|
||||
virtual void runMappings();
|
||||
// GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
|
||||
uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
|
||||
|
||||
InputDevice::Pointer _standardController;
|
||||
DevicesMap _registeredDevices;
|
||||
uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
|
||||
|
@ -142,6 +141,11 @@ namespace controller {
|
|||
|
||||
friend class RouteBuilderProxy;
|
||||
friend class MappingBuilderProxy;
|
||||
|
||||
void runMappings();
|
||||
void applyRoute(const Route::Pointer& route);
|
||||
void enableMapping(const Mapping::Pointer& mapping);
|
||||
void disableMapping(const Mapping::Pointer& mapping);
|
||||
Endpoint::Pointer endpointFor(const QJSValue& endpoint);
|
||||
Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
|
||||
Endpoint::Pointer endpointFor(const Input& endpoint) const;
|
||||
|
@ -163,9 +167,14 @@ namespace controller {
|
|||
|
||||
EndpointOverrideMap _overrides;
|
||||
MappingNameMap _mappingsByName;
|
||||
Mapping::Pointer _defaultMapping{ std::make_shared<Mapping>("Default") };
|
||||
MappingDeviceMap _mappingsByDevice;
|
||||
MappingStack _activeMappings;
|
||||
|
||||
Route::List _deviceRoutes;
|
||||
Route::List _standardRoutes;
|
||||
|
||||
using Locker = std::unique_lock<std::recursive_mutex>;
|
||||
|
||||
mutable std::recursive_mutex _lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue