mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 00:13:53 +02:00
Merge pull request #6108 from jherico/controllers
Controllers Branch - Breaking up UserInputMapper, restoring some mappings
This commit is contained in:
commit
9ae1da371e
22 changed files with 1471 additions and 1360 deletions
|
@ -1,171 +1,218 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import "controller"
|
||||
import "controls" as HifiControls
|
||||
import "styles"
|
||||
|
||||
HifiControls.VrDialog {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
title: "Controller Test"
|
||||
resizable: true
|
||||
contentImplicitWidth: clientArea.implicitWidth
|
||||
contentImplicitHeight: clientArea.implicitHeight
|
||||
backgroundColor: "beige"
|
||||
|
||||
property var actions: Controller.Actions
|
||||
property var standard: Controller.Standard
|
||||
property var hydra: null
|
||||
property var testMapping: null
|
||||
property var xbox: null
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
var xboxRegex = /^X360Controller/;
|
||||
var hydraRegex = /^Hydra/;
|
||||
for (var prop in Controller.Hardware) {
|
||||
if(xboxRegex.test(prop)) {
|
||||
root.xbox = Controller.Hardware[prop]
|
||||
print("found xbox")
|
||||
continue
|
||||
}
|
||||
if (hydraRegex.test(prop)) {
|
||||
root.hydra = Controller.Hardware[prop]
|
||||
print("found hydra")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: clientArea
|
||||
spacing: 12
|
||||
x: root.clientX
|
||||
y: root.clientY
|
||||
|
||||
Row {
|
||||
spacing: 8
|
||||
Button {
|
||||
text: "Default Mapping"
|
||||
onClicked: {
|
||||
var mapping = Controller.newMapping("Default");
|
||||
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);
|
||||
Controller.enableMapping("Default");
|
||||
enabled = false;
|
||||
text = "Built"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Build Mapping"
|
||||
onClicked: {
|
||||
var mapping = Controller.newMapping();
|
||||
// Inverting a value
|
||||
mapping.from(hydra.RY).invert().to(standard.RY);
|
||||
mapping.from(hydra.RX).to(standard.RX);
|
||||
mapping.from(hydra.LY).to(standard.LY);
|
||||
mapping.from(hydra.LY).to(standard.LX);
|
||||
// Assigning a value from a function
|
||||
// mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
|
||||
// Constrainting a value to -1, 0, or 1, with a deadzone
|
||||
// mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
|
||||
mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
|
||||
// mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
|
||||
// mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
|
||||
// mapping.modifier(keyboard.Ctrl).scale(2.0)
|
||||
// mapping.from(keyboard.A).to(actions.TranslateLeft)
|
||||
// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
|
||||
// mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
|
||||
// // First loopbacks
|
||||
// // Then non-loopbacks by constraint level (number of inputs)
|
||||
// mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
|
||||
// mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
|
||||
// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
|
||||
// mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
|
||||
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 {
|
||||
Xbox { device: root.standard; label: "Standard"; width: 360 }
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 8
|
||||
Xbox { device: root.xbox; label: "XBox"; width: 360 }
|
||||
Hydra { device: root.hydra; width: 360 }
|
||||
}
|
||||
// Row {
|
||||
// spacing: 8
|
||||
// ScrollingGraph {
|
||||
// controlId: Controller.Actions.Yaw
|
||||
// label: "Yaw"
|
||||
// min: -3.0
|
||||
// max: 3.0
|
||||
// size: 128
|
||||
// }
|
||||
//
|
||||
// ScrollingGraph {
|
||||
// controlId: Controller.Actions.YAW_LEFT
|
||||
// label: "Yaw Left"
|
||||
// min: -3.0
|
||||
// max: 3.0
|
||||
// size: 128
|
||||
// }
|
||||
//
|
||||
// ScrollingGraph {
|
||||
// controlId: Controller.Actions.YAW_RIGHT
|
||||
// label: "Yaw Right"
|
||||
// min: -3.0
|
||||
// max: 3.0
|
||||
// size: 128
|
||||
// }
|
||||
// }
|
||||
}
|
||||
} // dialog
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import "controller"
|
||||
import "controls" as HifiControls
|
||||
import "styles"
|
||||
|
||||
HifiControls.VrDialog {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
title: "Controller Test"
|
||||
resizable: true
|
||||
contentImplicitWidth: clientArea.implicitWidth
|
||||
contentImplicitHeight: clientArea.implicitHeight
|
||||
backgroundColor: "beige"
|
||||
|
||||
property var actions: Controller.Actions
|
||||
property var standard: Controller.Standard
|
||||
property var hydra: null
|
||||
property var testMapping: null
|
||||
property var xbox: null
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
var xboxRegex = /^X360Controller/;
|
||||
var hydraRegex = /^Hydra/;
|
||||
for (var prop in Controller.Hardware) {
|
||||
if(xboxRegex.test(prop)) {
|
||||
root.xbox = Controller.Hardware[prop]
|
||||
print("found xbox")
|
||||
continue
|
||||
}
|
||||
if (hydraRegex.test(prop)) {
|
||||
root.hydra = Controller.Hardware[prop]
|
||||
print("found hydra")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: clientArea
|
||||
spacing: 12
|
||||
x: root.clientX
|
||||
y: root.clientY
|
||||
|
||||
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
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
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(hydra.RY).invert().to(standard.RY);
|
||||
mapping.from(hydra.RX).to(standard.RX);
|
||||
mapping.from(hydra.LY).to(standard.LY);
|
||||
mapping.from(hydra.LX).to(standard.LX);
|
||||
// Assigning a value from a function
|
||||
// mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
|
||||
// Constrainting a value to -1, 0, or 1, with a deadzone
|
||||
// mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
|
||||
mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
|
||||
// mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
|
||||
// mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
|
||||
// mapping.modifier(keyboard.Ctrl).scale(2.0)
|
||||
// mapping.from(keyboard.A).to(actions.TranslateLeft)
|
||||
// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
|
||||
// mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
|
||||
// // First loopbacks
|
||||
// // Then non-loopbacks by constraint level (number of inputs)
|
||||
// mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
|
||||
// mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
|
||||
// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
|
||||
// mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
|
||||
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 {
|
||||
Xbox { device: root.standard; label: "Standard"; width: 360 }
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 8
|
||||
Xbox { device: root.xbox; label: "XBox"; width: 360 }
|
||||
Hydra { device: root.hydra; width: 360 }
|
||||
}
|
||||
// Row {
|
||||
// spacing: 8
|
||||
// ScrollingGraph {
|
||||
// controlId: Controller.Actions.Yaw
|
||||
// label: "Yaw"
|
||||
// min: -3.0
|
||||
// max: 3.0
|
||||
// size: 128
|
||||
// }
|
||||
//
|
||||
// ScrollingGraph {
|
||||
// controlId: Controller.Actions.YAW_LEFT
|
||||
// label: "Yaw Left"
|
||||
// min: -3.0
|
||||
// max: 3.0
|
||||
// size: 128
|
||||
// }
|
||||
//
|
||||
// ScrollingGraph {
|
||||
// controlId: Controller.Actions.YAW_RIGHT
|
||||
// label: "Yaw Right"
|
||||
// min: -3.0
|
||||
// max: 3.0
|
||||
// size: 128
|
||||
// }
|
||||
// }
|
||||
}
|
||||
} // dialog
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2710,22 +2710,6 @@ void Application::update(float deltaTime) {
|
|||
auto myAvatar = getMyAvatar();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
|
||||
// userInputMapper->update(deltaTime);
|
||||
|
||||
// This needs to go after userInputMapper->update() because of the keyboard
|
||||
bool jointsCaptured = false;
|
||||
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
|
||||
foreach(auto inputPlugin, inputPlugins) {
|
||||
QString name = inputPlugin->getName();
|
||||
QAction* action = Menu::getInstance()->getActionForOption(name);
|
||||
if (action && action->isChecked()) {
|
||||
inputPlugin->pluginUpdate(deltaTime, jointsCaptured);
|
||||
if (inputPlugin->isJointController()) {
|
||||
jointsCaptured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch input events
|
||||
_controllerScriptingInterface->update();
|
||||
|
||||
|
|
|
@ -23,109 +23,6 @@
|
|||
// TODO: this needs to be removed, as well as any related controller-specific information
|
||||
#include <input-plugins/SixenseManager.h>
|
||||
|
||||
ControllerScriptingInterface::ControllerScriptingInterface() :
|
||||
_mouseCaptured(false),
|
||||
_touchCaptured(false),
|
||||
_wheelCaptured(false),
|
||||
_actionsCaptured(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ControllerScriptingInterface::~ControllerScriptingInterface() {
|
||||
}
|
||||
|
||||
|
||||
static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
|
||||
static int inputChannelMetaTypeId = qRegisterMetaType<UserInputMapper::InputChannel>();
|
||||
static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
|
||||
static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
|
||||
|
||||
QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input);
|
||||
void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input);
|
||||
QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel);
|
||||
void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel);
|
||||
QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action);
|
||||
void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action);
|
||||
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair);
|
||||
void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair);
|
||||
|
||||
QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("device", input.getDevice());
|
||||
obj.setProperty("channel", input.getChannel());
|
||||
obj.setProperty("type", (unsigned short) input.getType());
|
||||
obj.setProperty("id", input.getID());
|
||||
return obj;
|
||||
}
|
||||
|
||||
void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) {
|
||||
input.setDevice(object.property("device").toUInt16());
|
||||
input.setChannel(object.property("channel").toUInt16());
|
||||
input.setType(object.property("type").toUInt16());
|
||||
input.setID(object.property("id").toInt32());
|
||||
}
|
||||
|
||||
QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("input", inputToScriptValue(engine, inputChannel.getInput()));
|
||||
obj.setProperty("modifier", inputToScriptValue(engine, inputChannel.getModifier()));
|
||||
obj.setProperty("action", inputChannel.getAction());
|
||||
obj.setProperty("scale", inputChannel.getScale());
|
||||
return obj;
|
||||
}
|
||||
|
||||
void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel) {
|
||||
UserInputMapper::Input input;
|
||||
UserInputMapper::Input modifier;
|
||||
inputFromScriptValue(object.property("input"), input);
|
||||
inputChannel.setInput(input);
|
||||
inputFromScriptValue(object.property("modifier"), modifier);
|
||||
inputChannel.setModifier(modifier);
|
||||
inputChannel.setAction(UserInputMapper::Action(object.property("action").toVariant().toInt()));
|
||||
inputChannel.setScale(object.property("scale").toVariant().toFloat());
|
||||
}
|
||||
|
||||
QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
QVector<UserInputMapper::InputChannel> inputChannels = userInputMapper->getInputChannelsForAction(action);
|
||||
QScriptValue _inputChannels = engine->newArray(inputChannels.size());
|
||||
for (int i = 0; i < inputChannels.size(); i++) {
|
||||
_inputChannels.setProperty(i, inputChannelToScriptValue(engine, inputChannels[i]));
|
||||
}
|
||||
obj.setProperty("action", (int) action);
|
||||
obj.setProperty("actionName", userInputMapper->getActionName(action));
|
||||
obj.setProperty("inputChannels", _inputChannels);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) {
|
||||
action = UserInputMapper::Action(object.property("action").toVariant().toInt());
|
||||
}
|
||||
|
||||
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("input", inputToScriptValue(engine, inputPair.first));
|
||||
obj.setProperty("inputName", inputPair.second);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) {
|
||||
inputFromScriptValue(object.property("input"), inputPair.first);
|
||||
inputPair.second = QString(object.property("inputName").toVariant().toString());
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::registerControllerTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
|
||||
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputChannel> >(engine);
|
||||
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
|
||||
qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
|
||||
if (event->type() == HFActionEvent::startType()) {
|
||||
emit actionStartEvent(static_cast<HFActionEvent&>(*event));
|
||||
|
@ -183,162 +80,6 @@ const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
bool ControllerScriptingInterface::isPrimaryButtonPressed() const {
|
||||
const PalmData* primaryPalm = getPrimaryPalm();
|
||||
if (primaryPalm) {
|
||||
if (primaryPalm->getControllerButtons() & BUTTON_FWD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::vec2 ControllerScriptingInterface::getPrimaryJoystickPosition() const {
|
||||
const PalmData* primaryPalm = getPrimaryPalm();
|
||||
if (primaryPalm) {
|
||||
return glm::vec2(primaryPalm->getJoystickX(), primaryPalm->getJoystickY());
|
||||
}
|
||||
|
||||
return glm::vec2(0);
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::getNumberOfButtons() const {
|
||||
return getNumberOfActivePalms() * NUMBER_OF_BUTTONS_PER_PALM;
|
||||
}
|
||||
|
||||
bool ControllerScriptingInterface::isButtonPressed(int buttonIndex) const {
|
||||
int palmIndex = buttonIndex / NUMBER_OF_BUTTONS_PER_PALM;
|
||||
int buttonOnPalm = buttonIndex % NUMBER_OF_BUTTONS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (buttonOnPalm) {
|
||||
case 0:
|
||||
return palmData->getControllerButtons() & BUTTON_0;
|
||||
case 1:
|
||||
return palmData->getControllerButtons() & BUTTON_1;
|
||||
case 2:
|
||||
return palmData->getControllerButtons() & BUTTON_2;
|
||||
case 3:
|
||||
return palmData->getControllerButtons() & BUTTON_3;
|
||||
case 4:
|
||||
return palmData->getControllerButtons() & BUTTON_4;
|
||||
case 5:
|
||||
return palmData->getControllerButtons() & BUTTON_FWD;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::getNumberOfTriggers() const {
|
||||
return getNumberOfActivePalms() * NUMBER_OF_TRIGGERS_PER_PALM;
|
||||
}
|
||||
|
||||
float ControllerScriptingInterface::getTriggerValue(int triggerIndex) const {
|
||||
// we know there's one trigger per palm, so the triggerIndex is the palm Index
|
||||
int palmIndex = triggerIndex;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
return palmData->getTrigger();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::getNumberOfJoysticks() const {
|
||||
return getNumberOfActivePalms() * NUMBER_OF_JOYSTICKS_PER_PALM;
|
||||
}
|
||||
|
||||
glm::vec2 ControllerScriptingInterface::getJoystickPosition(int joystickIndex) const {
|
||||
// we know there's one joystick per palm, so the joystickIndex is the palm Index
|
||||
int palmIndex = joystickIndex;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
return glm::vec2(palmData->getJoystickX(), palmData->getJoystickY());
|
||||
}
|
||||
return glm::vec2(0);
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::getNumberOfSpatialControls() const {
|
||||
return getNumberOfActivePalms() * NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
}
|
||||
|
||||
glm::vec3 ControllerScriptingInterface::getSpatialControlPosition(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getPosition();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getTipPosition();
|
||||
}
|
||||
}
|
||||
return glm::vec3(0); // bad index
|
||||
}
|
||||
|
||||
glm::vec3 ControllerScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getVelocity();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getTipVelocity();
|
||||
}
|
||||
}
|
||||
return glm::vec3(0); // bad index
|
||||
}
|
||||
|
||||
glm::quat ControllerScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getRawRotation();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getRawRotation(); // currently the tip doesn't have a unique rotation, use the palm rotation
|
||||
}
|
||||
}
|
||||
return glm::quat(); // bad index
|
||||
}
|
||||
|
||||
glm::vec3 ControllerScriptingInterface::getSpatialControlRawAngularVelocity(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getRawAngularVelocity();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getRawAngularVelocity(); // Tip = palm angular velocity
|
||||
}
|
||||
}
|
||||
return glm::vec3(0); // bad index
|
||||
}
|
||||
|
||||
glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getNormal();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getFingerDirection();
|
||||
}
|
||||
}
|
||||
return glm::vec3(0); // bad index
|
||||
}
|
||||
*/
|
||||
|
||||
bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const {
|
||||
return isKeyCaptured(KeyEvent(*event));
|
||||
}
|
||||
|
@ -432,15 +173,18 @@ void ControllerScriptingInterface::update() {
|
|||
float delta = now - last;
|
||||
last = now;
|
||||
|
||||
for(auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
DependencyManager::get<UserInputMapper>()->update(delta);
|
||||
|
||||
bool jointsCaptured = false;
|
||||
for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (inputPlugin->isActive()) {
|
||||
inputPlugin->pluginUpdate(delta, false);
|
||||
inputPlugin->pluginUpdate(delta, jointsCaptured);
|
||||
if (inputPlugin->isJointController()) {
|
||||
jointsCaptured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->update(delta);
|
||||
|
||||
for (auto entry : _inputControllers) {
|
||||
entry.second->update();
|
||||
}
|
||||
|
@ -448,62 +192,6 @@ void ControllerScriptingInterface::update() {
|
|||
controller::ScriptingInterface::update();
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::Action> ControllerScriptingInterface::getAllActions() {
|
||||
return DependencyManager::get<UserInputMapper>()->getAllActions();
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputChannel> ControllerScriptingInterface::getInputChannelsForAction(UserInputMapper::Action action) {
|
||||
return DependencyManager::get<UserInputMapper>()->getInputChannelsForAction(action);
|
||||
}
|
||||
|
||||
QString ControllerScriptingInterface::getDeviceName(unsigned int device) {
|
||||
return DependencyManager::get<UserInputMapper>()->getDeviceName((unsigned short)device);
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputChannel> ControllerScriptingInterface::getAllInputsForDevice(unsigned int device) {
|
||||
return DependencyManager::get<UserInputMapper>()->getAllInputsForDevice(device);
|
||||
}
|
||||
|
||||
bool ControllerScriptingInterface::addInputChannel(UserInputMapper::InputChannel inputChannel) {
|
||||
return DependencyManager::get<UserInputMapper>()->addInputChannel(inputChannel._action, inputChannel._input, inputChannel._modifier, inputChannel._scale);
|
||||
}
|
||||
|
||||
bool ControllerScriptingInterface::removeInputChannel(UserInputMapper::InputChannel inputChannel) {
|
||||
return DependencyManager::get<UserInputMapper>()->removeInputChannel(inputChannel);
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputPair> ControllerScriptingInterface::getAvailableInputs(unsigned int device) {
|
||||
return DependencyManager::get<UserInputMapper>()->getAvailableInputs((unsigned short)device);
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::resetAllDeviceBindings() {
|
||||
DependencyManager::get<UserInputMapper>()->resetAllDeviceBindings();
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::resetDevice(unsigned int device) {
|
||||
DependencyManager::get<UserInputMapper>()->resetDevice(device);
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::findDevice(QString name) {
|
||||
return DependencyManager::get<UserInputMapper>()->findDevice(name);
|
||||
}
|
||||
|
||||
QVector<QString> ControllerScriptingInterface::getDeviceNames() {
|
||||
return DependencyManager::get<UserInputMapper>()->getDeviceNames();
|
||||
}
|
||||
|
||||
float ControllerScriptingInterface::getActionValue(int action) {
|
||||
return DependencyManager::get<UserInputMapper>()->getActionState(UserInputMapper::Action(action));
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::findAction(QString actionName) {
|
||||
return DependencyManager::get<UserInputMapper>()->findAction(actionName);
|
||||
}
|
||||
|
||||
QVector<QString> ControllerScriptingInterface::getActionNames() const {
|
||||
return DependencyManager::get<UserInputMapper>()->getActionNames();
|
||||
}
|
||||
|
||||
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
|
||||
_deviceTrackerId(deviceTrackerId),
|
||||
_subTrackerId(subTrackerId),
|
||||
|
|
|
@ -63,33 +63,8 @@ class ControllerScriptingInterface : public controller::ScriptingInterface {
|
|||
|
||||
|
||||
public:
|
||||
ControllerScriptingInterface();
|
||||
~ControllerScriptingInterface();
|
||||
virtual ~ControllerScriptingInterface() {}
|
||||
|
||||
Q_INVOKABLE QVector<UserInputMapper::Action> getAllActions();
|
||||
|
||||
Q_INVOKABLE bool addInputChannel(UserInputMapper::InputChannel inputChannel);
|
||||
Q_INVOKABLE bool removeInputChannel(UserInputMapper::InputChannel inputChannel);
|
||||
Q_INVOKABLE QVector<UserInputMapper::InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
|
||||
|
||||
Q_INVOKABLE QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
|
||||
Q_INVOKABLE QVector<UserInputMapper::InputChannel> getAllInputsForDevice(unsigned int device);
|
||||
|
||||
Q_INVOKABLE QString getDeviceName(unsigned int device);
|
||||
|
||||
Q_INVOKABLE float getActionValue(int action);
|
||||
|
||||
Q_INVOKABLE void resetDevice(unsigned int device);
|
||||
Q_INVOKABLE void resetAllDeviceBindings();
|
||||
Q_INVOKABLE int findDevice(QString name);
|
||||
Q_INVOKABLE QVector<QString> getDeviceNames();
|
||||
|
||||
Q_INVOKABLE int findAction(QString actionName);
|
||||
Q_INVOKABLE QVector<QString> getActionNames() const;
|
||||
|
||||
|
||||
virtual void registerControllerTypes(QScriptEngine* engine);
|
||||
|
||||
void emitKeyPressEvent(QKeyEvent* event);
|
||||
void emitKeyReleaseEvent(QKeyEvent* event);
|
||||
|
||||
|
@ -108,10 +83,6 @@ public:
|
|||
|
||||
bool isKeyCaptured(QKeyEvent* event) const;
|
||||
bool isKeyCaptured(const KeyEvent& event) const;
|
||||
bool isMouseCaptured() const { return _mouseCaptured; }
|
||||
bool isTouchCaptured() const { return _touchCaptured; }
|
||||
bool isWheelCaptured() const { return _wheelCaptured; }
|
||||
bool areActionsCaptured() const { return _actionsCaptured; }
|
||||
bool isJoystickCaptured(int joystickIndex) const;
|
||||
|
||||
virtual void update() override;
|
||||
|
@ -121,18 +92,6 @@ public slots:
|
|||
virtual void captureKeyEvents(const KeyEvent& event);
|
||||
virtual void releaseKeyEvents(const KeyEvent& event);
|
||||
|
||||
virtual void captureMouseEvents() { _mouseCaptured = true; }
|
||||
virtual void releaseMouseEvents() { _mouseCaptured = false; }
|
||||
|
||||
virtual void captureTouchEvents() { _touchCaptured = true; }
|
||||
virtual void releaseTouchEvents() { _touchCaptured = false; }
|
||||
|
||||
virtual void captureWheelEvents() { _wheelCaptured = true; }
|
||||
virtual void releaseWheelEvents() { _wheelCaptured = false; }
|
||||
|
||||
virtual void captureActionEvents() { _actionsCaptured = true; }
|
||||
virtual void releaseActionEvents() { _actionsCaptured = false; }
|
||||
|
||||
virtual void captureJoystick(int joystickIndex);
|
||||
virtual void releaseJoystick(int joystickIndex);
|
||||
|
||||
|
@ -173,10 +132,6 @@ private:
|
|||
int getNumberOfActivePalms() const;
|
||||
const PalmData* getActivePalm(int palmIndex) const;
|
||||
|
||||
bool _mouseCaptured;
|
||||
bool _touchCaptured;
|
||||
bool _wheelCaptured;
|
||||
bool _actionsCaptured;
|
||||
QMultiMap<int,KeyEvent> _capturedKeys;
|
||||
QSet<int> _capturedJoysticks;
|
||||
|
||||
|
|
31
libraries/controllers/src/controllers/DeviceProxy.cpp
Normal file
31
libraries/controllers/src/controllers/DeviceProxy.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/10/18
|
||||
// (based on UserInputMapper inner class created by Sam Gateau on 4/27/15)
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "DeviceProxy.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
float DeviceProxy::getValue(const Input& input, int timestamp) const {
|
||||
switch (input.getType()) {
|
||||
case ChannelType::BUTTON:
|
||||
return getButton(input, timestamp) ? 1.0f : 0.0f;
|
||||
|
||||
case ChannelType::AXIS:
|
||||
return getAxis(input, timestamp);
|
||||
|
||||
case ChannelType::POSE:
|
||||
return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
|
||||
|
||||
default:
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
57
libraries/controllers/src/controllers/DeviceProxy.h
Normal file
57
libraries/controllers/src/controllers/DeviceProxy.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/10/18
|
||||
// (based on UserInputMapper inner class created by Sam Gateau on 4/27/15)
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_controllers_DeviceProxy_h
|
||||
#define hifi_controllers_DeviceProxy_h
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include "Input.h"
|
||||
#include "Pose.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
using Modifiers = std::vector<Input>;
|
||||
typedef QPair<Input, QString> InputPair;
|
||||
|
||||
|
||||
template<typename T>
|
||||
using InputGetter = std::function<T(const Input& input, int timestamp)>;
|
||||
using ButtonGetter = InputGetter<bool>;
|
||||
using AxisGetter = InputGetter<float>;
|
||||
using PoseGetter = InputGetter<Pose>;
|
||||
using ResetBindings = std::function<bool()>;
|
||||
using AvailableInputGetter = std::function<Input::NamedVector()>;
|
||||
|
||||
class DeviceProxy {
|
||||
public:
|
||||
DeviceProxy(QString name) : _baseName(name), _name(name) {}
|
||||
const QString& getBaseName() const { return _baseName; }
|
||||
const QString& getName() const { return _name; }
|
||||
|
||||
ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
|
||||
AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; };
|
||||
PoseGetter getPose = [](const Input& input, int timestamp) -> Pose { return Pose(); };
|
||||
AvailableInputGetter getAvailabeInputs = []() -> Input::NamedVector { return Input::NamedVector(); };
|
||||
ResetBindings resetDeviceBindings = [] () -> bool { return true; };
|
||||
float getValue(const Input& input, int timestamp = 0) const;
|
||||
|
||||
using Pointer = std::shared_ptr<DeviceProxy>;
|
||||
|
||||
QString _baseName;
|
||||
QString _name;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
19
libraries/controllers/src/controllers/Input.cpp
Normal file
19
libraries/controllers/src/controllers/Input.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/10/18
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Input.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
const Input Input::INVALID_INPUT = Input(UINT32_MAX);
|
||||
const uint16_t Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
|
||||
const uint16_t Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
|
||||
const uint16_t Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
|
||||
|
||||
}
|
||||
|
76
libraries/controllers/src/controllers/Input.h
Normal file
76
libraries/controllers/src/controllers/Input.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/10/18
|
||||
// (based on UserInputMapper inner class created by Sam Gateau on 4/27/15)
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_controllers_Input_h
|
||||
#define hifi_controllers_Input_h
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
namespace controller {
|
||||
|
||||
enum class ChannelType {
|
||||
UNKNOWN = 0,
|
||||
BUTTON = 1,
|
||||
AXIS,
|
||||
POSE,
|
||||
};
|
||||
|
||||
// Input is the unique identifier to find a n input channel of a particular device
|
||||
// Devices are responsible for registering to the UseInputMapper so their input channels can be sued and mapped
|
||||
// to the Action channels
|
||||
struct Input {
|
||||
union {
|
||||
struct {
|
||||
uint16_t _device; // Up to 64K possible devices
|
||||
uint16_t _channel : 13; // 2^13 possible channel per Device
|
||||
uint16_t _type : 2; // 2 bits to store the Type directly in the ID
|
||||
uint16_t _padding : 1; // 2 bits to store the Type directly in the ID
|
||||
};
|
||||
uint32_t _id = 0; // by default Input is 0 meaning invalid
|
||||
};
|
||||
|
||||
bool isValid() const { return (_id != 0); }
|
||||
|
||||
uint16_t getDevice() const { return _device; }
|
||||
uint16_t getChannel() const { return _channel; }
|
||||
uint32_t getID() const { return _id; }
|
||||
ChannelType getType() const { return (ChannelType) _type; }
|
||||
|
||||
void setDevice(uint16_t device) { _device = device; }
|
||||
void setChannel(uint16_t channel) { _channel = channel; }
|
||||
void setType(uint16_t type) { _type = type; }
|
||||
void setID(uint32_t ID) { _id = ID; }
|
||||
|
||||
bool isButton() const { return getType() == ChannelType::BUTTON; }
|
||||
bool isAxis() const { return getType() == ChannelType::AXIS; }
|
||||
bool isPose() const { return getType() == ChannelType::POSE; }
|
||||
|
||||
// WORKAROUND: the explicit initializer here avoids a bug in GCC-4.8.2 (but not found in 4.9.2)
|
||||
// where the default initializer (a C++-11ism) for the union data above is not applied.
|
||||
explicit Input() : _id(0) {}
|
||||
explicit Input(uint32_t id) : _id(id) {}
|
||||
explicit Input(uint16_t device, uint16_t channel, ChannelType type) : _device(device), _channel(channel), _type(uint16_t(type)), _padding(0) {}
|
||||
Input(const Input& src) : _id(src._id) {}
|
||||
Input& operator = (const Input& src) { _id = src._id; return (*this); }
|
||||
bool operator ==(const Input& right) const { return _id == right._id; }
|
||||
bool operator < (const Input& src) const { return _id < src._id; }
|
||||
|
||||
static const Input INVALID_INPUT;
|
||||
static const uint16_t INVALID_DEVICE;
|
||||
static const uint16_t INVALID_CHANNEL;
|
||||
static const uint16_t INVALID_TYPE;
|
||||
|
||||
using NamedPair = QPair<Input, QString>;
|
||||
using NamedVector = QVector<NamedPair>;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -13,7 +13,7 @@
|
|||
bool InputDevice::_lowVelocityFilter = false;
|
||||
|
||||
const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
|
||||
float InputDevice::reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
|
||||
float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
|
||||
|
||||
//Constants for getCursorPixelRangeMultiplier()
|
||||
const float MIN_PIXEL_RANGE_MULT = 0.4f;
|
||||
|
@ -23,7 +23,7 @@ const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f;
|
|||
//Returns a multiplier to be applied to the cursor range for the controllers
|
||||
float InputDevice::getCursorPixelRangeMult() {
|
||||
//scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT)
|
||||
return InputDevice::reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
|
||||
return InputDevice::_reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
|
||||
}
|
||||
|
||||
float InputDevice::getButton(int channel) const {
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
UserInputMapper::PoseValue getPose(int channel) const;
|
||||
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) = 0;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) {};
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) = 0;
|
||||
|
||||
// Update call MUST be called once per simulation loop
|
||||
// It takes care of updating the action states and deltas
|
||||
|
@ -45,8 +45,8 @@ public:
|
|||
int getDeviceID() { return _deviceID; }
|
||||
|
||||
static float getCursorPixelRangeMult();
|
||||
static float getReticleMoveSpeed() { return reticleMoveSpeed; }
|
||||
static void setReticleMoveSpeed(float sixenseReticleMoveSpeed) { reticleMoveSpeed = sixenseReticleMoveSpeed; }
|
||||
static float getReticleMoveSpeed() { return _reticleMoveSpeed; }
|
||||
static void setReticleMoveSpeed(float reticleMoveSpeed) { _reticleMoveSpeed = reticleMoveSpeed; }
|
||||
|
||||
static bool getLowVelocityFilter() { return _lowVelocityFilter; };
|
||||
|
||||
|
@ -72,5 +72,5 @@ protected:
|
|||
static bool _lowVelocityFilter;
|
||||
|
||||
private:
|
||||
static float reticleMoveSpeed;
|
||||
static float _reticleMoveSpeed;
|
||||
};
|
30
libraries/controllers/src/controllers/Pose.cpp
Normal file
30
libraries/controllers/src/controllers/Pose.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/10/18
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Pose.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
Pose::Pose(const vec3& translation, const quat& rotation,
|
||||
const vec3& velocity, const quat& angularVelocity) :
|
||||
_translation(translation), _rotation(rotation), _velocity(velocity), _angularVelocity(angularVelocity) { }
|
||||
|
||||
bool Pose::operator==(const Pose& right) const {
|
||||
// invalid poses return false for comparison, even against identical invalid poses, like NaN
|
||||
if (_valid || !right._valid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME add margin of error? Or add an additional withinEpsilon function?
|
||||
return _translation == right.getTranslation() && _rotation == right.getRotation() &&
|
||||
_velocity == right.getVelocity() && _angularVelocity == right.getAngularVelocity();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
43
libraries/controllers/src/controllers/Pose.h
Normal file
43
libraries/controllers/src/controllers/Pose.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/10/18
|
||||
// (based on UserInputMapper inner class created by Sam Gateau on 4/27/15)
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_controllers_Pose_h
|
||||
#define hifi_controllers_Pose_h
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
namespace controller {
|
||||
|
||||
struct Pose {
|
||||
public:
|
||||
vec3 _translation;
|
||||
quat _rotation;
|
||||
vec3 _velocity;
|
||||
quat _angularVelocity;
|
||||
bool _valid{ false };
|
||||
|
||||
Pose() {}
|
||||
Pose(const vec3& translation, const quat& rotation,
|
||||
const vec3& velocity = vec3(), const quat& angularVelocity = quat());
|
||||
|
||||
Pose(const Pose&) = default;
|
||||
Pose& operator = (const Pose&) = default;
|
||||
bool operator ==(const Pose& right) const;
|
||||
bool isValid() const { return _valid; }
|
||||
vec3 getTranslation() const { return _translation; }
|
||||
quat getRotation() const { return _rotation; }
|
||||
vec3 getVelocity() const { return _velocity; }
|
||||
quat getAngularVelocity() const { return _angularVelocity; }
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -67,7 +67,7 @@ namespace controller {
|
|||
|
||||
void ScriptEndpoint::updateValue() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -80,10 +80,10 @@ namespace controller {
|
|||
|
||||
void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
|
||||
Q_ARG(float, newValue),
|
||||
Q_ARG(float, oldValue),
|
||||
Q_ARG(int, sourceID));
|
||||
QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
|
||||
Q_ARG(float, newValue),
|
||||
Q_ARG(float, oldValue),
|
||||
Q_ARG(int, sourceID));
|
||||
return;
|
||||
}
|
||||
_callable.call(QScriptValue(),
|
||||
|
@ -163,28 +163,28 @@ namespace controller {
|
|||
QJsonObject obj;
|
||||
QJsonParseError error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error);
|
||||
// check validity of the document
|
||||
if (!doc.isNull()) {
|
||||
if (doc.isObject()) {
|
||||
obj = doc.object();
|
||||
|
||||
// check validity of the document
|
||||
if (!doc.isNull()) {
|
||||
if (doc.isObject()) {
|
||||
obj = doc.object();
|
||||
|
||||
auto mapping = std::make_shared<Mapping>("default");
|
||||
auto mappingBuilder = new MappingBuilderProxy(*this, mapping);
|
||||
|
||||
mappingBuilder->parse(obj);
|
||||
|
||||
_mappingsByName[mapping->_name] = mapping;
|
||||
|
||||
return mappingBuilder;
|
||||
} else {
|
||||
qDebug() << "Mapping json Document is not an object" << endl;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Invalid JSON...\n";
|
||||
qDebug() << error.errorString();
|
||||
qDebug() << "JSON was:\n" << json << endl;
|
||||
|
||||
}
|
||||
|
||||
return mappingBuilder;
|
||||
} else {
|
||||
qDebug() << "Mapping json Document is not an object" << endl;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Invalid JSON...\n";
|
||||
qDebug() << error.errorString();
|
||||
qDebug() << "JSON was:\n" << json << endl;
|
||||
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ namespace controller {
|
|||
if (request->getResult() == ResourceRequest::Success) {
|
||||
result = parseMapping(QString(request->getData()));
|
||||
} else {
|
||||
qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl;
|
||||
qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl;
|
||||
}
|
||||
request->deleteLater();
|
||||
}
|
||||
|
@ -263,8 +263,8 @@ namespace controller {
|
|||
return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID());
|
||||
}
|
||||
|
||||
glm::mat4 ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
|
||||
return glm::mat4();
|
||||
Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
|
||||
return Pose();
|
||||
}
|
||||
|
||||
void ScriptingInterface::update() {
|
||||
|
@ -368,7 +368,7 @@ namespace controller {
|
|||
}
|
||||
|
||||
UserInputMapper::Input ScriptingInterface::inputFor(const QString& inputName) {
|
||||
return DependencyManager::get<UserInputMapper>()->findDeviceInput(inputName);
|
||||
return DependencyManager::get<UserInputMapper>()->findDeviceInput(inputName);
|
||||
}
|
||||
|
||||
Endpoint::Pointer ScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) {
|
||||
|
@ -494,6 +494,39 @@ namespace controller {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::Action> ScriptingInterface::getAllActions() {
|
||||
return DependencyManager::get<UserInputMapper>()->getAllActions();
|
||||
}
|
||||
|
||||
QString ScriptingInterface::getDeviceName(unsigned int device) {
|
||||
return DependencyManager::get<UserInputMapper>()->getDeviceName((unsigned short)device);
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputPair> ScriptingInterface::getAvailableInputs(unsigned int device) {
|
||||
return DependencyManager::get<UserInputMapper>()->getAvailableInputs((unsigned short)device);
|
||||
}
|
||||
|
||||
int ScriptingInterface::findDevice(QString name) {
|
||||
return DependencyManager::get<UserInputMapper>()->findDevice(name);
|
||||
}
|
||||
|
||||
QVector<QString> ScriptingInterface::getDeviceNames() {
|
||||
return DependencyManager::get<UserInputMapper>()->getDeviceNames();
|
||||
}
|
||||
|
||||
float ScriptingInterface::getActionValue(int action) {
|
||||
return DependencyManager::get<UserInputMapper>()->getActionState(UserInputMapper::Action(action));
|
||||
}
|
||||
|
||||
int ScriptingInterface::findAction(QString actionName) {
|
||||
return DependencyManager::get<UserInputMapper>()->findAction(actionName);
|
||||
}
|
||||
|
||||
QVector<QString> ScriptingInterface::getActionNames() const {
|
||||
return DependencyManager::get<UserInputMapper>()->getActionNames();
|
||||
}
|
||||
|
||||
} // namespace controllers
|
||||
|
||||
|
||||
|
@ -520,7 +553,7 @@ ScriptingInterface::ScriptingInterface() {
|
|||
int actionNumber = 0;
|
||||
qCDebug(controllers) << "Setting up standard actions";
|
||||
for (const auto& actionName : actionNames) {
|
||||
UserInputMapper::Input actionInput(UserInputMapper::Input::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
|
||||
UserInputMapper::Input actionInput(UserInputMapper::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
|
||||
qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16);
|
||||
// Expose the IDs to JS
|
||||
QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
|
||||
|
@ -532,43 +565,3 @@ ScriptingInterface::ScriptingInterface() {
|
|||
|
||||
updateMaps();
|
||||
}
|
||||
|
||||
//var mapping = Controller.newMapping();
|
||||
//mapping.map(hydra.LeftButton0, actions.ContextMenu);
|
||||
//mapping.map(hydra.LeftButton0).to(xbox.RT);
|
||||
//mapping.from(xbox.RT).constrainToBoolean().invert().to(actions.Foo)
|
||||
// mapping.from(xbox.RY).invert().deadZone(0.2).to(actions.Pitch)
|
||||
// mapping.from(xbox.RY).filter(function(newValue, oldValue) {
|
||||
// return newValue * 2.0
|
||||
//}).to(actions.Pitch)
|
||||
|
||||
//mapping.from(function(time) {
|
||||
// return Math.cos(time);
|
||||
// }).to(actions.Pitch);
|
||||
|
||||
// mapping.mapFromFunction(function() {
|
||||
// return x;
|
||||
// }, actions.ContextMenu);
|
||||
|
||||
// mapping.from(xbox.LY).clamp(0, 1).to(actions.Forward);
|
||||
// mapping.from(xbox.LY).clamp(-1, 0).to(actions.Backward);
|
||||
// mapping.from(xbox.RY).clamp(0, 1).to(actions.Forward);
|
||||
// mapping.from(xbox.RS).to();
|
||||
// mapping.from(xbox.ALL).to();
|
||||
|
||||
// mapping.from(xbox.RY).to(function(...) { ... });
|
||||
// mapping.from(xbox.RY).pass();
|
||||
|
||||
// mapping.suppress() ≅ mapping.to(null)
|
||||
// mapping.pass() ≅ mapping.to(fromControl)
|
||||
|
||||
// mapping.from(keyboard.RightParen).invert().to(actions.Yaw)
|
||||
// mapping.from(keyboard.LeftParen).to(actions.Yaw)
|
||||
|
||||
// mapping.from(hydra.LX).pulse(MIN_SNAP_TIME, 3.0).to(Actions.Yaw)
|
||||
|
||||
// mapping.from(keyboard.LeftParen).pulse(MIN_SNAP_TIME).to(Actions.Yaw)
|
||||
// // Enable and disable as above
|
||||
|
||||
// mappingSnap.from(hydra.LX).to(function(newValue, oldValue) {
|
||||
// timeSinceLastYaw += deltaTime
|
||||
|
|
|
@ -67,15 +67,22 @@ namespace controller {
|
|||
ScriptingInterface();
|
||||
virtual ~ScriptingInterface();
|
||||
|
||||
Q_INVOKABLE QVector<UserInputMapper::Action> getAllActions();
|
||||
Q_INVOKABLE QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
|
||||
Q_INVOKABLE QString getDeviceName(unsigned int device);
|
||||
Q_INVOKABLE float getActionValue(int action);
|
||||
Q_INVOKABLE int findDevice(QString name);
|
||||
Q_INVOKABLE QVector<QString> getDeviceNames();
|
||||
Q_INVOKABLE int findAction(QString actionName);
|
||||
Q_INVOKABLE QVector<QString> getActionNames() const;
|
||||
|
||||
Q_INVOKABLE float getValue(const int& source) const;
|
||||
Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
|
||||
Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const;
|
||||
Q_INVOKABLE glm::mat4 getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
|
||||
Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
|
||||
Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
|
||||
Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
|
||||
Q_INVOKABLE void disableMapping(const QString& mappingName) {
|
||||
enableMapping(mappingName, false);
|
||||
}
|
||||
Q_INVOKABLE void disableMapping(const QString& mappingName) { enableMapping(mappingName, false); }
|
||||
Q_INVOKABLE QObject* parseMapping(const QString& json);
|
||||
Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl);
|
||||
|
||||
|
@ -102,13 +109,30 @@ namespace controller {
|
|||
Q_INVOKABLE const QVariantMap& getActions() { return _actions; }
|
||||
Q_INVOKABLE const QVariantMap& getStandard() { return _standard; }
|
||||
|
||||
bool isMouseCaptured() const { return _mouseCaptured; }
|
||||
bool isTouchCaptured() const { return _touchCaptured; }
|
||||
bool isWheelCaptured() const { return _wheelCaptured; }
|
||||
bool areActionsCaptured() const { return _actionsCaptured; }
|
||||
|
||||
static QRegularExpression SANITIZE_NAME_EXPRESSION;
|
||||
|
||||
public slots:
|
||||
virtual void update();
|
||||
virtual void registerControllerTypes(QScriptEngine* engine) = 0;
|
||||
virtual void updateMaps();
|
||||
|
||||
virtual void captureMouseEvents() { _mouseCaptured = true; }
|
||||
virtual void releaseMouseEvents() { _mouseCaptured = false; }
|
||||
|
||||
virtual void captureTouchEvents() { _touchCaptured = true; }
|
||||
virtual void releaseTouchEvents() { _touchCaptured = false; }
|
||||
|
||||
virtual void captureWheelEvents() { _wheelCaptured = true; }
|
||||
virtual void releaseWheelEvents() { _wheelCaptured = false; }
|
||||
|
||||
virtual void captureActionEvents() { _actionsCaptured = true; }
|
||||
virtual void releaseActionEvents() { _actionsCaptured = false; }
|
||||
|
||||
|
||||
private:
|
||||
friend class MappingBuilderProxy;
|
||||
friend class RouteBuilderProxy;
|
||||
|
@ -141,6 +165,11 @@ namespace controller {
|
|||
ValueMap _overrideValues;
|
||||
MappingMap _mappingsByName;
|
||||
MappingStack _activeMappings;
|
||||
|
||||
bool _mouseCaptured{ false };
|
||||
bool _touchCaptured{ false };
|
||||
bool _wheelCaptured{ false };
|
||||
bool _actionsCaptured{ false };
|
||||
};
|
||||
|
||||
class ScriptEndpoint : public Endpoint {
|
||||
|
|
|
@ -96,16 +96,65 @@ void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
|
|||
return availableInputs;
|
||||
};
|
||||
|
||||
proxy->resetDeviceBindings = [this, &mapper] () -> bool {
|
||||
mapper.removeAllInputChannelsForDevice(_deviceID);
|
||||
this->assignDefaultInputMapping(mapper);
|
||||
return true;
|
||||
};
|
||||
|
||||
mapper.registerStandardDevice(proxy);
|
||||
}
|
||||
|
||||
void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
const float DPAD_MOVE_SPEED = 0.5f;
|
||||
const float JOYSTICK_YAW_SPEED = 0.5f;
|
||||
const float JOYSTICK_PITCH_SPEED = 0.25f;
|
||||
const float BOOM_SPEED = 0.1f;
|
||||
|
||||
// Y axes are flipped (up is negative)
|
||||
// Left Joystick: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED);
|
||||
// Right Joystick: Camera orientation
|
||||
mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED);
|
||||
|
||||
// Dpad movement
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED);
|
||||
|
||||
// Button controls
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED);
|
||||
|
||||
// Zoom
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LB), BOOM_SPEED);
|
||||
|
||||
// Hold front right shoulder button for precision controls
|
||||
// Left Joystick: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
|
||||
|
||||
// Right Joystick: Camera orientation
|
||||
mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
|
||||
|
||||
// Dpad movement
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
|
||||
// Button controls
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
|
||||
// Zoom
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
|
||||
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A));
|
||||
}
|
||||
|
||||
UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) {
|
||||
|
|
|
@ -1,115 +1,108 @@
|
|||
//
|
||||
// UserInputMapper.cpp
|
||||
// input-plugins/src/input-plugins
|
||||
//
|
||||
// Created by Sam Gateau on 4/27/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "UserInputMapper.h"
|
||||
#include "StandardController.h"
|
||||
|
||||
//
|
||||
// Created by Sam Gateau on 4/27/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "UserInputMapper.h"
|
||||
#include "StandardController.h"
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX);
|
||||
const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
|
||||
const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
|
||||
const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
|
||||
const uint16_t UserInputMapper::Input::ACTIONS_DEVICE = INVALID_DEVICE - (uint16)1;
|
||||
const uint16_t UserInputMapper::Input::STANDARD_DEVICE = 0;
|
||||
|
||||
// Default contruct allocate the poutput size with the current hardcoded action channels
|
||||
UserInputMapper::UserInputMapper() {
|
||||
registerStandardDevice();
|
||||
assignDefaulActionScales();
|
||||
createActionNames();
|
||||
}
|
||||
|
||||
UserInputMapper::~UserInputMapper() {
|
||||
}
|
||||
|
||||
int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
|
||||
if (!_deviceCounts.contains(deviceName)) {
|
||||
_deviceCounts[deviceName] = 0;
|
||||
}
|
||||
_deviceCounts[deviceName] += 1;
|
||||
return _deviceCounts[deviceName];
|
||||
}
|
||||
|
||||
bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) {
|
||||
int numberOfType = recordDeviceOfType(proxy->_name);
|
||||
|
||||
if (numberOfType > 1) {
|
||||
proxy->_name += QString::number(numberOfType);
|
||||
}
|
||||
|
||||
|
||||
const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - (uint16)1;
|
||||
const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
|
||||
|
||||
// Default contruct allocate the poutput size with the current hardcoded action channels
|
||||
UserInputMapper::UserInputMapper() {
|
||||
registerStandardDevice();
|
||||
assignDefaulActionScales();
|
||||
createActionNames();
|
||||
}
|
||||
|
||||
UserInputMapper::~UserInputMapper() {
|
||||
}
|
||||
|
||||
int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
|
||||
if (!_deviceCounts.contains(deviceName)) {
|
||||
_deviceCounts[deviceName] = 0;
|
||||
}
|
||||
_deviceCounts[deviceName] += 1;
|
||||
return _deviceCounts[deviceName];
|
||||
}
|
||||
|
||||
bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) {
|
||||
int numberOfType = recordDeviceOfType(proxy->_name);
|
||||
|
||||
if (numberOfType > 1) {
|
||||
proxy->_name += QString::number(numberOfType);
|
||||
}
|
||||
|
||||
qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
|
||||
_registeredDevices[deviceID] = proxy;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
_registeredDevices[deviceID] = proxy;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) {
|
||||
device->_name = "Standard"; // Just to make sure
|
||||
_registeredDevices[getStandardDeviceID()] = device;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
|
||||
auto device = _registeredDevices.find(input.getDevice());
|
||||
if (device != _registeredDevices.end()) {
|
||||
return (device->second);
|
||||
} else {
|
||||
return DeviceProxy::Pointer();
|
||||
}
|
||||
}
|
||||
|
||||
QString UserInputMapper::getDeviceName(uint16 deviceID) {
|
||||
if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
|
||||
return _registeredDevices[deviceID]->_name;
|
||||
}
|
||||
return QString("unknown");
|
||||
}
|
||||
|
||||
|
||||
void UserInputMapper::resetAllDeviceBindings() {
|
||||
for (auto device : _registeredDevices) {
|
||||
device.second->resetDeviceBindings();
|
||||
}
|
||||
}
|
||||
|
||||
void UserInputMapper::resetDevice(uint16 deviceID) {
|
||||
auto device = _registeredDevices.find(deviceID);
|
||||
if (device != _registeredDevices.end()) {
|
||||
device->second->resetDeviceBindings();
|
||||
}
|
||||
}
|
||||
|
||||
int UserInputMapper::findDevice(QString name) const {
|
||||
for (auto device : _registeredDevices) {
|
||||
if (device.second->_name.split(" (")[0] == name) {
|
||||
return device.first;
|
||||
} else if (device.second->_baseName == name) {
|
||||
return device.first;
|
||||
}
|
||||
}
|
||||
return Input::INVALID_DEVICE;
|
||||
}
|
||||
|
||||
QVector<QString> UserInputMapper::getDeviceNames() {
|
||||
QVector<QString> result;
|
||||
for (auto device : _registeredDevices) {
|
||||
QString deviceName = device.second->_name.split(" (")[0];
|
||||
result << deviceName;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
|
||||
auto device = _registeredDevices.find(input.getDevice());
|
||||
if (device != _registeredDevices.end()) {
|
||||
return (device->second);
|
||||
} else {
|
||||
return DeviceProxy::Pointer();
|
||||
}
|
||||
}
|
||||
|
||||
QString UserInputMapper::getDeviceName(uint16 deviceID) {
|
||||
if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
|
||||
return _registeredDevices[deviceID]->_name;
|
||||
}
|
||||
return QString("unknown");
|
||||
}
|
||||
|
||||
|
||||
void UserInputMapper::resetAllDeviceBindings() {
|
||||
for (auto device : _registeredDevices) {
|
||||
device.second->resetDeviceBindings();
|
||||
}
|
||||
}
|
||||
|
||||
void UserInputMapper::resetDevice(uint16 deviceID) {
|
||||
auto device = _registeredDevices.find(deviceID);
|
||||
if (device != _registeredDevices.end()) {
|
||||
device->second->resetDeviceBindings();
|
||||
}
|
||||
}
|
||||
|
||||
int UserInputMapper::findDevice(QString name) const {
|
||||
for (auto device : _registeredDevices) {
|
||||
if (device.second->_name.split(" (")[0] == name) {
|
||||
return device.first;
|
||||
} else if (device.second->_baseName == name) {
|
||||
return device.first;
|
||||
}
|
||||
}
|
||||
return Input::INVALID_DEVICE;
|
||||
}
|
||||
|
||||
QVector<QString> UserInputMapper::getDeviceNames() {
|
||||
QVector<QString> result;
|
||||
for (auto device : _registeredDevices) {
|
||||
QString deviceName = device.second->_name.split(" (")[0];
|
||||
result << deviceName;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
|
||||
|
||||
// Split the full input name as such: deviceName.inputName
|
||||
|
@ -134,11 +127,11 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName
|
|||
qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">";
|
||||
|
||||
} else if (deviceName == "Actions") {
|
||||
deviceID = Input::ACTIONS_DEVICE;
|
||||
deviceID = ACTIONS_DEVICE;
|
||||
int actionNum = 0;
|
||||
for (auto action : _actionNames) {
|
||||
if (action == inputName) {
|
||||
return Input(Input::ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
|
||||
return Input(ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
|
||||
}
|
||||
actionNum++;
|
||||
}
|
||||
|
@ -152,296 +145,368 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName
|
|||
qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
|
||||
}
|
||||
|
||||
return Input();
|
||||
return Input::INVALID_INPUT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
|
||||
return addInputChannel(action, input, Input(), scale);
|
||||
}
|
||||
|
||||
bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
|
||||
// Check that the device is registered
|
||||
if (!getDeviceProxy(input)) {
|
||||
qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto inputChannel = InputChannel(input, modifier, action, scale);
|
||||
|
||||
// Insert or replace the input to modifiers
|
||||
if (inputChannel.hasModifier()) {
|
||||
auto& modifiers = _inputToModifiersMap[input.getID()];
|
||||
modifiers.push_back(inputChannel._modifier);
|
||||
std::sort(modifiers.begin(), modifiers.end());
|
||||
}
|
||||
|
||||
// Now update the action To Inputs side of things
|
||||
_actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int UserInputMapper::addInputChannels(const InputChannels& channels) {
|
||||
int nbAdded = 0;
|
||||
for (auto& channel : channels) {
|
||||
nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
|
||||
}
|
||||
return nbAdded;
|
||||
}
|
||||
|
||||
bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
|
||||
// Remove from Input to Modifiers map
|
||||
if (inputChannel.hasModifier()) {
|
||||
_inputToModifiersMap.erase(inputChannel._input.getID());
|
||||
}
|
||||
|
||||
// Remove from Action to Inputs map
|
||||
std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
|
||||
ret = _actionToInputsMap.equal_range(inputChannel._action);
|
||||
for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
|
||||
if (it->second == inputChannel) {
|
||||
_actionToInputsMap.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UserInputMapper::removeAllInputChannels() {
|
||||
_inputToModifiersMap.clear();
|
||||
_actionToInputsMap.clear();
|
||||
}
|
||||
|
||||
void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
|
||||
QVector<InputChannel> channels = getAllInputsForDevice(device);
|
||||
for (auto& channel : channels) {
|
||||
removeInputChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
void UserInputMapper::removeDevice(int device) {
|
||||
removeAllInputChannelsForDevice((uint16) device);
|
||||
_registeredDevices.erase(device);
|
||||
}
|
||||
|
||||
int UserInputMapper::getInputChannels(InputChannels& channels) const {
|
||||
for (auto& channel : _actionToInputsMap) {
|
||||
channels.push_back(channel.second);
|
||||
}
|
||||
|
||||
return _actionToInputsMap.size();
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
|
||||
InputChannels allChannels;
|
||||
getInputChannels(allChannels);
|
||||
|
||||
QVector<InputChannel> channels;
|
||||
for (InputChannel inputChannel : allChannels) {
|
||||
if (inputChannel._input._device == device) {
|
||||
channels.push_back(inputChannel);
|
||||
}
|
||||
}
|
||||
|
||||
return channels;
|
||||
}
|
||||
|
||||
void UserInputMapper::update(float deltaTime) {
|
||||
|
||||
// Reset the axis state for next loop
|
||||
for (auto& channel : _actionStates) {
|
||||
channel = 0.0f;
|
||||
}
|
||||
|
||||
for (auto& channel : _poseStates) {
|
||||
channel = PoseValue();
|
||||
}
|
||||
|
||||
int currentTimestamp = 0;
|
||||
|
||||
for (auto& channelInput : _actionToInputsMap) {
|
||||
auto& inputMapping = channelInput.second;
|
||||
auto& inputID = inputMapping._input;
|
||||
bool enabled = true;
|
||||
|
||||
// Check if this input channel has modifiers and collect the possibilities
|
||||
auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
|
||||
if (modifiersIt != _inputToModifiersMap.end()) {
|
||||
Modifiers validModifiers;
|
||||
bool isActiveModifier = false;
|
||||
for (auto& modifier : modifiersIt->second) {
|
||||
auto deviceProxy = getDeviceProxy(modifier);
|
||||
if (deviceProxy->getButton(modifier, currentTimestamp)) {
|
||||
validModifiers.push_back(modifier);
|
||||
isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
|
||||
}
|
||||
}
|
||||
enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
|
||||
}
|
||||
|
||||
// if enabled: default input or all modifiers on
|
||||
if (enabled) {
|
||||
auto deviceProxy = getDeviceProxy(inputID);
|
||||
switch (inputMapping._input.getType()) {
|
||||
case ChannelType::BUTTON: {
|
||||
_actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
|
||||
break;
|
||||
}
|
||||
case ChannelType::AXIS: {
|
||||
_actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
|
||||
break;
|
||||
}
|
||||
case ChannelType::POSE: {
|
||||
if (!_poseStates[channelInput.first].isValid()) {
|
||||
_poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break; //silence please
|
||||
}
|
||||
}
|
||||
} else{
|
||||
// Channel input not enabled
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Scale all the channel step with the scale
|
||||
static const float EPSILON = 0.01f;
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
if (_externalActionStates[i] != 0) {
|
||||
_actionStates[i] += _externalActionStates[i];
|
||||
_externalActionStates[i] = 0.0f;
|
||||
}
|
||||
_actionStates[i] *= _actionScales[i];
|
||||
|
||||
// Emit only on change, and emit when moving back to 0
|
||||
if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
|
||||
_lastActionStates[i] = _actionStates[i];
|
||||
emit actionEvent(i, _actionStates[i]);
|
||||
}
|
||||
// TODO: emit signal for pose changes
|
||||
}
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
|
||||
QVector<Action> actions;
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
actions.append(Action(i));
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
|
||||
QVector<InputChannel> inputChannels;
|
||||
std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
|
||||
ret = _actionToInputsMap.equal_range(action);
|
||||
for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
|
||||
inputChannels.append(it->second);
|
||||
}
|
||||
return inputChannels;
|
||||
}
|
||||
|
||||
int UserInputMapper::findAction(const QString& actionName) const {
|
||||
auto actions = getAllActions();
|
||||
for (auto action : actions) {
|
||||
if (getActionName(action) == actionName) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
// If the action isn't found, return -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
QVector<QString> UserInputMapper::getActionNames() const {
|
||||
QVector<QString> result;
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
result << _actionNames[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void UserInputMapper::assignDefaulActionScales() {
|
||||
_actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit
|
||||
_actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit
|
||||
_actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit
|
||||
_actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit
|
||||
_actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit
|
||||
_actionScales[VERTICAL_UP] = 1.0f; // 1m per unit
|
||||
_actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit
|
||||
_actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit
|
||||
_actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit
|
||||
_actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
|
||||
_actionScales[BOOM_IN] = 0.5f; // .5m per unit
|
||||
_actionScales[BOOM_OUT] = 0.5f; // .5m per unit
|
||||
_actionScales[LEFT_HAND] = 1.0f; // default
|
||||
_actionScales[RIGHT_HAND] = 1.0f; // default
|
||||
_actionScales[LEFT_HAND_CLICK] = 1.0f; // on
|
||||
_actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
|
||||
_actionScales[SHIFT] = 1.0f; // on
|
||||
_actionScales[ACTION1] = 1.0f; // default
|
||||
_actionScales[ACTION2] = 1.0f; // default
|
||||
_actionScales[TRANSLATE_X] = 1.0f; // default
|
||||
_actionScales[TRANSLATE_Y] = 1.0f; // default
|
||||
_actionScales[TRANSLATE_Z] = 1.0f; // default
|
||||
_actionScales[ROLL] = 1.0f; // default
|
||||
_actionScales[PITCH] = 1.0f; // default
|
||||
_actionScales[YAW] = 1.0f; // default
|
||||
}
|
||||
|
||||
// This is only necessary as long as the actions are hardcoded
|
||||
// Eventually you can just add the string when you add the action
|
||||
void UserInputMapper::createActionNames() {
|
||||
_actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
|
||||
_actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
|
||||
_actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
|
||||
_actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
|
||||
_actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
|
||||
_actionNames[VERTICAL_UP] = "VERTICAL_UP";
|
||||
_actionNames[YAW_LEFT] = "YAW_LEFT";
|
||||
_actionNames[YAW_RIGHT] = "YAW_RIGHT";
|
||||
_actionNames[PITCH_DOWN] = "PITCH_DOWN";
|
||||
_actionNames[PITCH_UP] = "PITCH_UP";
|
||||
_actionNames[BOOM_IN] = "BOOM_IN";
|
||||
_actionNames[BOOM_OUT] = "BOOM_OUT";
|
||||
_actionNames[LEFT_HAND] = "LEFT_HAND";
|
||||
_actionNames[RIGHT_HAND] = "RIGHT_HAND";
|
||||
_actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
|
||||
_actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
|
||||
_actionNames[SHIFT] = "SHIFT";
|
||||
_actionNames[ACTION1] = "ACTION1";
|
||||
_actionNames[ACTION2] = "ACTION2";
|
||||
_actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
|
||||
_actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
|
||||
_actionNames[TRANSLATE_X] = "TranslateX";
|
||||
_actionNames[TRANSLATE_Y] = "TranslateY";
|
||||
_actionNames[TRANSLATE_Z] = "TranslateZ";
|
||||
_actionNames[ROLL] = "Roll";
|
||||
_actionNames[PITCH] = "Pitch";
|
||||
_actionNames[YAW] = "Yaw";
|
||||
}
|
||||
|
||||
void UserInputMapper::registerStandardDevice() {
|
||||
_standardController = std::make_shared<StandardController>();
|
||||
_standardController->registerToUserInputMapper(*this);
|
||||
}
|
||||
|
||||
float UserInputMapper::DeviceProxy::getValue(const Input& input, int timestamp) const {
|
||||
switch (input.getType()) {
|
||||
case UserInputMapper::ChannelType::BUTTON:
|
||||
return getButton(input, timestamp) ? 1.0f : 0.0f;
|
||||
|
||||
case UserInputMapper::ChannelType::AXIS:
|
||||
return getAxis(input, timestamp);
|
||||
|
||||
case UserInputMapper::ChannelType::POSE:
|
||||
return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
|
||||
|
||||
default:
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
|
||||
return addInputChannel(action, input, Input(), scale);
|
||||
}
|
||||
|
||||
bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
|
||||
// Check that the device is registered
|
||||
if (!getDeviceProxy(input)) {
|
||||
qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto inputChannel = InputChannel(input, modifier, action, scale);
|
||||
|
||||
// Insert or replace the input to modifiers
|
||||
if (inputChannel.hasModifier()) {
|
||||
auto& modifiers = _inputToModifiersMap[input.getID()];
|
||||
modifiers.push_back(inputChannel._modifier);
|
||||
std::sort(modifiers.begin(), modifiers.end());
|
||||
}
|
||||
|
||||
// Now update the action To Inputs side of things
|
||||
_actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int UserInputMapper::addInputChannels(const InputChannels& channels) {
|
||||
int nbAdded = 0;
|
||||
for (auto& channel : channels) {
|
||||
nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
|
||||
}
|
||||
return nbAdded;
|
||||
}
|
||||
|
||||
bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
|
||||
// Remove from Input to Modifiers map
|
||||
if (inputChannel.hasModifier()) {
|
||||
_inputToModifiersMap.erase(inputChannel._input.getID());
|
||||
}
|
||||
|
||||
// Remove from Action to Inputs map
|
||||
std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
|
||||
ret = _actionToInputsMap.equal_range(inputChannel._action);
|
||||
for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
|
||||
if (it->second == inputChannel) {
|
||||
_actionToInputsMap.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UserInputMapper::removeAllInputChannels() {
|
||||
_inputToModifiersMap.clear();
|
||||
_actionToInputsMap.clear();
|
||||
}
|
||||
|
||||
void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
|
||||
QVector<InputChannel> channels = getAllInputsForDevice(device);
|
||||
for (auto& channel : channels) {
|
||||
removeInputChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
void UserInputMapper::removeDevice(int device) {
|
||||
removeAllInputChannelsForDevice((uint16) device);
|
||||
_registeredDevices.erase(device);
|
||||
}
|
||||
|
||||
int UserInputMapper::getInputChannels(InputChannels& channels) const {
|
||||
for (auto& channel : _actionToInputsMap) {
|
||||
channels.push_back(channel.second);
|
||||
}
|
||||
|
||||
return _actionToInputsMap.size();
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
|
||||
InputChannels allChannels;
|
||||
getInputChannels(allChannels);
|
||||
|
||||
QVector<InputChannel> channels;
|
||||
for (InputChannel inputChannel : allChannels) {
|
||||
if (inputChannel._input._device == device) {
|
||||
channels.push_back(inputChannel);
|
||||
}
|
||||
}
|
||||
|
||||
return channels;
|
||||
}
|
||||
|
||||
void fixBisectedAxis(float& full, float& negative, float& positive) {
|
||||
full = full + (negative * -1.0f) + positive;
|
||||
negative = full >= 0.0f ? 0.0f : full * -1.0f;
|
||||
positive = full <= 0.0f ? 0.0f : full;
|
||||
}
|
||||
|
||||
void UserInputMapper::update(float deltaTime) {
|
||||
|
||||
// Reset the axis state for next loop
|
||||
for (auto& channel : _actionStates) {
|
||||
channel = 0.0f;
|
||||
}
|
||||
|
||||
for (auto& channel : _poseStates) {
|
||||
channel = PoseValue();
|
||||
}
|
||||
|
||||
int currentTimestamp = 0;
|
||||
for (auto& channelInput : _actionToInputsMap) {
|
||||
auto& inputMapping = channelInput.second;
|
||||
auto& inputID = inputMapping._input;
|
||||
bool enabled = true;
|
||||
|
||||
// Check if this input channel has modifiers and collect the possibilities
|
||||
auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
|
||||
if (modifiersIt != _inputToModifiersMap.end()) {
|
||||
Modifiers validModifiers;
|
||||
bool isActiveModifier = false;
|
||||
for (auto& modifier : modifiersIt->second) {
|
||||
auto deviceProxy = getDeviceProxy(modifier);
|
||||
if (deviceProxy->getButton(modifier, currentTimestamp)) {
|
||||
validModifiers.push_back(modifier);
|
||||
isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
|
||||
}
|
||||
}
|
||||
enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
|
||||
}
|
||||
|
||||
// if enabled: default input or all modifiers on
|
||||
if (enabled) {
|
||||
auto deviceProxy = getDeviceProxy(inputID);
|
||||
switch (inputMapping._input.getType()) {
|
||||
case ChannelType::BUTTON: {
|
||||
_actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
|
||||
break;
|
||||
}
|
||||
case ChannelType::AXIS: {
|
||||
_actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
|
||||
break;
|
||||
}
|
||||
case ChannelType::POSE: {
|
||||
if (!_poseStates[channelInput.first].isValid()) {
|
||||
_poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break; //silence please
|
||||
}
|
||||
}
|
||||
} else{
|
||||
// Channel input not enabled
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Scale all the channel step with the scale
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
if (_externalActionStates[i] != 0) {
|
||||
_actionStates[i] += _externalActionStates[i];
|
||||
_externalActionStates[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// merge the bisected and non-bisected axes for now
|
||||
fixBisectedAxis(_actionStates[TRANSLATE_X], _actionStates[LATERAL_LEFT], _actionStates[LATERAL_RIGHT]);
|
||||
fixBisectedAxis(_actionStates[TRANSLATE_Y], _actionStates[VERTICAL_DOWN], _actionStates[VERTICAL_UP]);
|
||||
fixBisectedAxis(_actionStates[TRANSLATE_Z], _actionStates[LONGITUDINAL_FORWARD], _actionStates[LONGITUDINAL_BACKWARD]);
|
||||
fixBisectedAxis(_actionStates[TRANSLATE_CAMERA_Z], _actionStates[BOOM_IN], _actionStates[BOOM_OUT]);
|
||||
fixBisectedAxis(_actionStates[ROTATE_Y], _actionStates[YAW_LEFT], _actionStates[YAW_RIGHT]);
|
||||
fixBisectedAxis(_actionStates[ROTATE_X], _actionStates[PITCH_UP], _actionStates[PITCH_DOWN]);
|
||||
|
||||
|
||||
static const float EPSILON = 0.01f;
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
_actionStates[i] *= _actionScales[i];
|
||||
// Emit only on change, and emit when moving back to 0
|
||||
if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
|
||||
_lastActionStates[i] = _actionStates[i];
|
||||
emit actionEvent(i, _actionStates[i]);
|
||||
}
|
||||
// TODO: emit signal for pose changes
|
||||
}
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
|
||||
QVector<Action> actions;
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
actions.append(Action(i));
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
|
||||
QVector<InputChannel> inputChannels;
|
||||
std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
|
||||
ret = _actionToInputsMap.equal_range(action);
|
||||
for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
|
||||
inputChannels.append(it->second);
|
||||
}
|
||||
return inputChannels;
|
||||
}
|
||||
|
||||
int UserInputMapper::findAction(const QString& actionName) const {
|
||||
auto actions = getAllActions();
|
||||
for (auto action : actions) {
|
||||
if (getActionName(action) == actionName) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
// If the action isn't found, return -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
QVector<QString> UserInputMapper::getActionNames() const {
|
||||
QVector<QString> result;
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
result << _actionNames[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void UserInputMapper::assignDefaulActionScales() {
|
||||
_actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit
|
||||
_actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit
|
||||
_actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit
|
||||
_actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit
|
||||
_actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit
|
||||
_actionScales[VERTICAL_UP] = 1.0f; // 1m per unit
|
||||
_actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit
|
||||
_actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit
|
||||
_actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit
|
||||
_actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
|
||||
_actionScales[BOOM_IN] = 0.5f; // .5m per unit
|
||||
_actionScales[BOOM_OUT] = 0.5f; // .5m per unit
|
||||
_actionScales[LEFT_HAND] = 1.0f; // default
|
||||
_actionScales[RIGHT_HAND] = 1.0f; // default
|
||||
_actionScales[LEFT_HAND_CLICK] = 1.0f; // on
|
||||
_actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
|
||||
_actionScales[SHIFT] = 1.0f; // on
|
||||
_actionScales[ACTION1] = 1.0f; // default
|
||||
_actionScales[ACTION2] = 1.0f; // default
|
||||
_actionScales[TRANSLATE_X] = 1.0f; // default
|
||||
_actionScales[TRANSLATE_Y] = 1.0f; // default
|
||||
_actionScales[TRANSLATE_Z] = 1.0f; // default
|
||||
_actionScales[ROLL] = 1.0f; // default
|
||||
_actionScales[PITCH] = 1.0f; // default
|
||||
_actionScales[YAW] = 1.0f; // default
|
||||
}
|
||||
|
||||
// This is only necessary as long as the actions are hardcoded
|
||||
// Eventually you can just add the string when you add the action
|
||||
void UserInputMapper::createActionNames() {
|
||||
_actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
|
||||
_actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
|
||||
_actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
|
||||
_actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
|
||||
_actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
|
||||
_actionNames[VERTICAL_UP] = "VERTICAL_UP";
|
||||
_actionNames[YAW_LEFT] = "YAW_LEFT";
|
||||
_actionNames[YAW_RIGHT] = "YAW_RIGHT";
|
||||
_actionNames[PITCH_DOWN] = "PITCH_DOWN";
|
||||
_actionNames[PITCH_UP] = "PITCH_UP";
|
||||
_actionNames[BOOM_IN] = "BOOM_IN";
|
||||
_actionNames[BOOM_OUT] = "BOOM_OUT";
|
||||
_actionNames[LEFT_HAND] = "LEFT_HAND";
|
||||
_actionNames[RIGHT_HAND] = "RIGHT_HAND";
|
||||
_actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
|
||||
_actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
|
||||
_actionNames[SHIFT] = "SHIFT";
|
||||
_actionNames[ACTION1] = "ACTION1";
|
||||
_actionNames[ACTION2] = "ACTION2";
|
||||
_actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
|
||||
_actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
|
||||
_actionNames[TRANSLATE_X] = "TranslateX";
|
||||
_actionNames[TRANSLATE_Y] = "TranslateY";
|
||||
_actionNames[TRANSLATE_Z] = "TranslateZ";
|
||||
_actionNames[ROLL] = "Roll";
|
||||
_actionNames[PITCH] = "Pitch";
|
||||
_actionNames[YAW] = "Yaw";
|
||||
}
|
||||
|
||||
void UserInputMapper::registerStandardDevice() {
|
||||
_standardController = std::make_shared<StandardController>();
|
||||
_standardController->registerToUserInputMapper(*this);
|
||||
_standardController->assignDefaultInputMapping(*this);
|
||||
}
|
||||
|
||||
static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
|
||||
static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
|
||||
static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
|
||||
|
||||
QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input);
|
||||
void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input);
|
||||
QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action);
|
||||
void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action);
|
||||
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair);
|
||||
void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair);
|
||||
|
||||
QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("device", input.getDevice());
|
||||
obj.setProperty("channel", input.getChannel());
|
||||
obj.setProperty("type", (unsigned short)input.getType());
|
||||
obj.setProperty("id", input.getID());
|
||||
return obj;
|
||||
}
|
||||
|
||||
void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) {
|
||||
input.setDevice(object.property("device").toUInt16());
|
||||
input.setChannel(object.property("channel").toUInt16());
|
||||
input.setType(object.property("type").toUInt16());
|
||||
input.setID(object.property("id").toInt32());
|
||||
}
|
||||
|
||||
QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
obj.setProperty("action", (int)action);
|
||||
obj.setProperty("actionName", userInputMapper->getActionName(action));
|
||||
return obj;
|
||||
}
|
||||
|
||||
void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) {
|
||||
action = UserInputMapper::Action(object.property("action").toVariant().toInt());
|
||||
}
|
||||
|
||||
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("input", inputToScriptValue(engine, inputPair.first));
|
||||
obj.setProperty("inputName", inputPair.second);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) {
|
||||
inputFromScriptValue(object.property("input"), inputPair.first);
|
||||
inputPair.second = QString(object.property("inputName").toVariant().toString());
|
||||
}
|
||||
|
||||
void UserInputMapper::registerControllerTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
|
||||
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
|
||||
qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
|
||||
}
|
||||
|
||||
UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) {
|
||||
return Input(STANDARD_DEVICE, button, ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) {
|
||||
return Input(STANDARD_DEVICE, axis, ChannelType::AXIS);
|
||||
}
|
||||
|
||||
UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
|
||||
return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
//
|
||||
// UserInputMapper.h
|
||||
// input-plugins/src/input-plugins
|
||||
//
|
||||
// Created by Sam Gateau on 4/27/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
|
@ -9,6 +6,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_UserInputMapper_h
|
||||
#define hifi_UserInputMapper_h
|
||||
|
||||
|
@ -20,6 +18,11 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#include "Pose.h"
|
||||
#include "Input.h"
|
||||
#include "DeviceProxy.h"
|
||||
#include "StandardControls.h"
|
||||
|
||||
class StandardController;
|
||||
typedef std::shared_ptr<StandardController> StandardControllerPointer;
|
||||
|
||||
|
@ -30,86 +33,22 @@ class UserInputMapper : public QObject, public Dependency {
|
|||
public:
|
||||
~UserInputMapper();
|
||||
|
||||
using DeviceProxy = controller::DeviceProxy;
|
||||
using PoseValue = controller::Pose;
|
||||
using Input = controller::Input;
|
||||
using ChannelType = controller::ChannelType;
|
||||
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
enum class ChannelType {
|
||||
UNKNOWN = 0,
|
||||
BUTTON = 1,
|
||||
AXIS,
|
||||
POSE,
|
||||
};
|
||||
static void registerControllerTypes(QScriptEngine* engine);
|
||||
|
||||
// Input is the unique identifier to find a n input channel of a particular device
|
||||
// Devices are responsible for registering to the UseInputMapper so their input channels can be sued and mapped
|
||||
// to the Action channels
|
||||
class Input {
|
||||
public:
|
||||
union {
|
||||
struct {
|
||||
uint16 _device; // Up to 64K possible devices
|
||||
uint16 _channel : 13; // 2^13 possible channel per Device
|
||||
uint16 _type : 2; // 2 bits to store the Type directly in the ID
|
||||
uint16 _padding : 1; // 2 bits to store the Type directly in the ID
|
||||
};
|
||||
uint32 _id = 0; // by default Input is 0 meaning invalid
|
||||
};
|
||||
|
||||
bool isValid() const { return (_id != 0); }
|
||||
|
||||
uint16 getDevice() const { return _device; }
|
||||
uint16 getChannel() const { return _channel; }
|
||||
uint32 getID() const { return _id; }
|
||||
ChannelType getType() const { return (ChannelType) _type; }
|
||||
|
||||
void setDevice(uint16 device) { _device = device; }
|
||||
void setChannel(uint16 channel) { _channel = channel; }
|
||||
void setType(uint16 type) { _type = type; }
|
||||
void setID(uint32 ID) { _id = ID; }
|
||||
|
||||
bool isButton() const { return getType() == ChannelType::BUTTON; }
|
||||
bool isAxis() const { return getType() == ChannelType::AXIS; }
|
||||
bool isPose() const { return getType() == ChannelType::POSE; }
|
||||
|
||||
// WORKAROUND: the explicit initializer here avoids a bug in GCC-4.8.2 (but not found in 4.9.2)
|
||||
// where the default initializer (a C++-11ism) for the union data above is not applied.
|
||||
explicit Input() : _id(0) {}
|
||||
explicit Input(uint32 id) : _id(id) {}
|
||||
explicit Input(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)), _padding(0) {}
|
||||
Input(const Input& src) : _id(src._id) {}
|
||||
Input& operator = (const Input& src) { _id = src._id; return (*this); }
|
||||
bool operator ==(const Input& right) const { return _id == right._id; }
|
||||
bool operator < (const Input& src) const { return _id < src._id; }
|
||||
|
||||
static const Input INVALID_INPUT;
|
||||
static const uint16 INVALID_DEVICE;
|
||||
static const uint16 INVALID_CHANNEL;
|
||||
static const uint16 INVALID_TYPE;
|
||||
static const uint16 ACTIONS_DEVICE;
|
||||
static const uint16 STANDARD_DEVICE;
|
||||
};
|
||||
static const uint16 ACTIONS_DEVICE;
|
||||
static const uint16 STANDARD_DEVICE;
|
||||
|
||||
|
||||
// Modifiers are just button inputID
|
||||
typedef std::vector< Input > Modifiers;
|
||||
|
||||
class PoseValue {
|
||||
public:
|
||||
glm::vec3 _translation{ 0.0f };
|
||||
glm::quat _rotation;
|
||||
bool _valid;
|
||||
|
||||
PoseValue() : _valid(false) {};
|
||||
PoseValue(glm::vec3 translation, glm::quat rotation) : _translation(translation), _rotation(rotation), _valid(true) {}
|
||||
PoseValue(const PoseValue&) = default;
|
||||
PoseValue& operator = (const PoseValue&) = default;
|
||||
bool operator ==(const PoseValue& right) const { return _translation == right.getTranslation() && _rotation == right.getRotation() && _valid == right.isValid(); }
|
||||
|
||||
bool isValid() const { return _valid; }
|
||||
glm::vec3 getTranslation() const { return _translation; }
|
||||
glm::quat getRotation() const { return _rotation; }
|
||||
};
|
||||
|
||||
typedef std::function<bool (const Input& input, int timestamp)> ButtonGetter;
|
||||
typedef std::function<float (const Input& input, int timestamp)> AxisGetter;
|
||||
typedef std::function<PoseValue (const Input& input, int timestamp)> PoseGetter;
|
||||
|
@ -119,22 +58,6 @@ public:
|
|||
|
||||
typedef QVector<InputPair> AvailableInput;
|
||||
|
||||
class DeviceProxy {
|
||||
public:
|
||||
DeviceProxy(QString name) : _baseName(name), _name(name) {}
|
||||
const QString& getBaseName() const { return _baseName; }
|
||||
const QString& getName() const { return _name; }
|
||||
|
||||
QString _baseName;
|
||||
QString _name;
|
||||
ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
|
||||
AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; };
|
||||
PoseGetter getPose = [] (const Input& input, int timestamp) -> PoseValue { return PoseValue(); };
|
||||
AvailableInputGetter getAvailabeInputs = [] () -> AvailableInput { return QVector<InputPair>(); };
|
||||
ResetBindings resetDeviceBindings = [] () -> bool { return true; };
|
||||
float getValue(const Input& input, int timestamp = 0) const;
|
||||
typedef std::shared_ptr<DeviceProxy> Pointer;
|
||||
};
|
||||
// GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
|
||||
uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
|
||||
|
||||
|
@ -162,8 +85,9 @@ public:
|
|||
ROTATE_Z, ROLL = ROTATE_Z,
|
||||
|
||||
TRANSLATE_CAMERA_Z,
|
||||
NUM_COMBINED_AXES,
|
||||
|
||||
LEFT_HAND,
|
||||
LEFT_HAND = NUM_COMBINED_AXES,
|
||||
RIGHT_HAND,
|
||||
|
||||
LEFT_HAND_CLICK,
|
||||
|
@ -222,7 +146,11 @@ public:
|
|||
// Return true if theinput channel is created correctly, false either
|
||||
bool addInputChannel(Action action, const Input& input, float scale = 1.0f);
|
||||
bool addInputChannel(Action action, const Input& input, const Input& modifer, float scale = 1.0f);
|
||||
|
||||
|
||||
UserInputMapper::Input makeStandardInput(controller::StandardButtonChannel button);
|
||||
UserInputMapper::Input makeStandardInput(controller::StandardAxisChannel axis);
|
||||
UserInputMapper::Input makeStandardInput(controller::StandardPoseChannel pose);
|
||||
|
||||
// Under the hood, the input channels are organized in map sorted on the _output
|
||||
// The InputChannel class is just the full values describing the input channel in one object
|
||||
class InputChannel {
|
||||
|
@ -276,7 +204,7 @@ public:
|
|||
typedef std::map<int, DeviceProxy::Pointer> DevicesMap;
|
||||
DevicesMap getDevices() { return _registeredDevices; }
|
||||
|
||||
uint16 getStandardDeviceID() const { return Input::STANDARD_DEVICE; }
|
||||
uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
|
||||
DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
|
||||
|
||||
signals:
|
||||
|
@ -288,7 +216,7 @@ protected:
|
|||
StandardControllerPointer _standardController;
|
||||
|
||||
DevicesMap _registeredDevices;
|
||||
uint16 _nextFreeDeviceID = Input::STANDARD_DEVICE + 1;
|
||||
uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
|
||||
|
||||
typedef std::map<int, Modifiers> InputToMoModifiersMap;
|
||||
InputToMoModifiersMap _inputToModifiersMap;
|
||||
|
@ -309,6 +237,7 @@ protected:
|
|||
};
|
||||
|
||||
Q_DECLARE_METATYPE(UserInputMapper::InputPair)
|
||||
Q_DECLARE_METATYPE(UserInputMapper::PoseValue)
|
||||
Q_DECLARE_METATYPE(QVector<UserInputMapper::InputPair>)
|
||||
Q_DECLARE_METATYPE(UserInputMapper::Input)
|
||||
Q_DECLARE_METATYPE(UserInputMapper::InputChannel)
|
||||
|
|
|
@ -1,145 +1,207 @@
|
|||
//
|
||||
// Joystick.cpp
|
||||
// input-plugins/src/input-plugins
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-09-23.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Joystick.h"
|
||||
|
||||
#include <limits>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
const float CONTROLLER_THRESHOLD = 0.3f;
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
const float MAX_AXIS = 32768.0f;
|
||||
|
||||
Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
|
||||
InputDevice(name),
|
||||
_sdlGameController(sdlGameController),
|
||||
_sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
|
||||
_instanceId(instanceId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Joystick::~Joystick() {
|
||||
closeJoystick();
|
||||
}
|
||||
|
||||
void Joystick::closeJoystick() {
|
||||
#ifdef HAVE_SDL2
|
||||
SDL_GameControllerClose(_sdlGameController);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Joystick::update(float deltaTime, bool jointsCaptured) {
|
||||
for (auto axisState : _axisStateMap) {
|
||||
if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
|
||||
_axisStateMap[axisState.first] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Joystick::focusOutEvent() {
|
||||
_axisStateMap.clear();
|
||||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
|
||||
void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
|
||||
SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
|
||||
_axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
|
||||
}
|
||||
|
||||
void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
|
||||
auto input = makeInput((controller::StandardButtonChannel)event.button);
|
||||
bool newValue = event.state == SDL_PRESSED;
|
||||
if (newValue) {
|
||||
_buttonPressedMap.insert(input.getChannel());
|
||||
} else {
|
||||
_buttonPressedMap.erase(input.getChannel());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||
// Grab the current free device ID
|
||||
_deviceID = mapper.getFreeDeviceID();
|
||||
|
||||
auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
|
||||
proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
|
||||
QVector<UserInputMapper::InputPair> availableInputs;
|
||||
// Buttons
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
|
||||
|
||||
// DPad
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
|
||||
|
||||
// Bumpers
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
|
||||
|
||||
// Stick press
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
|
||||
|
||||
// Center buttons
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
|
||||
|
||||
// Analog sticks
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
|
||||
|
||||
// Triggers
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
|
||||
|
||||
// Aliases, PlayStation style names
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
|
||||
|
||||
return availableInputs;
|
||||
};
|
||||
proxy->resetDeviceBindings = [this, &mapper] () -> bool {
|
||||
mapper.removeAllInputChannelsForDevice(_deviceID);
|
||||
this->assignDefaultInputMapping(mapper);
|
||||
return true;
|
||||
};
|
||||
mapper.registerDevice(_deviceID, proxy);
|
||||
}
|
||||
|
||||
//
|
||||
// Joystick.cpp
|
||||
// input-plugins/src/input-plugins
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-09-23.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Joystick.h"
|
||||
|
||||
#include <limits>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
const float CONTROLLER_THRESHOLD = 0.3f;
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
const float MAX_AXIS = 32768.0f;
|
||||
|
||||
Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
|
||||
InputDevice(name),
|
||||
_sdlGameController(sdlGameController),
|
||||
_sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
|
||||
_instanceId(instanceId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Joystick::~Joystick() {
|
||||
closeJoystick();
|
||||
}
|
||||
|
||||
void Joystick::closeJoystick() {
|
||||
#ifdef HAVE_SDL2
|
||||
SDL_GameControllerClose(_sdlGameController);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Joystick::update(float deltaTime, bool jointsCaptured) {
|
||||
for (auto axisState : _axisStateMap) {
|
||||
if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
|
||||
_axisStateMap[axisState.first] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Joystick::focusOutEvent() {
|
||||
_axisStateMap.clear();
|
||||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
|
||||
void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
|
||||
SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
|
||||
_axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
|
||||
}
|
||||
|
||||
void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
|
||||
auto input = makeInput((controller::StandardButtonChannel)event.button);
|
||||
bool newValue = event.state == SDL_PRESSED;
|
||||
if (newValue) {
|
||||
_buttonPressedMap.insert(input.getChannel());
|
||||
} else {
|
||||
_buttonPressedMap.erase(input.getChannel());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||
// Grab the current free device ID
|
||||
_deviceID = mapper.getFreeDeviceID();
|
||||
|
||||
auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
|
||||
proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
|
||||
QVector<UserInputMapper::InputPair> availableInputs;
|
||||
// Buttons
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
|
||||
|
||||
// DPad
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
|
||||
|
||||
// Bumpers
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
|
||||
|
||||
// Stick press
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
|
||||
|
||||
// Center buttons
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
|
||||
|
||||
// Analog sticks
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
|
||||
|
||||
// Triggers
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
|
||||
|
||||
// Aliases, PlayStation style names
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
|
||||
|
||||
return availableInputs;
|
||||
};
|
||||
proxy->resetDeviceBindings = [this, &mapper] () -> bool {
|
||||
mapper.removeAllInputChannelsForDevice(_deviceID);
|
||||
this->assignDefaultInputMapping(mapper);
|
||||
return true;
|
||||
};
|
||||
mapper.registerDevice(_deviceID, proxy);
|
||||
}
|
||||
|
||||
|
||||
void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
#if 0
|
||||
#ifdef HAVE_SDL2
|
||||
const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
const float DPAD_MOVE_SPEED = 0.5f;
|
||||
const float JOYSTICK_YAW_SPEED = 0.5f;
|
||||
const float JOYSTICK_PITCH_SPEED = 0.25f;
|
||||
const float BOOM_SPEED = 0.1f;
|
||||
|
||||
// Y axes are flipped (up is negative)
|
||||
// Left Joystick: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED);
|
||||
// Right Joystick: Camera orientation
|
||||
mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED);
|
||||
|
||||
// Dpad movement
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED);
|
||||
|
||||
// Button controls
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED);
|
||||
|
||||
// Zoom
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), BOOM_SPEED);
|
||||
|
||||
// Hold front right shoulder button for precision controls
|
||||
// Left Joystick: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
|
||||
|
||||
// Right Joystick: Camera orientation
|
||||
mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
|
||||
|
||||
// Dpad movement
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
|
||||
// Button controls
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
|
||||
|
||||
// Zoom
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
|
||||
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A));
|
||||
#endif
|
||||
#endif
|
||||
}
|
|
@ -1,69 +1,70 @@
|
|||
//
|
||||
// Joystick.h
|
||||
// input-plugins/src/input-plugins
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-09-23.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Joystick_h
|
||||
#define hifi_Joystick_h
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qvector.h>
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
#include <SDL.h>
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
#include <controllers/InputDevice.h>
|
||||
#include <controllers/StandardControls.h>
|
||||
|
||||
class Joystick : public QObject, public InputDevice {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ getName)
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
Q_PROPERTY(int instanceId READ getInstanceId)
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
const QString& getName() const { return _name; }
|
||||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
Joystick() : InputDevice("Joystick") {}
|
||||
~Joystick();
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
|
||||
#endif
|
||||
|
||||
void closeJoystick();
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
void handleAxisEvent(const SDL_ControllerAxisEvent& event);
|
||||
void handleButtonEvent(const SDL_ControllerButtonEvent& event);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
int getInstanceId() const { return _instanceId; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef HAVE_SDL2
|
||||
SDL_GameController* _sdlGameController;
|
||||
SDL_Joystick* _sdlJoystick;
|
||||
SDL_JoystickID _instanceId;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // hifi_Joystick_h
|
||||
//
|
||||
// Joystick.h
|
||||
// input-plugins/src/input-plugins
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-09-23.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Joystick_h
|
||||
#define hifi_Joystick_h
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qvector.h>
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
#include <SDL.h>
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
#include <controllers/InputDevice.h>
|
||||
#include <controllers/StandardControls.h>
|
||||
|
||||
class Joystick : public QObject, public InputDevice {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ getName)
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
Q_PROPERTY(int instanceId READ getInstanceId)
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
const QString& getName() const { return _name; }
|
||||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
Joystick() : InputDevice("Joystick") {}
|
||||
~Joystick();
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
|
||||
#endif
|
||||
|
||||
void closeJoystick();
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
void handleAxisEvent(const SDL_ControllerAxisEvent& event);
|
||||
void handleButtonEvent(const SDL_ControllerButtonEvent& event);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
int getInstanceId() const { return _instanceId; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef HAVE_SDL2
|
||||
SDL_GameController* _sdlGameController;
|
||||
SDL_Joystick* _sdlJoystick;
|
||||
SDL_JoystickID _instanceId;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // hifi_Joystick_h
|
||||
|
|
|
@ -449,6 +449,17 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, boo
|
|||
#endif // HAVE_SIXENSE
|
||||
}
|
||||
|
||||
static const auto L0 = controller::BACK;
|
||||
static const auto L1 = controller::DL;
|
||||
static const auto L2 = controller::DD;
|
||||
static const auto L3 = controller::DR;
|
||||
static const auto L4 = controller::DU;
|
||||
static const auto R0 = controller::START;
|
||||
static const auto R1 = controller::X;
|
||||
static const auto R2 = controller::A;
|
||||
static const auto R3 = controller::B;
|
||||
static const auto R4 = controller::Y;
|
||||
|
||||
void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||
// Grab the current free device ID
|
||||
_deviceID = mapper.getFreeDeviceID();
|
||||
|
@ -459,31 +470,75 @@ void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) {
|
|||
using namespace controller;
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<UserInputMapper::InputPair> {
|
||||
QVector<UserInputMapper::InputPair> availableInputs;
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BACK), "L0"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(DL), "L1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(DD), "L2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(DR), "L3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(DU), "L4"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(L0), "L0"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(L1), "L1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(L2), "L2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(L3), "L3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(L4), "L4"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LB), "LB"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LS), "LS"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LX), "LX"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LY), "LY"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LT), "LT"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(START), "R0"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(X), "R1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(A), "R2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(B), "R3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Y), "R4"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(R0), "R0"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(R1), "R1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(R2), "R2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(R3), "R3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(R4), "R4"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RB), "RB"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RS), "RS"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RX), "RX"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RY), "RY"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RT), "RT"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT), "LeftPose"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT), "RightPose"));
|
||||
return availableInputs;
|
||||
};
|
||||
mapper.registerDevice(_deviceID, proxy);
|
||||
}
|
||||
|
||||
void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
const float JOYSTICK_YAW_SPEED = 0.5f;
|
||||
const float JOYSTICK_PITCH_SPEED = 0.25f;
|
||||
const float BUTTON_MOVE_SPEED = 1.0f;
|
||||
const float BOOM_SPEED = 0.1f;
|
||||
using namespace controller;
|
||||
|
||||
// Left Joystick: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(LY), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(LX), JOYSTICK_MOVE_SPEED);
|
||||
|
||||
// Right Joystick: Camera orientation
|
||||
mapper.addInputChannel(UserInputMapper::YAW, makeInput(RX), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH, makeInput(RY), JOYSTICK_PITCH_SPEED);
|
||||
|
||||
// Buttons
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(L3), BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(L1), BOOM_SPEED);
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(R3), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(R1), BUTTON_MOVE_SPEED);
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(L2));
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(R2));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(L4));
|
||||
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(R4));
|
||||
|
||||
// FIXME
|
||||
// mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
|
||||
// mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(LT));
|
||||
mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(RT));
|
||||
|
||||
// TODO find a mechanism to allow users to navigate the context menu via
|
||||
mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(L0));
|
||||
mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(R0));
|
||||
|
||||
}
|
||||
|
||||
// virtual
|
||||
void SixenseManager::saveSettings() const {
|
||||
Settings settings;
|
||||
|
|
|
@ -61,6 +61,8 @@ public:
|
|||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
|
|
|
@ -308,8 +308,6 @@ void ScriptEngine::init() {
|
|||
|
||||
registerGlobalObject("Script", this);
|
||||
registerGlobalObject("Audio", &AudioScriptingInterface::getInstance());
|
||||
auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
|
||||
registerGlobalObject("Controller", scriptingInterface.data());
|
||||
registerGlobalObject("Entities", entityScriptingInterface.data());
|
||||
registerGlobalObject("Quat", &_quatLibrary);
|
||||
registerGlobalObject("Vec3", &_vec3Library);
|
||||
|
@ -319,11 +317,9 @@ void ScriptEngine::init() {
|
|||
// constants
|
||||
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
|
||||
|
||||
if (scriptingInterface) {
|
||||
scriptingInterface->registerControllerTypes(this);
|
||||
}
|
||||
|
||||
|
||||
auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
|
||||
registerGlobalObject("Controller", scriptingInterface.data());
|
||||
UserInputMapper::registerControllerTypes(this);
|
||||
}
|
||||
|
||||
void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
|
||||
|
|
Loading…
Reference in a new issue