Merge pull request #6108 from jherico/controllers

Controllers Branch - Breaking up UserInputMapper, restoring some mappings
This commit is contained in:
samcake 2015-10-19 11:16:13 -07:00
commit 9ae1da371e
22 changed files with 1471 additions and 1360 deletions

View file

@ -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

View file

@ -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();

View file

@ -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),

View file

@ -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;

View 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;
}
}
}

View 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

View 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();
}

View 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

View file

@ -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 {

View file

@ -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;
};

View 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();
}
}

View 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

View file

@ -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

View file

@ -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 {

View file

@ -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) {

View file

@ -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);
}

View file

@ -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)

View file

@ -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
}

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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) {