Breaking up UserInputMapper, restoring some mappings

This commit is contained in:
Brad Davis 2015-10-18 18:58:03 -07:00
parent a75316f27b
commit 734a39f962
21 changed files with 670 additions and 630 deletions

View file

@ -87,7 +87,7 @@ HifiControls.VrDialog {
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);
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

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));
}
@ -448,62 +189,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,7 +1,4 @@
//
// UserInputMapper.cpp
// input-plugins/src/input-plugins
//
// Created by Sam Gateau on 4/27/15.
// Copyright 2015 High Fidelity, Inc.
//
@ -12,14 +9,10 @@
#include "UserInputMapper.h"
#include "StandardController.h"
#include "Logging.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;
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() {
@ -46,18 +39,18 @@ bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer
proxy->_name += QString::number(numberOfType);
}
qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
_registeredDevices[deviceID] = proxy;
return true;
}
bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) {
device->_name = "Standard"; // Just to make sure
_registeredDevices[getStandardDeviceID()] = device;
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) {
@ -110,51 +103,51 @@ QVector<QString> UserInputMapper::getDeviceNames() {
return result;
}
UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
// Split the full input name as such: deviceName.inputName
auto names = inputName.split('.');
if (names.size() >= 2) {
// Get the device name:
auto deviceName = names[0];
auto inputName = names[1];
int deviceID = findDevice(deviceName);
if (deviceID != Input::INVALID_DEVICE) {
const auto& deviceProxy = _registeredDevices.at(deviceID);
auto deviceInputs = deviceProxy->getAvailabeInputs();
for (auto input : deviceInputs) {
if (input.second == inputName) {
return input.first;
}
}
qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">";
} else if (deviceName == "Actions") {
deviceID = Input::ACTIONS_DEVICE;
int actionNum = 0;
for (auto action : _actionNames) {
if (action == inputName) {
return Input(Input::ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
}
actionNum++;
}
qCDebug(controllers) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions";
} else {
qCDebug(controllers) << "Couldn\'t find InputDevice named <" << deviceName << ">";
}
} else {
qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
}
return Input();
}
UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
// Split the full input name as such: deviceName.inputName
auto names = inputName.split('.');
if (names.size() >= 2) {
// Get the device name:
auto deviceName = names[0];
auto inputName = names[1];
int deviceID = findDevice(deviceName);
if (deviceID != Input::INVALID_DEVICE) {
const auto& deviceProxy = _registeredDevices.at(deviceID);
auto deviceInputs = deviceProxy->getAvailabeInputs();
for (auto input : deviceInputs) {
if (input.second == inputName) {
return input.first;
}
}
qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">";
} else if (deviceName == "Actions") {
deviceID = ACTIONS_DEVICE;
int actionNum = 0;
for (auto action : _actionNames) {
if (action == inputName) {
return Input(ACTIONS_DEVICE, actionNum, ChannelType::AXIS);
}
actionNum++;
}
qCDebug(controllers) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions";
} else {
qCDebug(controllers) << "Couldn\'t find InputDevice named <" << deviceName << ">";
}
} else {
qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
}
return Input::INVALID_INPUT;
}
bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
@ -261,7 +254,6 @@ void UserInputMapper::update(float deltaTime) {
}
int currentTimestamp = 0;
for (auto& channelInput : _actionToInputsMap) {
auto& inputMapping = channelInput.second;
auto& inputID = inputMapping._input;
@ -430,18 +422,62 @@ void UserInputMapper::registerStandardDevice() {
_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);
static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
case UserInputMapper::ChannelType::POSE:
return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
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);
default:
return 0.0f;
}
}
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);
}

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,10 @@
#include <DependencyManager.h>
#include <RegisteredMetaTypes.h>
#include "Pose.h"
#include "Input.h"
#include "DeviceProxy.h"
class StandardController;
typedef std::shared_ptr<StandardController> StandardControllerPointer;
@ -30,86 +32,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 +57,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++; }
@ -222,7 +144,7 @@ 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);
// 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 +198,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 +210,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 +231,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

@ -143,3 +143,63 @@ void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
mapper.registerDevice(_deviceID, proxy);
}
void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
#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
}

View file

@ -37,6 +37,7 @@ 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

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