mirror of
https://github.com/overte-org/overte.git
synced 2025-04-16 16:26:17 +02:00
Working on JSON parsing and cleanup
Conflicts: libraries/controllers/src/controllers/Route.cpp libraries/controllers/src/controllers/ScriptingInterface.cpp libraries/controllers/src/controllers/StandardController.cpp libraries/controllers/src/controllers/impl/RouteBuilderProxy.h
This commit is contained in:
parent
ef6c4f6f66
commit
bea6fdd890
49 changed files with 1925 additions and 2116 deletions
25
interface/resources/controllers/keyboardMouse.json
Normal file
25
interface/resources/controllers/keyboardMouse.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "Keyboard/Mouse to Actions",
|
||||
"channels": [
|
||||
{ "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
|
||||
{ "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
|
||||
{ "from": "Keyboard.A", "to": "Actions.YAW_LEFT" },
|
||||
{ "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" },
|
||||
{ "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
|
||||
{ "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
|
||||
{ "from": "Keyboard.Up", "to": "Actions.LONGITUDINAL_FORWARD" },
|
||||
{ "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" },
|
||||
{ "from": "Keyboard.Left", "to": "Actions.YAW_LEFT" },
|
||||
{ "from": "Keyboard.Right", "to": "Actions.YAW_RIGHT" },
|
||||
{ "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
|
||||
{ "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },
|
||||
{ "from": "Keyboard.MouseMoveLeft", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_LEFT" },
|
||||
{ "from": "Keyboard.MouseMoveRight", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_RIGHT" },
|
||||
{ "from": "Keyboard.MouseMoveUp", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_UP" },
|
||||
{ "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_DOWN" }
|
||||
]
|
||||
}
|
41
interface/resources/controllers/standard.json
Normal file
41
interface/resources/controllers/standard.json
Normal file
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "Standard to Action",
|
||||
"channels": [
|
||||
{ "from": "Standard.LY", "to": "Actions.TranslateZ" },
|
||||
{ "from": "Standard.LX", "to": "Actions.TranslateX" },
|
||||
{ "from": "Standard.RX", "to": "Actions.Yaw" },
|
||||
{ "from": "Standard.RY", "to": "Actions.Pitch" },
|
||||
{
|
||||
"from": "Standard.DU",
|
||||
"to": "Actions.LONGITUDINAL_FORWARD",
|
||||
"filters": [ { "type": "scale", "scale": 0.5 } ]
|
||||
},
|
||||
{
|
||||
"from": "Standard.DD",
|
||||
"to": "Actions.LONGITUDINAL_BACKWARD",
|
||||
"filters": [ { "type": "scale", "scale": 0.5 } ]
|
||||
},
|
||||
{
|
||||
"from": "Standard.DR",
|
||||
"to": "Actions.LATERAL_RIGHT",
|
||||
"filters": [ { "type": "scale", "scale": 0.5 } ]
|
||||
},
|
||||
{
|
||||
"from": "Standard.DL",
|
||||
"to": "Actions.LATERAL_LEFT",
|
||||
"filters": [ { "type": "scale", "scale": 0.5 } ]
|
||||
},
|
||||
{ "from": "Standard.Y", "to": "Actions.VERTICAL_UP" },
|
||||
{ "from": "Standard.X", "to": "Actions.VERTICAL_DOWN" },
|
||||
{
|
||||
"from": "Standard.RT",
|
||||
"to": "Actions.BOOM_IN",
|
||||
"filters": [ { "type": "scale", "scale": 0.1 } ]
|
||||
},
|
||||
{
|
||||
"from": "Standard.LT",
|
||||
"to": "Actions.BOOM_OUT",
|
||||
"filters": [ { "type": "scale", "scale": 0.1 } ]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,29 +1,29 @@
|
|||
{
|
||||
"name": "XBox to Standard",
|
||||
"channels": [
|
||||
{ "from": "XBox.LY", "to": "Standard.LY" },
|
||||
{ "from": "XBox.LX", "to": "Standard.LX" },
|
||||
{ "from": "XBox.LT", "to": "Standard.LT" },
|
||||
{ "from": "XBox.LB", "to": "Standard.LB" },
|
||||
{ "from": "XBox.LS", "to": "Standard.LS" },
|
||||
{ "from": "GamePad.LY", "to": "Standard.LY" },
|
||||
{ "from": "GamePad.LX", "to": "Standard.LX" },
|
||||
{ "from": "GamePad.LT", "to": "Standard.LT" },
|
||||
{ "from": "GamePad.LB", "to": "Standard.LB" },
|
||||
{ "from": "GamePad.LS", "to": "Standard.LS" },
|
||||
|
||||
{ "from": "XBox.RY", "to": "Standard.RY" },
|
||||
{ "from": "XBox.RX", "to": "Standard.RX" },
|
||||
{ "from": "XBox.RT", "to": "Standard.RT" },
|
||||
{ "from": "XBox.RB", "to": "Standard.RB" },
|
||||
{ "from": "XBox.RS", "to": "Standard.RS" },
|
||||
{ "from": "GamePad.RY", "to": "Standard.RY" },
|
||||
{ "from": "GamePad.RX", "to": "Standard.RX" },
|
||||
{ "from": "GamePad.RT", "to": "Standard.RT" },
|
||||
{ "from": "GamePad.RB", "to": "Standard.RB" },
|
||||
{ "from": "GamePad.RS", "to": "Standard.RS" },
|
||||
|
||||
{ "from": "XBox.Back", "to": "Standard.Back" },
|
||||
{ "from": "XBox.Start", "to": "Standard.Start" },
|
||||
{ "from": "GamePad.Back", "to": "Standard.Back" },
|
||||
{ "from": "GamePad.Start", "to": "Standard.Start" },
|
||||
|
||||
{ "from": "XBox.DU", "to": "Standard.DU" },
|
||||
{ "from": "XBox.DD", "to": "Standard.DD" },
|
||||
{ "from": "XBox.DL", "to": "Standard.DL" },
|
||||
{ "from": "XBox.DR", "to": "Standard.DR" },
|
||||
{ "from": "GamePad.DU", "to": "Standard.DU" },
|
||||
{ "from": "GamePad.DD", "to": "Standard.DD" },
|
||||
{ "from": "GamePad.DL", "to": "Standard.DL" },
|
||||
{ "from": "GamePad.DR", "to": "Standard.DR" },
|
||||
|
||||
{ "from": "XBox.A", "to": "Standard.A" },
|
||||
{ "from": "XBox.B", "to": "Standard.B" },
|
||||
{ "from": "XBox.X", "to": "Standard.X" },
|
||||
{ "from": "XBox.Y", "to": "Standard.Y" }
|
||||
{ "from": "GamePad.A", "to": "Standard.A" },
|
||||
{ "from": "GamePad.B", "to": "Standard.B" },
|
||||
{ "from": "GamePad.X", "to": "Standard.X" },
|
||||
{ "from": "GamePad.Y", "to": "Standard.Y" }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ HifiControls.VrDialog {
|
|||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
var xboxRegex = /^X360Controller/;
|
||||
var xboxRegex = /^GamePad/;
|
||||
var hydraRegex = /^Hydra/;
|
||||
for (var prop in Controller.Hardware) {
|
||||
if(xboxRegex.test(prop)) {
|
||||
|
|
|
@ -631,7 +631,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
|
||||
if (state) {
|
||||
switch (action) {
|
||||
case UserInputMapper::Action::TOGGLE_MUTE:
|
||||
case controller::Action::TOGGLE_MUTE:
|
||||
DependencyManager::get<AudioClient>()->toggleMute();
|
||||
break;
|
||||
}
|
||||
|
@ -639,8 +639,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
});
|
||||
|
||||
// Setup the keyboardMouseDevice and the user input mapper with the default bindings
|
||||
_keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
|
||||
_keyboardMouseDevice->assignDefaultInputMapping(*userInputMapper);
|
||||
userInputMapper->registerDevice(_keyboardMouseDevice);
|
||||
|
||||
// check first run...
|
||||
if (_firstRun.get()) {
|
||||
|
@ -2182,7 +2181,7 @@ float Application::getAvatarSimrate() {
|
|||
}
|
||||
|
||||
void Application::setLowVelocityFilter(bool lowVelocityFilter) {
|
||||
InputDevice::setLowVelocityFilter(lowVelocityFilter);
|
||||
controller::InputDevice::setLowVelocityFilter(lowVelocityFilter);
|
||||
}
|
||||
|
||||
ivec2 Application::getMouse() const {
|
||||
|
@ -2710,19 +2709,28 @@ void Application::update(float deltaTime) {
|
|||
auto myAvatar = getMyAvatar();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
|
||||
// Dispatch input events
|
||||
_controllerScriptingInterface->update();
|
||||
userInputMapper->update(deltaTime);
|
||||
|
||||
bool jointsCaptured = false;
|
||||
for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (inputPlugin->isActive()) {
|
||||
inputPlugin->pluginUpdate(deltaTime, jointsCaptured);
|
||||
if (inputPlugin->isJointController()) {
|
||||
jointsCaptured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer the user inputs to the driveKeys
|
||||
myAvatar->clearDriveKeys();
|
||||
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
|
||||
if (!_controllerScriptingInterface->areActionsCaptured()) {
|
||||
myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
|
||||
myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
|
||||
myAvatar->setDriveKeys(UP, userInputMapper->getActionState(UserInputMapper::VERTICAL_UP));
|
||||
myAvatar->setDriveKeys(DOWN, userInputMapper->getActionState(UserInputMapper::VERTICAL_DOWN));
|
||||
myAvatar->setDriveKeys(LEFT, userInputMapper->getActionState(UserInputMapper::LATERAL_LEFT));
|
||||
myAvatar->setDriveKeys(RIGHT, userInputMapper->getActionState(UserInputMapper::LATERAL_RIGHT));
|
||||
myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(controller::LONGITUDINAL_FORWARD));
|
||||
myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(controller::LONGITUDINAL_BACKWARD));
|
||||
myAvatar->setDriveKeys(UP, userInputMapper->getActionState(controller::VERTICAL_UP));
|
||||
myAvatar->setDriveKeys(DOWN, userInputMapper->getActionState(controller::VERTICAL_DOWN));
|
||||
myAvatar->setDriveKeys(LEFT, userInputMapper->getActionState(controller::LATERAL_LEFT));
|
||||
myAvatar->setDriveKeys(RIGHT, userInputMapper->getActionState(controller::LATERAL_RIGHT));
|
||||
if (deltaTime > FLT_EPSILON) {
|
||||
// For rotations what we really want are meausures of "angles per second" (in order to prevent
|
||||
// fps-dependent spin rates) so we need to scale the units of the controller contribution.
|
||||
|
@ -2730,25 +2738,25 @@ void Application::update(float deltaTime) {
|
|||
// controllers to provide a delta_per_second value rather than a raw delta.)
|
||||
const float EXPECTED_FRAME_RATE = 60.0f;
|
||||
float timeFactor = EXPECTED_FRAME_RATE * deltaTime;
|
||||
myAvatar->setDriveKeys(ROT_UP, userInputMapper->getActionState(UserInputMapper::PITCH_UP) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_DOWN, userInputMapper->getActionState(UserInputMapper::PITCH_DOWN) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_LEFT, userInputMapper->getActionState(UserInputMapper::YAW_LEFT) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_RIGHT, userInputMapper->getActionState(UserInputMapper::YAW_RIGHT) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_UP, userInputMapper->getActionState(controller::PITCH_UP) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_DOWN, userInputMapper->getActionState(controller::PITCH_DOWN) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_LEFT, userInputMapper->getActionState(controller::YAW_LEFT) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_RIGHT, userInputMapper->getActionState(controller::YAW_RIGHT) / timeFactor);
|
||||
}
|
||||
}
|
||||
myAvatar->setDriveKeys(BOOM_IN, userInputMapper->getActionState(UserInputMapper::BOOM_IN));
|
||||
myAvatar->setDriveKeys(BOOM_OUT, userInputMapper->getActionState(UserInputMapper::BOOM_OUT));
|
||||
myAvatar->setDriveKeys(BOOM_IN, userInputMapper->getActionState(controller::BOOM_IN));
|
||||
myAvatar->setDriveKeys(BOOM_OUT, userInputMapper->getActionState(controller::BOOM_OUT));
|
||||
}
|
||||
UserInputMapper::PoseValue leftHand = userInputMapper->getPoseState(UserInputMapper::LEFT_HAND);
|
||||
UserInputMapper::PoseValue rightHand = userInputMapper->getPoseState(UserInputMapper::RIGHT_HAND);
|
||||
controller::Pose leftHand = userInputMapper->getPoseState(controller::LEFT_HAND);
|
||||
controller::Pose rightHand = userInputMapper->getPoseState(controller::RIGHT_HAND);
|
||||
Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
|
||||
setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK));
|
||||
setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK));
|
||||
setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(controller::LEFT_HAND_CLICK));
|
||||
setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(controller::RIGHT_HAND_CLICK));
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
|
||||
emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK),
|
||||
userInputMapper->getActionState(UserInputMapper::SHIFT), LEFT_HAND_INDEX);
|
||||
emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK),
|
||||
userInputMapper->getActionState(UserInputMapper::SHIFT), RIGHT_HAND_INDEX);
|
||||
emulateMouse(hand, userInputMapper->getActionState(controller::LEFT_HAND_CLICK),
|
||||
userInputMapper->getActionState(controller::SHIFT), LEFT_HAND_INDEX);
|
||||
emulateMouse(hand, userInputMapper->getActionState(controller::RIGHT_HAND_CLICK),
|
||||
userInputMapper->getActionState(controller::SHIFT), RIGHT_HAND_INDEX);
|
||||
}
|
||||
|
||||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||
|
@ -4806,7 +4814,7 @@ mat4 Application::getHMDSensorPose() const {
|
|||
return mat4();
|
||||
}
|
||||
|
||||
void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue) {
|
||||
void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue) {
|
||||
PalmData* palm;
|
||||
bool foundHand = false;
|
||||
for (size_t j = 0; j < hand->getNumPalms(); j++) {
|
||||
|
@ -4855,7 +4863,7 @@ void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float
|
|||
palm->setRawAngularVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
|
||||
if (InputDevice::getLowVelocityFilter()) {
|
||||
if (controller::InputDevice::getLowVelocityFilter()) {
|
||||
// Use a velocity sensitive filter to damp small motions and preserve large ones with
|
||||
// no latency.
|
||||
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
|
||||
|
@ -4911,7 +4919,7 @@ void Application::emulateMouse(Hand* hand, float click, float shift, int index)
|
|||
float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)M_PI_2));
|
||||
auto canvasSize = getCanvasSize();
|
||||
// Get the pixel range over which the xAngle and yAngle are scaled
|
||||
float cursorRange = canvasSize.x * InputDevice::getCursorPixelRangeMult();
|
||||
float cursorRange = canvasSize.x * controller::InputDevice::getCursorPixelRangeMult();
|
||||
|
||||
pos.setX(canvasSize.x / 2.0f + cursorRange * xAngle);
|
||||
pos.setY(canvasSize.y / 2.0f + cursorRange * yAngle);
|
||||
|
|
|
@ -352,7 +352,7 @@ private:
|
|||
|
||||
void update(float deltaTime);
|
||||
|
||||
void setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue);
|
||||
void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue);
|
||||
void emulateMouse(Hand* hand, float click, float shift, int index);
|
||||
|
||||
// Various helper functions called during update()
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
//
|
||||
|
||||
#include "3DConnexionClient.h"
|
||||
|
||||
#include <UserActivityLogger.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "Menu.h"
|
||||
#include "UserActivityLogger.h"
|
||||
|
||||
const float MAX_AXIS = 75.0f; // max forward = 2x speed
|
||||
|
||||
|
@ -25,8 +28,9 @@ ConnexionData& ConnexionData::getInstance() {
|
|||
return sharedInstance;
|
||||
}
|
||||
|
||||
ConnexionData::ConnexionData() {
|
||||
}
|
||||
|
||||
ConnexionData::ConnexionData() : InputDevice("ConnexionClient") {}
|
||||
|
||||
|
||||
void ConnexionData::handleAxisEvent() {
|
||||
_axisStateMap[makeInput(ROTATION_AXIS_Y_POS).getChannel()] = (cc_rotation.y > 0.0f) ? cc_rotation.y / MAX_AXIS : 0.0f;
|
||||
|
@ -48,76 +52,71 @@ void ConnexionData::setButton(int lastButtonState) {
|
|||
_buttonPressedMap.insert(lastButtonState);
|
||||
}
|
||||
|
||||
void ConnexionData::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||
// Grab the current free device ID
|
||||
_deviceID = mapper.getFreeDeviceID();
|
||||
void ConnexionData::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
|
||||
proxy->_name = _name = "ConnexionClient";
|
||||
proxy->getButton = [this](const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this](const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<controller::Input::NamedPair> {
|
||||
QVector<controller::Input::NamedPair> availableInputs;
|
||||
|
||||
auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("ConnexionClient"));
|
||||
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;
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_1), "Left button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_2), "Right button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_3), "Both buttons"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_NEG), "Move backward"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_POS), "Move forward"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_POS), "Move right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_NEG), "Move Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_POS), "Move up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_NEG), "Move down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_NEG), "Rotate backward"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_POS), "Rotate forward"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_POS), "Rotate right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_NEG), "Rotate left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_POS), "Rotate up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_NEG), "Rotate down"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_1), "Left button"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_2), "Right button"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_3), "Both buttons"));
|
||||
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Y_NEG), "Move backward"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Y_POS), "Move forward"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_X_POS), "Move right"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_X_NEG), "Move Left"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Z_POS), "Move up"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Z_NEG), "Move down"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Y_NEG), "Rotate backward"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Y_POS), "Rotate forward"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_X_POS), "Rotate right"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_X_NEG), "Rotate left"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Z_POS), "Rotate up"));
|
||||
availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Z_NEG), "Rotate down"));
|
||||
return availableInputs;
|
||||
};
|
||||
proxy->resetDeviceBindings = [this, &mapper]() -> bool {
|
||||
mapper.removeAllInputChannelsForDevice(_deviceID);
|
||||
this->assignDefaultInputMapping(mapper);
|
||||
return true;
|
||||
};
|
||||
mapper.registerDevice(_deviceID, proxy);
|
||||
}
|
||||
|
||||
void ConnexionData::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)
|
||||
// postion: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED);
|
||||
|
||||
// Rotation: Camera orientation with button 1
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
|
||||
|
||||
// Button controls
|
||||
// Zoom
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED);
|
||||
|
||||
// Zoom
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED);
|
||||
|
||||
QString ConnexionData::getDefaultMappingConfig() {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
||||
//void ConnexionData::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)
|
||||
// // postion: Movement, strafing
|
||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED);
|
||||
//
|
||||
// // Rotation: Camera orientation with button 1
|
||||
// mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
|
||||
//
|
||||
// // Button controls
|
||||
// // Zoom
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED);
|
||||
//
|
||||
// // Zoom
|
||||
// // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED);
|
||||
// // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED);
|
||||
//
|
||||
//}
|
||||
|
||||
float ConnexionData::getButton(int channel) const {
|
||||
if (!_buttonPressedMap.empty()) {
|
||||
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
|
||||
|
@ -138,15 +137,15 @@ float ConnexionData::getAxis(int channel) const {
|
|||
}
|
||||
}
|
||||
|
||||
UserInputMapper::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) {
|
||||
return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
|
||||
controller::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) {
|
||||
return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
UserInputMapper::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) {
|
||||
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
|
||||
controller::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) {
|
||||
return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
void ConnexionData::update() {
|
||||
void ConnexionData::update(float deltaTime, bool jointsCaptured) {
|
||||
// the update is done in the ConnexionClient class.
|
||||
// for windows in the nativeEventFilter the inputmapper is connected or registed or removed when an 3Dconnnexion device is attached or detached
|
||||
// for osx the api will call DeviceAddedHandler or DeviceRemoveHandler when a 3Dconnexion device is attached or detached
|
||||
|
@ -187,7 +186,6 @@ void ConnexionClient::destroy() {
|
|||
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
int deviceid = connexiondata.getDeviceID();
|
||||
connexiondata.setDeviceID(0);
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->removeDevice(deviceid);
|
||||
}
|
||||
|
@ -295,13 +293,10 @@ bool ConnexionClient::RawInputEventFilter(void* msg, long* result) {
|
|||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) {
|
||||
connexiondata.registerToUserInputMapper(*userInputMapper);
|
||||
connexiondata.assignDefaultInputMapping(*userInputMapper);
|
||||
userInputMapper->registerDevice(&connexiondata);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
|
||||
} else if (!Is3dmouseAttached() && connexiondata.getDeviceID() != 0) {
|
||||
int deviceid = connexiondata.getDeviceID();
|
||||
connexiondata.setDeviceID(0);
|
||||
userInputMapper->removeDevice(deviceid);
|
||||
userInputMapper->removeDevice(connexiondata.getDeviceID());
|
||||
}
|
||||
|
||||
if (!Is3dmouseAttached()) {
|
||||
|
@ -894,8 +889,7 @@ void ConnexionClient::init() {
|
|||
|
||||
if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
connexiondata.registerToUserInputMapper(*userInputMapper);
|
||||
connexiondata.assignDefaultInputMapping(*userInputMapper);
|
||||
userInputMapper->registerDevice(&connexiondata);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
|
||||
}
|
||||
//let one axis be dominant
|
||||
|
@ -926,8 +920,7 @@ void DeviceAddedHandler(unsigned int connection) {
|
|||
if (connexiondata.getDeviceID() == 0) {
|
||||
qCWarning(interfaceapp) << "3Dconnexion device added ";
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
connexiondata.registerToUserInputMapper(*userInputMapper);
|
||||
connexiondata.assignDefaultInputMapping(*userInputMapper);
|
||||
userInputMapper->registerDevice(&connexiondata);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,13 +175,12 @@ public slots:
|
|||
|
||||
|
||||
// connnects to the userinputmapper
|
||||
class ConnexionData : public QObject {
|
||||
class ConnexionData : public QObject, public controller::InputDevice {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static ConnexionData& getInstance();
|
||||
ConnexionData();
|
||||
|
||||
enum PositionChannel {
|
||||
POSITION_AXIS_X_POS = 1,
|
||||
POSITION_AXIS_X_NEG = 2,
|
||||
|
@ -209,19 +208,12 @@ public:
|
|||
float getButton(int channel) const;
|
||||
float getAxis(int channel) const;
|
||||
|
||||
UserInputMapper::Input makeInput(ConnexionData::PositionChannel axis);
|
||||
UserInputMapper::Input makeInput(ConnexionData::ButtonChannel button);
|
||||
|
||||
void registerToUserInputMapper(UserInputMapper& mapper);
|
||||
void assignDefaultInputMapping(UserInputMapper& mapper);
|
||||
|
||||
void update();
|
||||
void focusOutEvent();
|
||||
|
||||
int getDeviceID() { return _deviceID; }
|
||||
void setDeviceID(int deviceID) { _deviceID = deviceID; }
|
||||
|
||||
QString _name;
|
||||
controller::Input makeInput(ConnexionData::PositionChannel axis);
|
||||
controller::Input makeInput(ConnexionData::ButtonChannel button);
|
||||
virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
|
||||
virtual QString getDefaultMappingConfig() override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
glm::vec3 cc_position;
|
||||
glm::vec3 cc_rotation;
|
||||
|
@ -229,12 +221,6 @@ public:
|
|||
|
||||
void setButton(int lastButtonState);
|
||||
void handleAxisEvent();
|
||||
|
||||
protected:
|
||||
int _deviceID = 0;
|
||||
|
||||
ButtonPressedMap _buttonPressedMap;
|
||||
AxisStateMap _axisStateMap;
|
||||
};
|
||||
|
||||
#endif // defined(hifi_3DConnexionClient_h)
|
||||
|
|
|
@ -167,31 +167,6 @@ void ControllerScriptingInterface::releaseInputController(controller::InputContr
|
|||
_inputControllers.erase(input->getKey());
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::update() {
|
||||
static float last = secTimestampNow();
|
||||
float now = secTimestampNow();
|
||||
float delta = now - last;
|
||||
last = now;
|
||||
|
||||
DependencyManager::get<UserInputMapper>()->update(delta);
|
||||
|
||||
bool jointsCaptured = false;
|
||||
for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (inputPlugin->isActive()) {
|
||||
inputPlugin->pluginUpdate(delta, jointsCaptured);
|
||||
if (inputPlugin->isJointController()) {
|
||||
jointsCaptured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto entry : _inputControllers) {
|
||||
entry.second->update();
|
||||
}
|
||||
|
||||
controller::ScriptingInterface::update();
|
||||
}
|
||||
|
||||
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
|
||||
_deviceTrackerId(deviceTrackerId),
|
||||
_subTrackerId(subTrackerId),
|
||||
|
|
|
@ -85,8 +85,6 @@ public:
|
|||
bool isKeyCaptured(const KeyEvent& event) const;
|
||||
bool isJoystickCaptured(int joystickIndex) const;
|
||||
|
||||
virtual void update() override;
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void captureKeyEvents(const KeyEvent& event);
|
||||
|
|
|
@ -521,7 +521,7 @@ void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) {
|
|||
float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)PI_OVER_TWO));
|
||||
|
||||
// Get the pixel range over which the xAngle and yAngle are scaled
|
||||
float cursorRange = canvasSize.x * InputDevice::getCursorPixelRangeMult();
|
||||
float cursorRange = canvasSize.x * controller::InputDevice::getCursorPixelRangeMult();
|
||||
|
||||
mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle);
|
||||
mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle);
|
||||
|
|
|
@ -198,7 +198,7 @@ void PreferencesDialog::loadPreferences() {
|
|||
ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationCompositor().getHmdUIAngularSize());
|
||||
#endif
|
||||
|
||||
ui.sixenseReticleMoveSpeedSpin->setValue(InputDevice::getReticleMoveSpeed());
|
||||
ui.sixenseReticleMoveSpeedSpin->setValue(controller::InputDevice::getReticleMoveSpeed());
|
||||
|
||||
// LOD items
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
|
@ -273,7 +273,7 @@ void PreferencesDialog::savePreferences() {
|
|||
|
||||
qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
|
||||
|
||||
InputDevice::setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
|
||||
controller::InputDevice::setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
|
||||
|
||||
auto audio = DependencyManager::get<AudioClient>();
|
||||
MixedProcessedAudioStream& stream = audio->getReceivedAudioStream();
|
||||
|
|
71
libraries/controllers/src/controllers/Actions.cpp
Normal file
71
libraries/controllers/src/controllers/Actions.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/10/19
|
||||
// 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 "Actions.h"
|
||||
|
||||
#include "UserInputMapper.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
// Device functions
|
||||
void ActionsDevice::buildDeviceProxy(DeviceProxy::Pointer proxy) {
|
||||
proxy->_name = _name;
|
||||
proxy->getButton = [this](const Input& input, int timestamp) -> bool { return false; };
|
||||
proxy->getAxis = [this](const Input& input, int timestamp) -> float { return 0; };
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
|
||||
QVector<Input::NamedPair> availableInputs{
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LONGITUDINAL_BACKWARD, ChannelType::AXIS), "LONGITUDINAL_BACKWARD"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LONGITUDINAL_FORWARD, ChannelType::AXIS), "LONGITUDINAL_FORWARD"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LATERAL_LEFT, ChannelType::AXIS), "LATERAL_LEFT"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LATERAL_RIGHT, ChannelType::AXIS), "LATERAL_RIGHT"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, VERTICAL_DOWN, ChannelType::AXIS), "VERTICAL_DOWN"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, VERTICAL_UP, ChannelType::AXIS), "VERTICAL_UP"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, YAW_LEFT, ChannelType::AXIS), "YAW_LEFT"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, YAW_RIGHT, ChannelType::AXIS), "YAW_RIGHT"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, PITCH_DOWN, ChannelType::AXIS), "PITCH_DOWN"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, PITCH_UP, ChannelType::AXIS), "PITCH_UP"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, BOOM_IN, ChannelType::AXIS), "BOOM_IN"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, BOOM_OUT, ChannelType::AXIS), "BOOM_OUT"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LEFT_HAND, ChannelType::POSE), "LEFT_HAND"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, RIGHT_HAND, ChannelType::POSE), "RIGHT_HAND"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LEFT_HAND_CLICK, ChannelType::BUTTON), "LEFT_HAND_CLICK"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, RIGHT_HAND_CLICK, ChannelType::BUTTON), "RIGHT_HAND_CLICK"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, SHIFT, ChannelType::BUTTON), "SHIFT"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, ACTION1, ChannelType::BUTTON), "ACTION1"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, ACTION2, ChannelType::BUTTON), "ACTION2"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, CONTEXT_MENU, ChannelType::BUTTON), "CONTEXT_MENU"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TOGGLE_MUTE, ChannelType::AXIS), "TOGGLE_MUTE"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TRANSLATE_X, ChannelType::AXIS), "TranslateX"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TRANSLATE_Y, ChannelType::AXIS), "TranslateY"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TRANSLATE_Z, ChannelType::AXIS), "TranslateZ"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, ROLL, ChannelType::AXIS), "Roll"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, PITCH, ChannelType::AXIS), "Pitch"),
|
||||
Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, YAW, ChannelType::AXIS), "Yaw")
|
||||
};
|
||||
return availableInputs;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
QString ActionsDevice::getDefaultMappingConfig() {
|
||||
return QString();
|
||||
}
|
||||
|
||||
void ActionsDevice::update(float deltaTime, bool jointsCaptured) {
|
||||
}
|
||||
|
||||
void ActionsDevice::focusOutEvent() {
|
||||
}
|
||||
|
||||
ActionsDevice::ActionsDevice() : InputDevice("Actions") {
|
||||
_deviceID = UserInputMapper::ACTIONS_DEVICE;
|
||||
}
|
||||
|
||||
ActionsDevice::~ActionsDevice() {}
|
||||
|
||||
}
|
100
libraries/controllers/src/controllers/Actions.h
Normal file
100
libraries/controllers/src/controllers/Actions.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/10/19
|
||||
// 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_controller_Actions_h
|
||||
#define hifi_controller_Actions_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include "InputDevice.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
// Actions are the output channels of the Mapper, that's what the InputChannel map to
|
||||
// For now the Actions are hardcoded, this is bad, but we will fix that in the near future
|
||||
enum Action {
|
||||
TRANSLATE_X = 0,
|
||||
TRANSLATE_Y,
|
||||
TRANSLATE_Z,
|
||||
ROTATE_X, PITCH = ROTATE_X,
|
||||
ROTATE_Y, YAW = ROTATE_Y,
|
||||
ROTATE_Z, ROLL = ROTATE_Z,
|
||||
|
||||
TRANSLATE_CAMERA_Z,
|
||||
NUM_COMBINED_AXES,
|
||||
|
||||
LEFT_HAND = NUM_COMBINED_AXES,
|
||||
RIGHT_HAND,
|
||||
|
||||
LEFT_HAND_CLICK,
|
||||
RIGHT_HAND_CLICK,
|
||||
|
||||
ACTION1,
|
||||
ACTION2,
|
||||
|
||||
CONTEXT_MENU,
|
||||
TOGGLE_MUTE,
|
||||
|
||||
SHIFT,
|
||||
|
||||
// Biseced aliases for TRANSLATE_Z
|
||||
LONGITUDINAL_BACKWARD,
|
||||
LONGITUDINAL_FORWARD,
|
||||
|
||||
// Biseced aliases for TRANSLATE_X
|
||||
LATERAL_LEFT,
|
||||
LATERAL_RIGHT,
|
||||
|
||||
// Biseced aliases for TRANSLATE_Y
|
||||
VERTICAL_DOWN,
|
||||
VERTICAL_UP,
|
||||
|
||||
// Biseced aliases for ROTATE_Y
|
||||
YAW_LEFT,
|
||||
YAW_RIGHT,
|
||||
|
||||
// Biseced aliases for ROTATE_X
|
||||
PITCH_DOWN,
|
||||
PITCH_UP,
|
||||
|
||||
// Biseced aliases for TRANSLATE_CAMERA_Z
|
||||
BOOM_IN,
|
||||
BOOM_OUT,
|
||||
|
||||
NUM_ACTIONS,
|
||||
};
|
||||
|
||||
|
||||
class ActionsDevice : public QObject, public InputDevice {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ getName)
|
||||
|
||||
public:
|
||||
const QString& getName() const { return _name; }
|
||||
|
||||
// Device functions
|
||||
virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override;
|
||||
virtual QString getDefaultMappingConfig() override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
ActionsDevice();
|
||||
virtual ~ActionsDevice();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#include "StandardControls.h"
|
||||
|
||||
|
||||
#endif // hifi_StandardController_h
|
|
@ -20,7 +20,7 @@ namespace controller {
|
|||
return getAxis(input, timestamp);
|
||||
|
||||
case ChannelType::POSE:
|
||||
return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
|
||||
return getPose(input, timestamp).valid ? 1.0f : 0.0f;
|
||||
|
||||
default:
|
||||
return NAN;
|
||||
|
|
|
@ -35,23 +35,15 @@ namespace controller {
|
|||
|
||||
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;
|
||||
using Pointer = std::shared_ptr<DeviceProxy>;
|
||||
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 const { return Input::NamedVector(); };
|
||||
float getValue(const Input& input, int timestamp = 0) const;
|
||||
QString _name;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include "UserInputMapper.h"
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "Input.h"
|
||||
|
||||
class QScriptValue;
|
||||
|
||||
|
@ -24,7 +26,7 @@ namespace controller {
|
|||
* i.e. Hydra.Button0, Standard.X, Action.Yaw
|
||||
*/
|
||||
class Endpoint : public QObject {
|
||||
Q_OBJECT;
|
||||
Q_OBJECT;
|
||||
public:
|
||||
using Pointer = std::shared_ptr<Endpoint>;
|
||||
using List = std::list<Pointer>;
|
||||
|
@ -32,18 +34,18 @@ namespace controller {
|
|||
using ReadLambda = std::function<float()>;
|
||||
using WriteLambda = std::function<void(float)>;
|
||||
|
||||
Endpoint(const UserInputMapper::Input& input) : _input(input) {}
|
||||
Endpoint(const Input& input) : _input(input) {}
|
||||
virtual float value() = 0;
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
|
||||
const UserInputMapper::Input& getInput() { return _input; }
|
||||
const Input& getInput() { return _input; }
|
||||
protected:
|
||||
UserInputMapper::Input _input;
|
||||
Input _input;
|
||||
};
|
||||
|
||||
class LambdaEndpoint : public Endpoint {
|
||||
public:
|
||||
LambdaEndpoint(ReadLambda readLambda, WriteLambda writeLambda = [](float) {})
|
||||
: Endpoint(UserInputMapper::Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
|
||||
: Endpoint(Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
|
||||
|
||||
virtual float value() override { return _readLambda(); }
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override { _writeLambda(newValue); }
|
||||
|
|
|
@ -27,26 +27,21 @@ enum class ChannelType {
|
|||
// to the Action channels
|
||||
struct Input {
|
||||
union {
|
||||
uint32_t id{ 0 }; // by default Input is 0 meaning invalid
|
||||
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
|
||||
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); }
|
||||
bool isValid() const { return (id != INVALID_INPUT.id); }
|
||||
|
||||
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; }
|
||||
uint16_t getDevice() const { return device; }
|
||||
uint16_t getChannel() const { return channel; }
|
||||
uint32_t getID() const { return id; }
|
||||
ChannelType getType() const { return (ChannelType) type; }
|
||||
|
||||
bool isButton() const { return getType() == ChannelType::BUTTON; }
|
||||
bool isAxis() const { return getType() == ChannelType::AXIS; }
|
||||
|
@ -54,13 +49,13 @@ struct Input {
|
|||
|
||||
// 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; }
|
||||
explicit Input() {}
|
||||
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 INVALID_INPUT.id != id && INVALID_INPUT.id != right.id && id == right.id; }
|
||||
bool operator < (const Input& src) const { return id < src.id; }
|
||||
|
||||
static const Input INVALID_INPUT;
|
||||
static const uint16_t INVALID_DEVICE;
|
||||
|
|
|
@ -10,75 +10,78 @@
|
|||
//
|
||||
#include "InputDevice.h"
|
||||
|
||||
bool InputDevice::_lowVelocityFilter = false;
|
||||
#include "Input.h"
|
||||
|
||||
const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
|
||||
float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
|
||||
namespace controller {
|
||||
|
||||
//Constants for getCursorPixelRangeMultiplier()
|
||||
const float MIN_PIXEL_RANGE_MULT = 0.4f;
|
||||
const float MAX_PIXEL_RANGE_MULT = 2.0f;
|
||||
const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f;
|
||||
bool InputDevice::_lowVelocityFilter = false;
|
||||
|
||||
//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;
|
||||
}
|
||||
const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
|
||||
float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
|
||||
|
||||
float InputDevice::getButton(int channel) const {
|
||||
if (!_buttonPressedMap.empty()) {
|
||||
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
|
||||
return 1.0f;
|
||||
//Constants for getCursorPixelRangeMultiplier()
|
||||
const float MIN_PIXEL_RANGE_MULT = 0.4f;
|
||||
const float MAX_PIXEL_RANGE_MULT = 2.0f;
|
||||
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;
|
||||
}
|
||||
|
||||
float InputDevice::getButton(int channel) const {
|
||||
if (!_buttonPressedMap.empty()) {
|
||||
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
|
||||
return 1.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float InputDevice::getAxis(int channel) const {
|
||||
auto axis = _axisStateMap.find(channel);
|
||||
if (axis != _axisStateMap.end()) {
|
||||
return (*axis).second;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float InputDevice::getAxis(int channel) const {
|
||||
auto axis = _axisStateMap.find(channel);
|
||||
if (axis != _axisStateMap.end()) {
|
||||
return (*axis).second;
|
||||
Pose InputDevice::getPose(int channel) const {
|
||||
auto pose = _poseStateMap.find(channel);
|
||||
if (pose != _poseStateMap.end()) {
|
||||
return (*pose).second;
|
||||
} else {
|
||||
return Pose();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0.0f;
|
||||
|
||||
Input InputDevice::makeInput(controller::StandardButtonChannel button) {
|
||||
return Input(_deviceID, button, ChannelType::BUTTON);
|
||||
}
|
||||
}
|
||||
|
||||
UserInputMapper::PoseValue InputDevice::getPose(int channel) const {
|
||||
auto pose = _poseStateMap.find(channel);
|
||||
if (pose != _poseStateMap.end()) {
|
||||
return (*pose).second;
|
||||
Input InputDevice::makeInput(controller::StandardAxisChannel axis) {
|
||||
return Input(_deviceID, axis, ChannelType::AXIS);
|
||||
}
|
||||
else {
|
||||
return UserInputMapper::PoseValue();
|
||||
|
||||
Input InputDevice::makeInput(controller::StandardPoseChannel pose) {
|
||||
return Input(_deviceID, pose, ChannelType::POSE);
|
||||
}
|
||||
}
|
||||
|
||||
UserInputMapper::Input InputDevice::makeInput(controller::StandardButtonChannel button) {
|
||||
return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
|
||||
}
|
||||
Input::NamedPair InputDevice::makePair(controller::StandardButtonChannel button, const QString& name) {
|
||||
return Input::NamedPair(makeInput(button), name);
|
||||
}
|
||||
|
||||
UserInputMapper::Input InputDevice::makeInput(controller::StandardAxisChannel axis) {
|
||||
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
|
||||
}
|
||||
Input::NamedPair InputDevice::makePair(controller::StandardAxisChannel axis, const QString& name) {
|
||||
return Input::NamedPair(makeInput(axis), name);
|
||||
}
|
||||
|
||||
UserInputMapper::Input InputDevice::makeInput(controller::StandardPoseChannel pose) {
|
||||
return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
|
||||
}
|
||||
Input::NamedPair InputDevice::makePair(controller::StandardPoseChannel pose, const QString& name) {
|
||||
return Input::NamedPair(makeInput(pose), name);
|
||||
}
|
||||
|
||||
UserInputMapper::InputPair InputDevice::makePair(controller::StandardButtonChannel button, const QString& name) {
|
||||
return UserInputMapper::InputPair(makeInput(button), name);
|
||||
}
|
||||
|
||||
UserInputMapper::InputPair InputDevice::makePair(controller::StandardAxisChannel axis, const QString& name) {
|
||||
return UserInputMapper::InputPair(makeInput(axis), name);
|
||||
}
|
||||
|
||||
UserInputMapper::InputPair InputDevice::makePair(controller::StandardPoseChannel pose, const QString& name) {
|
||||
return UserInputMapper::InputPair(makeInput(pose), name);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,23 @@
|
|||
//
|
||||
#pragma once
|
||||
|
||||
#include "UserInputMapper.h"
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include "Pose.h"
|
||||
#include "Input.h"
|
||||
#include "StandardControls.h"
|
||||
#include "DeviceProxy.h"
|
||||
|
||||
// Event types for each controller
|
||||
const unsigned int CONTROLLER_0_EVENT = 1500U;
|
||||
const unsigned int CONTROLLER_1_EVENT = 1501U;
|
||||
|
||||
namespace controller {
|
||||
|
||||
// NOTE: If something inherits from both InputDevice and InputPlugin, InputPlugin must go first.
|
||||
// e.g. class Example : public InputPlugin, public InputDevice
|
||||
// instead of class Example : public InputDevice, public InputPlugin
|
||||
|
@ -24,17 +34,19 @@ class InputDevice {
|
|||
public:
|
||||
InputDevice(const QString& name) : _name(name) {}
|
||||
|
||||
using Pointer = std::shared_ptr<InputDevice>;
|
||||
|
||||
typedef std::unordered_set<int> ButtonPressedMap;
|
||||
typedef std::map<int, float> AxisStateMap;
|
||||
typedef std::map<int, UserInputMapper::PoseValue> PoseStateMap;
|
||||
typedef std::map<int, Pose> PoseStateMap;
|
||||
|
||||
// Get current state for each channel
|
||||
float getButton(int channel) const;
|
||||
float getAxis(int channel) const;
|
||||
UserInputMapper::PoseValue getPose(int channel) const;
|
||||
Pose getPose(int channel) const;
|
||||
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) = 0;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) = 0;
|
||||
virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) = 0;
|
||||
virtual QString getDefaultMappingConfig() = 0;
|
||||
|
||||
// Update call MUST be called once per simulation loop
|
||||
// It takes care of updating the action states and deltas
|
||||
|
@ -43,6 +55,7 @@ public:
|
|||
virtual void focusOutEvent() = 0;
|
||||
|
||||
int getDeviceID() { return _deviceID; }
|
||||
void setDeviceID(int deviceID) { _deviceID = deviceID; }
|
||||
|
||||
static float getCursorPixelRangeMult();
|
||||
static float getReticleMoveSpeed() { return _reticleMoveSpeed; }
|
||||
|
@ -50,18 +63,18 @@ public:
|
|||
|
||||
static bool getLowVelocityFilter() { return _lowVelocityFilter; };
|
||||
|
||||
UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
|
||||
UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
|
||||
UserInputMapper::Input makeInput(controller::StandardPoseChannel pose);
|
||||
UserInputMapper::InputPair makePair(controller::StandardButtonChannel button, const QString& name);
|
||||
UserInputMapper::InputPair makePair(controller::StandardAxisChannel button, const QString& name);
|
||||
UserInputMapper::InputPair makePair(controller::StandardPoseChannel button, const QString& name);
|
||||
public slots:
|
||||
Input makeInput(StandardButtonChannel button);
|
||||
Input makeInput(StandardAxisChannel axis);
|
||||
Input makeInput(StandardPoseChannel pose);
|
||||
Input::NamedPair makePair(StandardButtonChannel button, const QString& name);
|
||||
Input::NamedPair makePair(StandardAxisChannel button, const QString& name);
|
||||
Input::NamedPair makePair(StandardPoseChannel button, const QString& name);
|
||||
public slots:
|
||||
static void setLowVelocityFilter(bool newLowVelocityFilter) { _lowVelocityFilter = newLowVelocityFilter; };
|
||||
|
||||
protected:
|
||||
|
||||
int _deviceID = 0;
|
||||
friend class UserInputMapper;
|
||||
uint16_t _deviceID{ Input::INVALID_DEVICE };
|
||||
|
||||
QString _name;
|
||||
|
||||
|
@ -73,4 +86,6 @@ protected:
|
|||
|
||||
private:
|
||||
static float _reticleMoveSpeed;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
|
@ -6,11 +6,3 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "Mapping.h"
|
||||
|
||||
namespace controller {
|
||||
Mapping::Mapping(const QString& name ) : _name(name) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -27,13 +27,11 @@ namespace controller {
|
|||
using Map = std::map<Endpoint::Pointer, Route::List>;
|
||||
using Pointer = std::shared_ptr<Mapping>;
|
||||
|
||||
Mapping(const QString& name);
|
||||
Mapping(const QString& name) : name(name) {}
|
||||
|
||||
Map _channelMappings;
|
||||
Map channelMappings;
|
||||
|
||||
QString _name;
|
||||
|
||||
protected:
|
||||
QString name;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -12,17 +12,17 @@ namespace controller {
|
|||
|
||||
Pose::Pose(const vec3& translation, const quat& rotation,
|
||||
const vec3& velocity, const quat& angularVelocity) :
|
||||
_translation(translation), _rotation(rotation), _velocity(velocity), _angularVelocity(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) {
|
||||
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();
|
||||
return translation == right.getTranslation() && rotation == right.getRotation() &&
|
||||
velocity == right.getVelocity() && angularVelocity == right.getAngularVelocity();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@ namespace controller {
|
|||
|
||||
struct Pose {
|
||||
public:
|
||||
vec3 _translation;
|
||||
quat _rotation;
|
||||
vec3 _velocity;
|
||||
quat _angularVelocity;
|
||||
bool _valid{ false };
|
||||
vec3 translation;
|
||||
quat rotation;
|
||||
vec3 velocity;
|
||||
quat angularVelocity;
|
||||
bool valid{ false };
|
||||
|
||||
Pose() {}
|
||||
Pose(const vec3& translation, const quat& rotation,
|
||||
|
@ -30,11 +30,11 @@ namespace controller {
|
|||
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; }
|
||||
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; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -6,5 +6,4 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "Route.h"
|
||||
|
|
|
@ -16,20 +16,17 @@
|
|||
class QJsonObject;
|
||||
|
||||
namespace controller {
|
||||
|
||||
/*
|
||||
* encapsulates a source, destination and filters to apply
|
||||
*/
|
||||
class Route {
|
||||
public:
|
||||
Endpoint::Pointer _source;
|
||||
Endpoint::Pointer _destination;
|
||||
Filter::List _filters;
|
||||
Endpoint::Pointer source;
|
||||
Endpoint::Pointer destination;
|
||||
Filter::List filters;
|
||||
|
||||
using Pointer = std::shared_ptr<Route>;
|
||||
using List = std::list<Pointer>;
|
||||
|
||||
void parse(const QJsonObject);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
#include <QtCore/QRegularExpression>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QEventLoop>
|
||||
#include <QThread>
|
||||
|
||||
|
@ -26,475 +24,146 @@
|
|||
#include "Logging.h"
|
||||
#include "InputDevice.h"
|
||||
|
||||
static QRegularExpression SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" };
|
||||
|
||||
static QVariantMap createDeviceMap(const controller::DeviceProxy::Pointer device) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
QVariantMap deviceMap;
|
||||
for (const auto& inputMapping : device->getAvailabeInputs()) {
|
||||
const auto& input = inputMapping.first;
|
||||
const auto inputName = QString(inputMapping.second).remove(SANITIZE_NAME_EXPRESSION);
|
||||
qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType()
|
||||
<< QString::number(input.getID(), 16) << ": " << inputName;
|
||||
deviceMap.insert(inputName, input.getID());
|
||||
}
|
||||
return deviceMap;
|
||||
}
|
||||
|
||||
// FIXME this throws a hissy fit on MSVC if I put it in the main controller namespace block
|
||||
controller::ScriptingInterface::ScriptingInterface() {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
|
||||
// FIXME make this thread safe
|
||||
connect(userInputMapper.data(), &UserInputMapper::hardwareChanged, [=] {
|
||||
updateMaps();
|
||||
});
|
||||
|
||||
|
||||
qCDebug(controllers) << "Setting up standard controller abstraction";
|
||||
_standard = createDeviceMap(userInputMapper->getStandardDevice());
|
||||
|
||||
// FIXME allow custom user actions?
|
||||
auto actionNames = userInputMapper->getActionNames();
|
||||
int actionNumber = 0;
|
||||
qCDebug(controllers) << "Setting up standard actions";
|
||||
for (const auto& namedInput : userInputMapper->getActionInputs()) {
|
||||
const QString& actionName = namedInput.second;
|
||||
const Input& actionInput = namedInput.first;
|
||||
qCDebug(controllers) << "\tAction: " << actionName << " " << actionInput.getChannel();
|
||||
|
||||
// Expose the IDs to JS
|
||||
QString cleanActionName = QString(actionName).remove(SANITIZE_NAME_EXPRESSION);
|
||||
_actions.insert(cleanActionName, actionInput.getID());
|
||||
}
|
||||
|
||||
updateMaps();
|
||||
}
|
||||
|
||||
namespace controller {
|
||||
|
||||
class VirtualEndpoint : public Endpoint {
|
||||
public:
|
||||
VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT)
|
||||
: Endpoint(id) {
|
||||
}
|
||||
|
||||
virtual float value() override { return _currentValue; }
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; }
|
||||
|
||||
private:
|
||||
float _currentValue{ 0.0f };
|
||||
};
|
||||
|
||||
|
||||
class JSEndpoint : public Endpoint {
|
||||
public:
|
||||
JSEndpoint(const QJSValue& callable)
|
||||
: Endpoint(UserInputMapper::Input::INVALID_INPUT), _callable(callable) {}
|
||||
|
||||
virtual float value() {
|
||||
float result = (float)_callable.call().toNumber();;
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) {
|
||||
_callable.call(QJSValueList({ QJSValue(newValue) }));
|
||||
}
|
||||
|
||||
private:
|
||||
QJSValue _callable;
|
||||
};
|
||||
|
||||
float ScriptEndpoint::value() {
|
||||
updateValue();
|
||||
return _lastValue;
|
||||
}
|
||||
|
||||
void ScriptEndpoint::updateValue() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
_lastValue = (float)_callable.call().toNumber();
|
||||
}
|
||||
|
||||
void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
|
||||
internalApply(newValue, oldValue, source->getInput().getID());
|
||||
}
|
||||
|
||||
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));
|
||||
return;
|
||||
}
|
||||
_callable.call(QScriptValue(),
|
||||
QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) }));
|
||||
}
|
||||
|
||||
class CompositeEndpoint : public Endpoint, Endpoint::Pair {
|
||||
public:
|
||||
CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
|
||||
: Endpoint(UserInputMapper::Input(UserInputMapper::Input::INVALID_INPUT)), Pair(first, second) { }
|
||||
|
||||
virtual float value() {
|
||||
float result = first->value() * -1.0f + second->value();
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) {
|
||||
// Composites are read only
|
||||
}
|
||||
|
||||
private:
|
||||
Endpoint::Pointer _first;
|
||||
Endpoint::Pointer _second;
|
||||
};
|
||||
|
||||
class ActionEndpoint : public Endpoint {
|
||||
public:
|
||||
ActionEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT)
|
||||
: Endpoint(id) {
|
||||
}
|
||||
|
||||
virtual float value() override { return _currentValue; }
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override {
|
||||
|
||||
_currentValue += newValue;
|
||||
if (!(_input == UserInputMapper::Input::INVALID_INPUT)) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->deltaActionState(UserInputMapper::Action(_input.getChannel()), newValue);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
float _currentValue{ 0.0f };
|
||||
};
|
||||
|
||||
QRegularExpression ScriptingInterface::SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" };
|
||||
|
||||
QVariantMap createDeviceMap(const UserInputMapper::DeviceProxy* device) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
QVariantMap deviceMap;
|
||||
for (const auto& inputMapping : device->getAvailabeInputs()) {
|
||||
const auto& input = inputMapping.first;
|
||||
const auto inputName = QString(inputMapping.second).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
|
||||
qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType()
|
||||
<< QString::number(input.getID(), 16) << ": " << inputName;
|
||||
deviceMap.insert(inputName, input.getID());
|
||||
}
|
||||
return deviceMap;
|
||||
}
|
||||
|
||||
|
||||
ScriptingInterface::~ScriptingInterface() {
|
||||
}
|
||||
|
||||
QObject* ScriptingInterface::newMapping(const QString& mappingName) {
|
||||
if (_mappingsByName.count(mappingName)) {
|
||||
qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
|
||||
}
|
||||
qDebug() << "Creating new Mapping " << mappingName;
|
||||
auto mapping = std::make_shared<Mapping>(mappingName);
|
||||
_mappingsByName[mappingName] = mapping;
|
||||
return new MappingBuilderProxy(*this, mapping);
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
return new MappingBuilderProxy(*userInputMapper, userInputMapper->newMapping(mappingName));
|
||||
}
|
||||
|
||||
QObject* ScriptingInterface::parseMapping(const QString& json) {
|
||||
|
||||
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();
|
||||
|
||||
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 nullptr;
|
||||
}
|
||||
|
||||
QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) {
|
||||
QObject* result = nullptr;
|
||||
auto request = ResourceManager::createResourceRequest(nullptr, QUrl(jsonUrl));
|
||||
if (request) {
|
||||
QEventLoop eventLoop;
|
||||
request->setCacheEnabled(false);
|
||||
connect(request, &ResourceRequest::finished, &eventLoop, &QEventLoop::quit);
|
||||
request->send();
|
||||
if (request->getState() != ResourceRequest::Finished) {
|
||||
eventLoop.exec();
|
||||
}
|
||||
|
||||
if (request->getResult() == ResourceRequest::Success) {
|
||||
result = parseMapping(QString(request->getData()));
|
||||
} else {
|
||||
qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl;
|
||||
}
|
||||
request->deleteLater();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Q_INVOKABLE QObject* newMapping(const QJsonObject& json);
|
||||
|
||||
void ScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
|
||||
qCDebug(controllers) << "Attempting to enable mapping " << mappingName;
|
||||
auto iterator = _mappingsByName.find(mappingName);
|
||||
if (_mappingsByName.end() == iterator) {
|
||||
qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName;
|
||||
return;
|
||||
}
|
||||
|
||||
auto mapping = iterator->second;
|
||||
if (enable) {
|
||||
_activeMappings.push_front(mapping);
|
||||
} else {
|
||||
auto activeIterator = std::find(_activeMappings.begin(), _activeMappings.end(), mapping);
|
||||
if (_activeMappings.end() == activeIterator) {
|
||||
qCWarning(controllers) << "Attempted to disable inactive mapping " << mappingName;
|
||||
return;
|
||||
}
|
||||
_activeMappings.erase(activeIterator);
|
||||
}
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->enableMapping(mappingName, enable);
|
||||
}
|
||||
|
||||
float ScriptingInterface::getValue(const int& source) const {
|
||||
// return (sin(secTimestampNow()) + 1.0f) / 2.0f;
|
||||
UserInputMapper::Input input(source);
|
||||
auto iterator = _endpoints.find(input);
|
||||
if (_endpoints.end() == iterator) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
const auto& endpoint = iterator->second;
|
||||
return getValue(endpoint);
|
||||
}
|
||||
|
||||
float ScriptingInterface::getValue(const Endpoint::Pointer& endpoint) const {
|
||||
auto valuesIterator = _overrideValues.find(endpoint);
|
||||
if (_overrideValues.end() != valuesIterator) {
|
||||
return valuesIterator->second;
|
||||
}
|
||||
|
||||
return endpoint->value();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
return userInputMapper->getValue(Input((uint32_t)source));
|
||||
}
|
||||
|
||||
float ScriptingInterface::getButtonValue(StandardButtonChannel source, uint16_t device) const {
|
||||
return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::BUTTON).getID());
|
||||
return getValue(Input(device, source, ChannelType::BUTTON).getID());
|
||||
}
|
||||
|
||||
float ScriptingInterface::getAxisValue(StandardAxisChannel source, uint16_t device) const {
|
||||
return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID());
|
||||
return getValue(Input(device, source, ChannelType::AXIS).getID());
|
||||
}
|
||||
|
||||
Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
|
||||
return Pose();
|
||||
}
|
||||
|
||||
void ScriptingInterface::update() {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
static auto deviceNames = userInputMapper->getDeviceNames();
|
||||
//bool ScriptingInterface::isPrimaryButtonPressed() const {
|
||||
// return isButtonPressed(StandardButtonChannel::A);
|
||||
//}
|
||||
//
|
||||
//glm::vec2 ScriptingInterface::getPrimaryJoystickPosition() const {
|
||||
// return getJoystickPosition(0);
|
||||
//}
|
||||
|
||||
if (deviceNames != userInputMapper->getDeviceNames()) {
|
||||
updateMaps();
|
||||
deviceNames = userInputMapper->getDeviceNames();
|
||||
}
|
||||
//int ScriptingInterface::getNumberOfButtons() const {
|
||||
// return StandardButtonChannel::NUM_STANDARD_BUTTONS;
|
||||
//}
|
||||
|
||||
_overrideValues.clear();
|
||||
EndpointSet readEndpoints;
|
||||
EndpointSet writtenEndpoints;
|
||||
// Now process the current values for each level of the stack
|
||||
for (auto& mapping : _activeMappings) {
|
||||
for (const auto& mappingEntry : mapping->_channelMappings) {
|
||||
const auto& source = mappingEntry.first;
|
||||
//bool ScriptingInterface::isButtonPressed(int buttonIndex) const {
|
||||
// return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0 ? false : true;
|
||||
//}
|
||||
|
||||
// Endpoints can only be read once (though a given mapping can route them to
|
||||
// multiple places). Consider... If the default is to wire the A button to JUMP
|
||||
// and someone else wires it to CONTEXT_MENU, I don't want both to occur when
|
||||
// I press the button. The exception is if I'm wiring a control back to itself
|
||||
// in order to adjust my interface, like inverting the Y axis on an analog stick
|
||||
if (readEndpoints.count(source)) {
|
||||
continue;
|
||||
}
|
||||
//int ScriptingInterface::getNumberOfTriggers() const {
|
||||
// return StandardCounts::TRIGGERS;
|
||||
//}
|
||||
|
||||
// Apply the value to all the routes
|
||||
const auto& routes = mappingEntry.second;
|
||||
//float ScriptingInterface::getTriggerValue(int triggerIndex) const {
|
||||
// return getAxisValue(triggerIndex == 0 ? StandardAxisChannel::LT : StandardAxisChannel::RT);
|
||||
//}
|
||||
|
||||
for (const auto& route : routes) {
|
||||
const auto& destination = route->_destination;
|
||||
// THis could happen if the route destination failed to create
|
||||
// FIXME: Maybe do not create the route if the destination failed and avoid this case ?
|
||||
if (!source || !destination) {
|
||||
continue;
|
||||
}
|
||||
//int ScriptingInterface::getNumberOfJoysticks() const {
|
||||
// return StandardCounts::ANALOG_STICKS;
|
||||
//}
|
||||
|
||||
if (writtenEndpoints.count(destination)) {
|
||||
continue;
|
||||
}
|
||||
//glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const {
|
||||
// StandardAxisChannel xid = StandardAxisChannel::LX;
|
||||
// StandardAxisChannel yid = StandardAxisChannel::LY;
|
||||
// if (joystickIndex != 0) {
|
||||
// xid = StandardAxisChannel::RX;
|
||||
// yid = StandardAxisChannel::RY;
|
||||
// }
|
||||
// vec2 result;
|
||||
// result.x = getAxisValue(xid);
|
||||
// result.y = getAxisValue(yid);
|
||||
// return result;
|
||||
//}
|
||||
|
||||
// Standard controller destinations can only be can only be used once.
|
||||
if (userInputMapper->getStandardDeviceID() == destination->getInput().getDevice()) {
|
||||
writtenEndpoints.insert(destination);
|
||||
}
|
||||
//int ScriptingInterface::getNumberOfSpatialControls() const {
|
||||
// return StandardCounts::POSES;
|
||||
//}
|
||||
|
||||
// Only consume the input if the route isn't a loopback.
|
||||
// This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
|
||||
bool loopback = source == destination;
|
||||
if (!loopback) {
|
||||
readEndpoints.insert(source);
|
||||
}
|
||||
//glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const {
|
||||
// // FIXME extract the position from the standard pose
|
||||
// return vec3();
|
||||
//}
|
||||
|
||||
// Fetch the value, may have been overriden by previous loopback routes
|
||||
float value = getValue(source);
|
||||
//glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
|
||||
// // FIXME extract the velocity from the standard pose
|
||||
// return vec3();
|
||||
//}
|
||||
|
||||
// Apply each of the filters.
|
||||
for (const auto& filter : route->_filters) {
|
||||
value = filter->apply(value);
|
||||
}
|
||||
//glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const {
|
||||
// // FIXME extract the normal from the standard pose
|
||||
// return vec3();
|
||||
//}
|
||||
//
|
||||
//glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
|
||||
// // FIXME extract the rotation from the standard pose
|
||||
// return quat();
|
||||
//}
|
||||
|
||||
if (loopback) {
|
||||
_overrideValues[source] = value;
|
||||
} else {
|
||||
destination->apply(value, 0, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Endpoint::Pointer ScriptingInterface::endpointFor(const QJSValue& endpoint) {
|
||||
if (endpoint.isNumber()) {
|
||||
return endpointFor(UserInputMapper::Input(endpoint.toInt()));
|
||||
}
|
||||
|
||||
if (endpoint.isCallable()) {
|
||||
auto result = std::make_shared<JSEndpoint>(endpoint);
|
||||
return result;
|
||||
}
|
||||
|
||||
qWarning() << "Unsupported input type " << endpoint.toString();
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
|
||||
Endpoint::Pointer ScriptingInterface::endpointFor(const QScriptValue& endpoint) {
|
||||
if (endpoint.isNumber()) {
|
||||
return endpointFor(UserInputMapper::Input(endpoint.toInt32()));
|
||||
}
|
||||
|
||||
if (endpoint.isFunction()) {
|
||||
auto result = std::make_shared<ScriptEndpoint>(endpoint);
|
||||
return result;
|
||||
}
|
||||
|
||||
qWarning() << "Unsupported input type " << endpoint.toString();
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
|
||||
UserInputMapper::Input ScriptingInterface::inputFor(const QString& inputName) {
|
||||
return DependencyManager::get<UserInputMapper>()->findDeviceInput(inputName);
|
||||
}
|
||||
|
||||
Endpoint::Pointer ScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) {
|
||||
auto iterator = _endpoints.find(inputId);
|
||||
if (_endpoints.end() == iterator) {
|
||||
qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
Endpoint::Pointer ScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) {
|
||||
EndpointPair pair(first, second);
|
||||
Endpoint::Pointer result;
|
||||
auto iterator = _compositeEndpoints.find(pair);
|
||||
if (_compositeEndpoints.end() == iterator) {
|
||||
result = std::make_shared<CompositeEndpoint>(first, second);
|
||||
_compositeEndpoints[pair] = result;
|
||||
} else {
|
||||
result = iterator->second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ScriptingInterface::isPrimaryButtonPressed() const {
|
||||
return isButtonPressed(StandardButtonChannel::A);
|
||||
}
|
||||
|
||||
glm::vec2 ScriptingInterface::getPrimaryJoystickPosition() const {
|
||||
return getJoystickPosition(0);
|
||||
}
|
||||
|
||||
int ScriptingInterface::getNumberOfButtons() const {
|
||||
return StandardButtonChannel::NUM_STANDARD_BUTTONS;
|
||||
}
|
||||
|
||||
bool ScriptingInterface::isButtonPressed(int buttonIndex) const {
|
||||
return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0f ? false : true;
|
||||
}
|
||||
|
||||
int ScriptingInterface::getNumberOfTriggers() const {
|
||||
return StandardCounts::TRIGGERS;
|
||||
}
|
||||
|
||||
float ScriptingInterface::getTriggerValue(int triggerIndex) const {
|
||||
return getAxisValue(triggerIndex == 0 ? StandardAxisChannel::LT : StandardAxisChannel::RT);
|
||||
}
|
||||
|
||||
int ScriptingInterface::getNumberOfJoysticks() const {
|
||||
return StandardCounts::ANALOG_STICKS;
|
||||
}
|
||||
|
||||
glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const {
|
||||
StandardAxisChannel xid = StandardAxisChannel::LX;
|
||||
StandardAxisChannel yid = StandardAxisChannel::LY;
|
||||
if (joystickIndex != 0) {
|
||||
xid = StandardAxisChannel::RX;
|
||||
yid = StandardAxisChannel::RY;
|
||||
}
|
||||
vec2 result;
|
||||
result.x = getAxisValue(xid);
|
||||
result.y = getAxisValue(yid);
|
||||
return result;
|
||||
}
|
||||
|
||||
int ScriptingInterface::getNumberOfSpatialControls() const {
|
||||
return StandardCounts::POSES;
|
||||
}
|
||||
|
||||
glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const {
|
||||
// FIXME extract the position from the standard pose
|
||||
return vec3();
|
||||
}
|
||||
|
||||
glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
|
||||
// FIXME extract the velocity from the standard pose
|
||||
return vec3();
|
||||
}
|
||||
|
||||
glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const {
|
||||
// FIXME extract the normal from the standard pose
|
||||
return vec3();
|
||||
}
|
||||
|
||||
glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
|
||||
// FIXME extract the rotation from the standard pose
|
||||
return quat();
|
||||
}
|
||||
|
||||
void ScriptingInterface::updateMaps() {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto devices = userInputMapper->getDevices();
|
||||
QSet<QString> foundDevices;
|
||||
for (const auto& deviceMapping : devices) {
|
||||
auto deviceID = deviceMapping.first;
|
||||
if (deviceID != userInputMapper->getStandardDeviceID()) {
|
||||
auto device = deviceMapping.second.get();
|
||||
auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
|
||||
qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
|
||||
foundDevices.insert(device->getName());
|
||||
if (_hardware.contains(deviceName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Expose the IDs to JS
|
||||
_hardware.insert(deviceName, createDeviceMap(device));
|
||||
|
||||
// Create the endpoints
|
||||
for (const auto& inputMapping : device->getAvailabeInputs()) {
|
||||
const auto& input = inputMapping.first;
|
||||
// Ignore aliases
|
||||
if (_endpoints.count(input)) {
|
||||
continue;
|
||||
}
|
||||
_endpoints[input] = std::make_shared<LambdaEndpoint>([=] {
|
||||
auto deviceProxy = userInputMapper->getDeviceProxy(input);
|
||||
if (!deviceProxy) {
|
||||
return 0.0f;
|
||||
}
|
||||
return deviceProxy->getValue(input, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::Action> ScriptingInterface::getAllActions() {
|
||||
QVector<Action> ScriptingInterface::getAllActions() {
|
||||
return DependencyManager::get<UserInputMapper>()->getAllActions();
|
||||
}
|
||||
|
||||
|
@ -502,7 +171,7 @@ namespace controller {
|
|||
return DependencyManager::get<UserInputMapper>()->getDeviceName((unsigned short)device);
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputPair> ScriptingInterface::getAvailableInputs(unsigned int device) {
|
||||
QVector<InputPair> ScriptingInterface::getAvailableInputs(unsigned int device) {
|
||||
return DependencyManager::get<UserInputMapper>()->getAvailableInputs((unsigned short)device);
|
||||
}
|
||||
|
||||
|
@ -515,7 +184,7 @@ namespace controller {
|
|||
}
|
||||
|
||||
float ScriptingInterface::getActionValue(int action) {
|
||||
return DependencyManager::get<UserInputMapper>()->getActionState(UserInputMapper::Action(action));
|
||||
return DependencyManager::get<UserInputMapper>()->getActionState(Action(action));
|
||||
}
|
||||
|
||||
int ScriptingInterface::findAction(QString actionName) {
|
||||
|
@ -526,41 +195,40 @@ namespace controller {
|
|||
return DependencyManager::get<UserInputMapper>()->getActionNames();
|
||||
}
|
||||
|
||||
void ScriptingInterface::updateMaps() {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
auto devices = userInputMapper->getDevices();
|
||||
QSet<QString> foundDevices;
|
||||
for (const auto& deviceMapping : devices) {
|
||||
auto deviceID = deviceMapping.first;
|
||||
if (deviceID != userInputMapper->getStandardDeviceID()) {
|
||||
auto device = deviceMapping.second;
|
||||
auto deviceName = QString(device->getName()).remove(SANITIZE_NAME_EXPRESSION);
|
||||
qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
|
||||
foundDevices.insert(device->getName());
|
||||
if (_hardware.contains(deviceName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Expose the IDs to JS
|
||||
_hardware.insert(deviceName, createDeviceMap(device));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QObject* ScriptingInterface::parseMapping(const QString& json) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto mapping = userInputMapper->parseMapping(json);
|
||||
return new MappingBuilderProxy(*userInputMapper, mapping);
|
||||
}
|
||||
|
||||
QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
} // namespace controllers
|
||||
|
||||
|
||||
using namespace controller;
|
||||
// FIXME this throws a hissy fit on MSVC if I put it in the main controller namespace block
|
||||
ScriptingInterface::ScriptingInterface() {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
qCDebug(controllers) << "Setting up standard controller abstraction";
|
||||
auto standardDevice = userInputMapper->getStandardDevice();
|
||||
// Expose the IDs to JS
|
||||
_standard = createDeviceMap(standardDevice.get());
|
||||
// Create the endpoints
|
||||
for (const auto& inputMapping : standardDevice->getAvailabeInputs()) {
|
||||
const auto& standardInput = inputMapping.first;
|
||||
// Ignore aliases
|
||||
if (_endpoints.count(standardInput)) {
|
||||
continue;
|
||||
}
|
||||
_endpoints[standardInput] = std::make_shared<VirtualEndpoint>(standardInput);
|
||||
}
|
||||
|
||||
// FIXME allow custom user actions?
|
||||
auto actionNames = userInputMapper->getActionNames();
|
||||
int actionNumber = 0;
|
||||
qCDebug(controllers) << "Setting up standard actions";
|
||||
for (const auto& actionName : actionNames) {
|
||||
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);
|
||||
_actions.insert(cleanActionName, actionInput.getID());
|
||||
|
||||
// Create the action endpoints
|
||||
_endpoints[actionInput] = std::make_shared<ActionEndpoint>(actionInput);
|
||||
}
|
||||
|
||||
updateMaps();
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
#include "UserInputMapper.h"
|
||||
#include "StandardControls.h"
|
||||
#include "Mapping.h"
|
||||
|
||||
namespace controller {
|
||||
class InputController : public QObject {
|
||||
|
@ -65,10 +64,10 @@ namespace controller {
|
|||
|
||||
public:
|
||||
ScriptingInterface();
|
||||
virtual ~ScriptingInterface();
|
||||
virtual ~ScriptingInterface() {};
|
||||
|
||||
Q_INVOKABLE QVector<UserInputMapper::Action> getAllActions();
|
||||
Q_INVOKABLE QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
|
||||
Q_INVOKABLE QVector<Action> getAllActions();
|
||||
Q_INVOKABLE QVector<Input::NamedPair> getAvailableInputs(unsigned int device);
|
||||
Q_INVOKABLE QString getDeviceName(unsigned int device);
|
||||
Q_INVOKABLE float getActionValue(int action);
|
||||
Q_INVOKABLE int findDevice(QString name);
|
||||
|
@ -87,23 +86,23 @@ namespace controller {
|
|||
Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl);
|
||||
|
||||
|
||||
Q_INVOKABLE bool isPrimaryButtonPressed() const;
|
||||
Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const;
|
||||
//Q_INVOKABLE bool isPrimaryButtonPressed() const;
|
||||
//Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const;
|
||||
|
||||
Q_INVOKABLE int getNumberOfButtons() const;
|
||||
Q_INVOKABLE bool isButtonPressed(int buttonIndex) const;
|
||||
//Q_INVOKABLE int getNumberOfButtons() const;
|
||||
//Q_INVOKABLE bool isButtonPressed(int buttonIndex) const;
|
||||
|
||||
Q_INVOKABLE int getNumberOfTriggers() const;
|
||||
Q_INVOKABLE float getTriggerValue(int triggerIndex) const;
|
||||
//Q_INVOKABLE int getNumberOfTriggers() const;
|
||||
//Q_INVOKABLE float getTriggerValue(int triggerIndex) const;
|
||||
|
||||
Q_INVOKABLE int getNumberOfJoysticks() const;
|
||||
Q_INVOKABLE glm::vec2 getJoystickPosition(int joystickIndex) const;
|
||||
//Q_INVOKABLE int getNumberOfJoysticks() const;
|
||||
//Q_INVOKABLE glm::vec2 getJoystickPosition(int joystickIndex) const;
|
||||
|
||||
Q_INVOKABLE int getNumberOfSpatialControls() const;
|
||||
Q_INVOKABLE glm::vec3 getSpatialControlPosition(int controlIndex) const;
|
||||
Q_INVOKABLE glm::vec3 getSpatialControlVelocity(int controlIndex) const;
|
||||
Q_INVOKABLE glm::vec3 getSpatialControlNormal(int controlIndex) const;
|
||||
Q_INVOKABLE glm::quat getSpatialControlRawRotation(int controlIndex) const;
|
||||
//Q_INVOKABLE int getNumberOfSpatialControls() const;
|
||||
//Q_INVOKABLE glm::vec3 getSpatialControlPosition(int controlIndex) const;
|
||||
//Q_INVOKABLE glm::vec3 getSpatialControlVelocity(int controlIndex) const;
|
||||
//Q_INVOKABLE glm::vec3 getSpatialControlNormal(int controlIndex) const;
|
||||
//Q_INVOKABLE glm::quat getSpatialControlRawRotation(int controlIndex) const;
|
||||
|
||||
Q_INVOKABLE const QVariantMap& getHardware() { return _hardware; }
|
||||
Q_INVOKABLE const QVariantMap& getActions() { return _actions; }
|
||||
|
@ -114,11 +113,7 @@ namespace controller {
|
|||
bool isWheelCaptured() const { return _wheelCaptured; }
|
||||
bool areActionsCaptured() const { return _actionsCaptured; }
|
||||
|
||||
static QRegularExpression SANITIZE_NAME_EXPRESSION;
|
||||
|
||||
public slots:
|
||||
virtual void update();
|
||||
virtual void updateMaps();
|
||||
|
||||
virtual void captureMouseEvents() { _mouseCaptured = true; }
|
||||
virtual void releaseMouseEvents() { _mouseCaptured = false; }
|
||||
|
@ -134,61 +129,19 @@ namespace controller {
|
|||
|
||||
|
||||
private:
|
||||
friend class MappingBuilderProxy;
|
||||
friend class RouteBuilderProxy;
|
||||
|
||||
// FIXME move to unordered set / map
|
||||
using MappingMap = std::map<QString, Mapping::Pointer>;
|
||||
using MappingStack = std::list<Mapping::Pointer>;
|
||||
using InputToEndpointMap = std::map<UserInputMapper::Input, Endpoint::Pointer>;
|
||||
using EndpointSet = std::unordered_set<Endpoint::Pointer>;
|
||||
using ValueMap = std::map<Endpoint::Pointer, float>;
|
||||
using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
|
||||
using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
|
||||
|
||||
void update(Mapping::Pointer& mapping, EndpointSet& consumed);
|
||||
float getValue(const Endpoint::Pointer& endpoint) const;
|
||||
Endpoint::Pointer endpointFor(const QJSValue& endpoint);
|
||||
Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
|
||||
Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint);
|
||||
Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
|
||||
|
||||
UserInputMapper::Input inputFor(const QString& inputName);
|
||||
// Update the exposed variant maps reporting active hardware
|
||||
void updateMaps();
|
||||
|
||||
QVariantMap _hardware;
|
||||
QVariantMap _actions;
|
||||
QVariantMap _standard;
|
||||
|
||||
InputToEndpointMap _endpoints;
|
||||
EndpointPairMap _compositeEndpoints;
|
||||
|
||||
ValueMap _overrideValues;
|
||||
MappingMap _mappingsByName;
|
||||
MappingStack _activeMappings;
|
||||
|
||||
bool _mouseCaptured{ false };
|
||||
bool _touchCaptured{ false };
|
||||
bool _wheelCaptured{ false };
|
||||
bool _actionsCaptured{ false };
|
||||
};
|
||||
|
||||
class ScriptEndpoint : public Endpoint {
|
||||
Q_OBJECT;
|
||||
public:
|
||||
ScriptEndpoint(const QScriptValue& callable)
|
||||
: Endpoint(UserInputMapper::Input::INVALID_INPUT), _callable(callable) {
|
||||
}
|
||||
|
||||
virtual float value();
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source);
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void updateValue();
|
||||
Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID);
|
||||
private:
|
||||
QScriptValue _callable;
|
||||
float _lastValue = 0.0f;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,21 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "StandardController.h"
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "DeviceProxy.h"
|
||||
#include "UserInputMapper.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
const float CONTROLLER_THRESHOLD = 0.3f;
|
||||
|
||||
StandardController::StandardController() : InputDevice("Standard") {
|
||||
_deviceID = UserInputMapper::STANDARD_DEVICE;
|
||||
}
|
||||
|
||||
StandardController::~StandardController() {
|
||||
}
|
||||
|
||||
|
@ -26,143 +35,111 @@ void StandardController::focusOutEvent() {
|
|||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||
// Grab the current free device ID
|
||||
_deviceID = mapper.getStandardDeviceID();
|
||||
|
||||
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;
|
||||
void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) {
|
||||
proxy->_name = _name;
|
||||
proxy->getButton = [this] (const Input& input, int timestamp) -> bool { return getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this] (const Input& input, int timestamp) -> float { return getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this] () -> QVector<Input::NamedPair> {
|
||||
QVector<Input::NamedPair> 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"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::A), "A"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::B), "B"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::X), "X"));
|
||||
availableInputs.append(Input::NamedPair(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"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::DU), "DU"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::DD), "DD"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::DL), "DL"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::DR), "DR"));
|
||||
|
||||
// Bumpers
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::LB), "LB"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::RB), "RB"));
|
||||
|
||||
// Stick press
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::LS), "LS"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::RS), "RS"));
|
||||
|
||||
// Center buttons
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::START), "Start"));
|
||||
availableInputs.append(Input::NamedPair(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"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::LY), "LY"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::LX), "LX"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::RY), "RY"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::RX), "RX"));
|
||||
|
||||
// Triggers
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::LT), "LT"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::RT), "RT"));
|
||||
|
||||
// Poses
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT), "LeftPose"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT), "RightPose"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::LEFT), "LeftPose"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::RIGHT), "RightPose"));
|
||||
|
||||
// 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"));
|
||||
|
||||
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::LB), "L1"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::RB), "R1"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::LT), "L2"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::RT), "R2"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::LS), "L3"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::RS), "R3"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::BACK), "Select"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::A), "Cross"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::B), "Circle"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::X), "Square"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::Y), "Triangle"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::DU), "Up"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::DD), "Down"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::DL), "Left"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(controller::DR), "Right"));
|
||||
return availableInputs;
|
||||
};
|
||||
|
||||
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));
|
||||
QString StandardController::getDefaultMappingConfig() {
|
||||
static const QString DEFAULT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard.json";
|
||||
return DEFAULT_MAPPING_JSON;
|
||||
}
|
||||
|
||||
UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) {
|
||||
return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
|
||||
}
|
||||
// FIXME figure out how to move the shifted version to JSON
|
||||
//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;
|
||||
//
|
||||
// // 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::StandardAxisChannel axis) {
|
||||
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
UserInputMapper::Input StandardController::makeInput(controller::StandardPoseChannel pose) {
|
||||
return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
|
||||
}
|
||||
|
|
|
@ -12,37 +12,31 @@
|
|||
#ifndef hifi_StandardController_h
|
||||
#define hifi_StandardController_h
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qvector.h>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include "InputDevice.h"
|
||||
|
||||
#include "StandardControls.h"
|
||||
|
||||
typedef std::shared_ptr<StandardController> StandardControllerPointer;
|
||||
namespace controller {
|
||||
|
||||
class StandardController : public QObject, public InputDevice {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ getName)
|
||||
|
||||
public:
|
||||
|
||||
const QString& getName() const { return _name; }
|
||||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override;
|
||||
virtual QString getDefaultMappingConfig() override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
StandardController() : InputDevice("Standard") {}
|
||||
~StandardController();
|
||||
|
||||
UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
|
||||
UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
|
||||
UserInputMapper::Input makeInput(controller::StandardPoseChannel pose);
|
||||
|
||||
private:
|
||||
StandardController();
|
||||
virtual ~StandardController();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // hifi_StandardController_h
|
||||
|
|
|
@ -7,20 +7,156 @@
|
|||
//
|
||||
|
||||
#include "UserInputMapper.h"
|
||||
#include "StandardController.h"
|
||||
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QJsonArray>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "StandardController.h"
|
||||
#include "Logging.h"
|
||||
|
||||
const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - (uint16)1;
|
||||
const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
|
||||
namespace controller {
|
||||
const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
|
||||
const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
|
||||
}
|
||||
|
||||
// Default contruct allocate the poutput size with the current hardcoded action channels
|
||||
UserInputMapper::UserInputMapper() {
|
||||
registerStandardDevice();
|
||||
controller::UserInputMapper::UserInputMapper() {
|
||||
_activeMappings.push_back(_defaultMapping);
|
||||
_standardController = std::make_shared<StandardController>();
|
||||
registerDevice(new ActionsDevice());
|
||||
registerDevice(_standardController.get());
|
||||
assignDefaulActionScales();
|
||||
createActionNames();
|
||||
}
|
||||
|
||||
namespace controller {
|
||||
|
||||
class ScriptEndpoint : public Endpoint {
|
||||
Q_OBJECT;
|
||||
public:
|
||||
ScriptEndpoint(const QScriptValue& callable)
|
||||
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
|
||||
}
|
||||
|
||||
virtual float value();
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source);
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void updateValue();
|
||||
Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID);
|
||||
private:
|
||||
QScriptValue _callable;
|
||||
float _lastValue = 0.0f;
|
||||
};
|
||||
|
||||
class VirtualEndpoint : public Endpoint {
|
||||
public:
|
||||
VirtualEndpoint(const Input& id = Input::INVALID_INPUT)
|
||||
: Endpoint(id) {
|
||||
}
|
||||
|
||||
virtual float value() override { return _currentValue; }
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; }
|
||||
|
||||
private:
|
||||
float _currentValue{ 0.0f };
|
||||
};
|
||||
|
||||
|
||||
class JSEndpoint : public Endpoint {
|
||||
public:
|
||||
JSEndpoint(const QJSValue& callable)
|
||||
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
|
||||
}
|
||||
|
||||
virtual float value() {
|
||||
float result = (float)_callable.call().toNumber();;
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) {
|
||||
_callable.call(QJSValueList({ QJSValue(newValue) }));
|
||||
}
|
||||
|
||||
private:
|
||||
QJSValue _callable;
|
||||
};
|
||||
|
||||
float ScriptEndpoint::value() {
|
||||
updateValue();
|
||||
return _lastValue;
|
||||
}
|
||||
|
||||
void ScriptEndpoint::updateValue() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
_lastValue = (float)_callable.call().toNumber();
|
||||
}
|
||||
|
||||
void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
|
||||
internalApply(newValue, oldValue, source->getInput().getID());
|
||||
}
|
||||
|
||||
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));
|
||||
return;
|
||||
}
|
||||
_callable.call(QScriptValue(),
|
||||
QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) }));
|
||||
}
|
||||
|
||||
class CompositeEndpoint : public Endpoint, Endpoint::Pair {
|
||||
public:
|
||||
CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
|
||||
: Endpoint(Input(Input::INVALID_INPUT)), Pair(first, second) { }
|
||||
|
||||
virtual float value() {
|
||||
float result = first->value() * -1.0f + second->value();
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) {
|
||||
// Composites are read only
|
||||
}
|
||||
|
||||
private:
|
||||
Endpoint::Pointer _first;
|
||||
Endpoint::Pointer _second;
|
||||
};
|
||||
|
||||
class ActionEndpoint : public Endpoint {
|
||||
public:
|
||||
ActionEndpoint(const Input& id = Input::INVALID_INPUT)
|
||||
: Endpoint(id) {
|
||||
}
|
||||
|
||||
virtual float value() override { return _currentValue; }
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override {
|
||||
|
||||
_currentValue += newValue;
|
||||
if (!(_input == Input::INVALID_INPUT)) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
float _currentValue{ 0.0f };
|
||||
};
|
||||
|
||||
|
||||
UserInputMapper::~UserInputMapper() {
|
||||
}
|
||||
|
||||
|
@ -32,28 +168,58 @@ int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
|
|||
return _deviceCounts[deviceName];
|
||||
}
|
||||
|
||||
bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) {
|
||||
void UserInputMapper::registerDevice(InputDevice* device) {
|
||||
if (device->_deviceID == Input::INVALID_DEVICE) {
|
||||
device->_deviceID = getFreeDeviceID();
|
||||
}
|
||||
const auto& deviceID = device->_deviceID;
|
||||
DeviceProxy::Pointer proxy = std::make_shared<DeviceProxy>();
|
||||
proxy->_name = device->_name;
|
||||
device->buildDeviceProxy(proxy);
|
||||
|
||||
int numberOfType = recordDeviceOfType(proxy->_name);
|
||||
|
||||
if (numberOfType > 1) {
|
||||
proxy->_name += QString::number(numberOfType);
|
||||
}
|
||||
|
||||
|
||||
qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID;
|
||||
|
||||
for (const auto& inputMapping : proxy->getAvailabeInputs()) {
|
||||
const auto& input = inputMapping.first;
|
||||
// Ignore aliases
|
||||
if (_endpointsByInput.count(input)) {
|
||||
continue;
|
||||
}
|
||||
Endpoint::Pointer endpoint;
|
||||
if (input.device == STANDARD_DEVICE) {
|
||||
endpoint = std::make_shared<VirtualEndpoint>(input);
|
||||
} else if (input.device == ACTIONS_DEVICE) {
|
||||
endpoint = std::make_shared<ActionEndpoint>(input);
|
||||
} else {
|
||||
endpoint = std::make_shared<LambdaEndpoint>([=] {
|
||||
return proxy->getValue(input, 0);
|
||||
});
|
||||
}
|
||||
_inputsByEndpoint[endpoint] = input;
|
||||
_endpointsByInput[input] = endpoint;
|
||||
}
|
||||
|
||||
_registeredDevices[deviceID] = proxy;
|
||||
return true;
|
||||
|
||||
auto mapping = loadMapping(device->getDefaultMappingConfig());
|
||||
if (mapping) {
|
||||
_mappingsByDevice[deviceID] = mapping;
|
||||
for (const auto& entry : mapping->channelMappings) {
|
||||
const auto& source = entry.first;
|
||||
const auto& routes = entry.second;
|
||||
auto& list = _defaultMapping->channelMappings[source];
|
||||
list.insert(list.end(), routes.begin(), routes.end());
|
||||
}
|
||||
}
|
||||
|
||||
emit hardwareChanged();
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
|
||||
auto device = _registeredDevices.find(input.getDevice());
|
||||
if (device != _registeredDevices.end()) {
|
||||
return (device->second);
|
||||
|
@ -69,25 +235,9 @@ QString UserInputMapper::getDeviceName(uint16 deviceID) {
|
|||
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) {
|
||||
if (device.second->_name == name) {
|
||||
return device.first;
|
||||
}
|
||||
}
|
||||
|
@ -103,8 +253,11 @@ QVector<QString> UserInputMapper::getDeviceNames() {
|
|||
return result;
|
||||
}
|
||||
|
||||
UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const {
|
||||
|
||||
int UserInputMapper::findAction(const QString& actionName) const {
|
||||
return findDeviceInput("Actions." + actionName).getChannel();
|
||||
}
|
||||
|
||||
Input UserInputMapper::findDeviceInput(const QString& inputName) const {
|
||||
// Split the full input name as such: deviceName.inputName
|
||||
auto names = inputName.split('.');
|
||||
|
||||
|
@ -126,20 +279,9 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName
|
|||
|
||||
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 << ">";
|
||||
findDevice(deviceName);
|
||||
}
|
||||
} else {
|
||||
qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName";
|
||||
|
@ -148,100 +290,11 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME remove the associated device mappings
|
||||
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;
|
||||
|
@ -249,64 +302,17 @@ void fixBisectedAxis(float& full, float& negative, float& positive) {
|
|||
}
|
||||
|
||||
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();
|
||||
channel = Pose();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
// Run the mappings code
|
||||
update();
|
||||
|
||||
// Scale all the channel step with the scale
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
|
@ -337,7 +343,12 @@ void UserInputMapper::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
|
||||
Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const {
|
||||
auto iterator = _registeredDevices.find(deviceID);
|
||||
return iterator->second->getAvailabeInputs();
|
||||
}
|
||||
|
||||
QVector<Action> UserInputMapper::getAllActions() const {
|
||||
QVector<Action> actions;
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
actions.append(Action(i));
|
||||
|
@ -345,31 +356,20 @@ QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
|
|||
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;
|
||||
QString UserInputMapper::getActionName(Action action) const {
|
||||
for (auto actionPair : getActionInputs()) {
|
||||
if (actionPair.first.channel == action) {
|
||||
return actionPair.second;
|
||||
}
|
||||
}
|
||||
// If the action isn't found, return -1
|
||||
return -1;
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
QVector<QString> UserInputMapper::getActionNames() const {
|
||||
QVector<QString> result;
|
||||
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||
result << _actionNames[i];
|
||||
for (auto actionPair : getActionInputs()) {
|
||||
result << actionPair.second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -402,56 +402,18 @@ void UserInputMapper::assignDefaulActionScales() {
|
|||
_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";
|
||||
}
|
||||
static int actionMetaTypeId = qRegisterMetaType<Action>();
|
||||
static int inputMetaTypeId = qRegisterMetaType<Input>();
|
||||
static int inputPairMetaTypeId = qRegisterMetaType<InputPair>();
|
||||
|
||||
void UserInputMapper::registerStandardDevice() {
|
||||
_standardController = std::make_shared<StandardController>();
|
||||
_standardController->registerToUserInputMapper(*this);
|
||||
_standardController->assignDefaultInputMapping(*this);
|
||||
}
|
||||
QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input);
|
||||
void inputFromScriptValue(const QScriptValue& object, Input& input);
|
||||
QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action);
|
||||
void actionFromScriptValue(const QScriptValue& object, Action& action);
|
||||
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const InputPair& inputPair);
|
||||
void inputPairFromScriptValue(const QScriptValue& object, InputPair& inputPair);
|
||||
|
||||
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 inputToScriptValue(QScriptEngine* engine, const Input& input) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("device", input.getDevice());
|
||||
obj.setProperty("channel", input.getChannel());
|
||||
|
@ -460,14 +422,11 @@ QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::In
|
|||
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());
|
||||
void inputFromScriptValue(const QScriptValue& object, Input& input) {
|
||||
input.id = object.property("id").toInt32();
|
||||
}
|
||||
|
||||
QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) {
|
||||
QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
obj.setProperty("action", (int)action);
|
||||
|
@ -475,38 +434,361 @@ QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::A
|
|||
return obj;
|
||||
}
|
||||
|
||||
void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) {
|
||||
action = UserInputMapper::Action(object.property("action").toVariant().toInt());
|
||||
void actionFromScriptValue(const QScriptValue& object, Action& action) {
|
||||
action = Action(object.property("action").toVariant().toInt());
|
||||
}
|
||||
|
||||
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) {
|
||||
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const 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) {
|
||||
void inputPairFromScriptValue(const QScriptValue& object, 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);
|
||||
qScriptRegisterSequenceMetaType<QVector<Action> >(engine);
|
||||
qScriptRegisterSequenceMetaType<QVector<InputPair> >(engine);
|
||||
qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
|
||||
}
|
||||
|
||||
UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) {
|
||||
Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) {
|
||||
return Input(STANDARD_DEVICE, button, ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) {
|
||||
Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) {
|
||||
return Input(STANDARD_DEVICE, axis, ChannelType::AXIS);
|
||||
}
|
||||
|
||||
UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
|
||||
Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
|
||||
return Input(STANDARD_DEVICE, pose, ChannelType::POSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UserInputMapper::update() {
|
||||
static auto deviceNames = getDeviceNames();
|
||||
_overrideValues.clear();
|
||||
|
||||
EndpointSet readEndpoints;
|
||||
EndpointSet writtenEndpoints;
|
||||
|
||||
static const int HARDWARE_PASS = 0;
|
||||
static const int STANDARD_PASS = 1;
|
||||
|
||||
// Now process the current values for each level of the stack
|
||||
for (auto& mapping : _activeMappings) {
|
||||
for (int pass = 0; pass < 2; ++pass) {
|
||||
for (const auto& mappingEntry : mapping->channelMappings) {
|
||||
const auto& source = mappingEntry.first;
|
||||
if (_inputsByEndpoint.count(source)) {
|
||||
auto sourceInput = _inputsByEndpoint[source];
|
||||
if ((sourceInput.device == STANDARD_DEVICE) ^ (pass == STANDARD_PASS)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoints can only be read once (though a given mapping can route them to
|
||||
// multiple places). Consider... If the default is to wire the A button to JUMP
|
||||
// and someone else wires it to CONTEXT_MENU, I don't want both to occur when
|
||||
// I press the button. The exception is if I'm wiring a control back to itself
|
||||
// in order to adjust my interface, like inverting the Y axis on an analog stick
|
||||
if (readEndpoints.count(source)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Apply the value to all the routes
|
||||
const auto& routes = mappingEntry.second;
|
||||
|
||||
for (const auto& route : routes) {
|
||||
const auto& destination = route->destination;
|
||||
// THis could happen if the route destination failed to create
|
||||
// FIXME: Maybe do not create the route if the destination failed and avoid this case ?
|
||||
if (!destination) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (writtenEndpoints.count(destination)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Standard controller destinations can only be can only be used once.
|
||||
if (getStandardDeviceID() == destination->getInput().getDevice()) {
|
||||
writtenEndpoints.insert(destination);
|
||||
}
|
||||
|
||||
// Only consume the input if the route isn't a loopback.
|
||||
// This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);`
|
||||
bool loopback = source == destination;
|
||||
if (!loopback) {
|
||||
readEndpoints.insert(source);
|
||||
}
|
||||
|
||||
// Fetch the value, may have been overriden by previous loopback routes
|
||||
float value = getValue(source);
|
||||
|
||||
// Apply each of the filters.
|
||||
const auto& filters = route->filters;
|
||||
for (const auto& filter : route->filters) {
|
||||
value = filter->apply(value);
|
||||
}
|
||||
|
||||
if (loopback) {
|
||||
_overrideValues[source] = value;
|
||||
} else {
|
||||
destination->apply(value, 0, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) {
|
||||
if (endpoint.isNumber()) {
|
||||
return endpointFor(Input(endpoint.toInt()));
|
||||
}
|
||||
|
||||
if (endpoint.isCallable()) {
|
||||
auto result = std::make_shared<JSEndpoint>(endpoint);
|
||||
return result;
|
||||
}
|
||||
|
||||
qWarning() << "Unsupported input type " << endpoint.toString();
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
|
||||
Endpoint::Pointer UserInputMapper::endpointFor(const QScriptValue& endpoint) {
|
||||
if (endpoint.isNumber()) {
|
||||
return endpointFor(Input(endpoint.toInt32()));
|
||||
}
|
||||
|
||||
if (endpoint.isFunction()) {
|
||||
auto result = std::make_shared<ScriptEndpoint>(endpoint);
|
||||
return result;
|
||||
}
|
||||
|
||||
qWarning() << "Unsupported input type " << endpoint.toString();
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
|
||||
Endpoint::Pointer UserInputMapper::endpointFor(const Input& inputId) const {
|
||||
auto iterator = _endpointsByInput.find(inputId);
|
||||
if (_endpointsByInput.end() == iterator) {
|
||||
qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
Endpoint::Pointer UserInputMapper::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) {
|
||||
EndpointPair pair(first, second);
|
||||
Endpoint::Pointer result;
|
||||
auto iterator = _compositeEndpoints.find(pair);
|
||||
if (_compositeEndpoints.end() == iterator) {
|
||||
result = std::make_shared<CompositeEndpoint>(first, second);
|
||||
_compositeEndpoints[pair] = result;
|
||||
} else {
|
||||
result = iterator->second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Mapping::Pointer UserInputMapper::newMapping(const QString& mappingName) {
|
||||
if (_mappingsByName.count(mappingName)) {
|
||||
qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
|
||||
}
|
||||
qDebug() << "Creating new Mapping " << mappingName;
|
||||
auto mapping = std::make_shared<Mapping>(mappingName);
|
||||
_mappingsByName[mappingName] = mapping;
|
||||
return mapping;
|
||||
}
|
||||
|
||||
// FIXME handle asynchronous loading in the UserInputMapper
|
||||
//QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) {
|
||||
// QObject* result = nullptr;
|
||||
// auto request = ResourceManager::createResourceRequest(nullptr, QUrl(jsonUrl));
|
||||
// if (request) {
|
||||
// QEventLoop eventLoop;
|
||||
// request->setCacheEnabled(false);
|
||||
// connect(request, &ResourceRequest::finished, &eventLoop, &QEventLoop::quit);
|
||||
// request->send();
|
||||
// if (request->getState() != ResourceRequest::Finished) {
|
||||
// eventLoop.exec();
|
||||
// }
|
||||
//
|
||||
// if (request->getResult() == ResourceRequest::Success) {
|
||||
// result = parseMapping(QString(request->getData()));
|
||||
// } else {
|
||||
// qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl;
|
||||
// }
|
||||
// request->deleteLater();
|
||||
// }
|
||||
// return result;
|
||||
//}
|
||||
|
||||
|
||||
void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
|
||||
qCDebug(controllers) << "Attempting to enable mapping " << mappingName;
|
||||
auto iterator = _mappingsByName.find(mappingName);
|
||||
if (_mappingsByName.end() == iterator) {
|
||||
qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName;
|
||||
return;
|
||||
}
|
||||
|
||||
auto mapping = iterator->second;
|
||||
if (enable) {
|
||||
_activeMappings.push_front(mapping);
|
||||
} else {
|
||||
auto activeIterator = std::find(_activeMappings.begin(), _activeMappings.end(), mapping);
|
||||
if (_activeMappings.end() == activeIterator) {
|
||||
qCWarning(controllers) << "Attempted to disable inactive mapping " << mappingName;
|
||||
return;
|
||||
}
|
||||
_activeMappings.erase(activeIterator);
|
||||
}
|
||||
}
|
||||
|
||||
float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const {
|
||||
auto valuesIterator = _overrideValues.find(endpoint);
|
||||
if (_overrideValues.end() != valuesIterator) {
|
||||
return valuesIterator->second;
|
||||
}
|
||||
|
||||
return endpoint->value();
|
||||
}
|
||||
|
||||
float UserInputMapper::getValue(const Input& input) const {
|
||||
auto endpoint = endpointFor(input);
|
||||
if (!endpoint) {
|
||||
return 0;
|
||||
}
|
||||
return endpoint->value();
|
||||
}
|
||||
|
||||
|
||||
Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) {
|
||||
if (jsonFile.isEmpty()) {
|
||||
return Mapping::Pointer();
|
||||
}
|
||||
QString json;
|
||||
{
|
||||
QFile file(jsonFile);
|
||||
if (file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
json = QTextStream(&file).readAll();
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
return parseMapping(json);
|
||||
}
|
||||
|
||||
|
||||
const QString JSON_NAME = QStringLiteral("name");
|
||||
const QString JSON_CHANNELS = QStringLiteral("channels");
|
||||
const QString JSON_CHANNEL_FROM = QStringLiteral("from");
|
||||
const QString JSON_CHANNEL_TO = QStringLiteral("to");
|
||||
const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
|
||||
|
||||
Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) {
|
||||
if (value.isString()) {
|
||||
auto input = findDeviceInput(value.toString());
|
||||
return endpointFor(input);
|
||||
} else if (value.isObject()) {
|
||||
// Endpoint is defined as an object, we expect a js function then
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
|
||||
Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
|
||||
if (!value.isObject()) {
|
||||
return Route::Pointer();
|
||||
}
|
||||
|
||||
const auto& obj = value.toObject();
|
||||
Route::Pointer result = std::make_shared<Route>();
|
||||
result->source = parseEndpoint(obj[JSON_CHANNEL_FROM]);
|
||||
if (!result->source) {
|
||||
qWarning() << "Invalid route source " << obj[JSON_CHANNEL_FROM];
|
||||
return Route::Pointer();
|
||||
}
|
||||
result->destination = parseEndpoint(obj[JSON_CHANNEL_TO]);
|
||||
if (!result->destination) {
|
||||
qWarning() << "Invalid route destination " << obj[JSON_CHANNEL_TO];
|
||||
return Route::Pointer();
|
||||
}
|
||||
|
||||
const auto& filtersValue = obj[JSON_CHANNEL_FILTERS];
|
||||
if (filtersValue.isArray()) {
|
||||
auto filtersArray = filtersValue.toArray();
|
||||
for (auto filterValue : filtersArray) {
|
||||
if (filterValue.isObject()) {
|
||||
qWarning() << "Invalid filter " << filterValue;
|
||||
return Route::Pointer();
|
||||
}
|
||||
Filter::Pointer filter = Filter::parse(filterValue.toObject());
|
||||
if (!filter) {
|
||||
qWarning() << "Invalid filter " << filterValue;
|
||||
return Route::Pointer();
|
||||
}
|
||||
result->filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Mapping::Pointer UserInputMapper::parseMapping(const QJsonValue& json) {
|
||||
if (!json.isObject()) {
|
||||
return Mapping::Pointer();
|
||||
}
|
||||
|
||||
auto obj = json.toObject();
|
||||
auto mapping = std::make_shared<Mapping>("default");
|
||||
mapping->name = obj[JSON_NAME].toString();
|
||||
mapping->channelMappings.clear();
|
||||
const auto& jsonChannels = obj[JSON_CHANNELS].toArray();
|
||||
Mapping::Map map;
|
||||
for (const auto& channelIt : jsonChannels) {
|
||||
Route::Pointer route = parseRoute(channelIt);
|
||||
if (!route) {
|
||||
qWarning() << "Couldn't parse route";
|
||||
continue;
|
||||
}
|
||||
mapping->channelMappings[route->source].push_back(route);
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
Mapping::Pointer UserInputMapper::parseMapping(const QString& json) {
|
||||
Mapping::Pointer result;
|
||||
QJsonObject obj;
|
||||
QJsonParseError error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error);
|
||||
// check validity of the document
|
||||
if (doc.isNull()) {
|
||||
return Mapping::Pointer();
|
||||
}
|
||||
|
||||
if (!doc.isObject()) {
|
||||
qWarning() << "Mapping json Document is not an object" << endl;
|
||||
return Mapping::Pointer();
|
||||
}
|
||||
|
||||
// FIXME how did we detect this?
|
||||
// qDebug() << "Invalid JSON...\n";
|
||||
// qDebug() << error.errorString();
|
||||
// qDebug() << "JSON was:\n" << json << endl;
|
||||
//}
|
||||
return parseMapping(doc.object());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "UserInputMapper.moc"
|
||||
|
|
|
@ -15,234 +15,155 @@
|
|||
#include <unordered_set>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <QtQml/QJSValue>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#include "Pose.h"
|
||||
#include "Input.h"
|
||||
#include "InputDevice.h"
|
||||
#include "DeviceProxy.h"
|
||||
#include "StandardControls.h"
|
||||
#include "Mapping.h"
|
||||
#include "Endpoint.h"
|
||||
#include "Actions.h"
|
||||
|
||||
class StandardController;
|
||||
typedef std::shared_ptr<StandardController> StandardControllerPointer;
|
||||
namespace controller {
|
||||
class UserInputMapper : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
Q_ENUMS(Action)
|
||||
|
||||
class UserInputMapper : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
Q_ENUMS(Action)
|
||||
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;
|
||||
|
||||
static void registerControllerTypes(QScriptEngine* engine);
|
||||
|
||||
static const uint16 ACTIONS_DEVICE;
|
||||
static const uint16 STANDARD_DEVICE;
|
||||
|
||||
|
||||
// Modifiers are just button inputID
|
||||
typedef std::vector< Input > Modifiers;
|
||||
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;
|
||||
typedef QPair<Input, QString> InputPair;
|
||||
typedef std::function<QVector<InputPair> ()> AvailableInputGetter;
|
||||
typedef std::function<bool ()> ResetBindings;
|
||||
|
||||
typedef QVector<InputPair> AvailableInput;
|
||||
|
||||
// GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
|
||||
uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
|
||||
|
||||
bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device);
|
||||
bool registerStandardDevice(const DeviceProxy::Pointer& device);
|
||||
DeviceProxy::Pointer getDeviceProxy(const Input& input);
|
||||
QString getDeviceName(uint16 deviceID);
|
||||
QVector<InputPair> getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); }
|
||||
void resetAllDeviceBindings();
|
||||
void resetDevice(uint16 deviceID);
|
||||
int findDevice(QString name) const;
|
||||
QVector<QString> getDeviceNames();
|
||||
|
||||
Input findDeviceInput(const QString& inputName) const;
|
||||
|
||||
|
||||
// Actions are the output channels of the Mapper, that's what the InputChannel map to
|
||||
// For now the Actions are hardcoded, this is bad, but we will fix that in the near future
|
||||
enum Action {
|
||||
TRANSLATE_X = 0,
|
||||
TRANSLATE_Y,
|
||||
TRANSLATE_Z,
|
||||
ROTATE_X, PITCH = ROTATE_X,
|
||||
ROTATE_Y, YAW = ROTATE_Y,
|
||||
ROTATE_Z, ROLL = ROTATE_Z,
|
||||
|
||||
TRANSLATE_CAMERA_Z,
|
||||
NUM_COMBINED_AXES,
|
||||
|
||||
LEFT_HAND = NUM_COMBINED_AXES,
|
||||
RIGHT_HAND,
|
||||
|
||||
LEFT_HAND_CLICK,
|
||||
RIGHT_HAND_CLICK,
|
||||
|
||||
ACTION1,
|
||||
ACTION2,
|
||||
|
||||
CONTEXT_MENU,
|
||||
TOGGLE_MUTE,
|
||||
|
||||
SHIFT,
|
||||
|
||||
// Biseced aliases for TRANSLATE_Z
|
||||
LONGITUDINAL_BACKWARD,
|
||||
LONGITUDINAL_FORWARD,
|
||||
|
||||
// Biseced aliases for TRANSLATE_X
|
||||
LATERAL_LEFT,
|
||||
LATERAL_RIGHT,
|
||||
|
||||
// Biseced aliases for TRANSLATE_Y
|
||||
VERTICAL_DOWN,
|
||||
VERTICAL_UP,
|
||||
|
||||
// Biseced aliases for ROTATE_Y
|
||||
YAW_LEFT,
|
||||
YAW_RIGHT,
|
||||
|
||||
// Biseced aliases for ROTATE_X
|
||||
PITCH_DOWN,
|
||||
PITCH_UP,
|
||||
|
||||
// Biseced aliases for TRANSLATE_CAMERA_Z
|
||||
BOOM_IN,
|
||||
BOOM_OUT,
|
||||
|
||||
NUM_ACTIONS,
|
||||
};
|
||||
|
||||
std::vector<QString> _actionNames = std::vector<QString>(NUM_ACTIONS);
|
||||
void createActionNames();
|
||||
|
||||
QVector<Action> getAllActions() const;
|
||||
QString getActionName(Action action) const { return UserInputMapper::_actionNames[(int) action]; }
|
||||
float getActionState(Action action) const { return _actionStates[action]; }
|
||||
PoseValue getPoseState(Action action) const { return _poseStates[action]; }
|
||||
int findAction(const QString& actionName) const;
|
||||
QVector<QString> getActionNames() const;
|
||||
void assignDefaulActionScales();
|
||||
|
||||
void setActionState(Action action, float value) { _externalActionStates[action] = value; }
|
||||
void deltaActionState(Action action, float delta) { _externalActionStates[action] += delta; }
|
||||
|
||||
// Add input channel to the mapper and check that all the used channels are registered.
|
||||
// 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 {
|
||||
public:
|
||||
Input _input;
|
||||
Input _modifier = Input(); // make it invalid by default, meaning no modifier
|
||||
Action _action = LONGITUDINAL_BACKWARD;
|
||||
float _scale = 0.0f;
|
||||
|
||||
Input getInput() const { return _input; }
|
||||
Input getModifier() const { return _modifier; }
|
||||
Action getAction() const { return _action; }
|
||||
float getScale() const { return _scale; }
|
||||
|
||||
void setInput(Input input) { _input = input; }
|
||||
void setModifier(Input modifier) { _modifier = modifier; }
|
||||
void setAction(Action action) { _action = action; }
|
||||
void setScale(float scale) { _scale = scale; }
|
||||
using InputPair = Input::NamedPair;
|
||||
// FIXME move to unordered set / map
|
||||
using EndpointToInputMap = std::map<Endpoint::Pointer, Input>;
|
||||
using MappingNameMap = std::map<QString, Mapping::Pointer>;
|
||||
using MappingDeviceMap = std::map<uint16_t, Mapping::Pointer>;
|
||||
using MappingStack = std::list<Mapping::Pointer>;
|
||||
using InputToEndpointMap = std::map<Input, Endpoint::Pointer>;
|
||||
using EndpointSet = std::unordered_set<Endpoint::Pointer>;
|
||||
using ValueMap = std::map<Endpoint::Pointer, float>;
|
||||
using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
|
||||
using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
|
||||
using DevicesMap = std::map<int, DeviceProxy::Pointer>;
|
||||
using uint16 = uint16_t;
|
||||
using uint32 = uint32_t;
|
||||
|
||||
InputChannel() {}
|
||||
InputChannel(const Input& input, const Input& modifier, Action action, float scale = 1.0f) :
|
||||
_input(input), _modifier(modifier), _action(action), _scale(scale) {}
|
||||
InputChannel(const InputChannel& src) : InputChannel(src._input, src._modifier, src._action, src._scale) {}
|
||||
InputChannel& operator = (const InputChannel& src) { _input = src._input; _modifier = src._modifier; _action = src._action; _scale = src._scale; return (*this); }
|
||||
bool operator ==(const InputChannel& right) const { return _input == right._input && _modifier == right._modifier && _action == right._action && _scale == right._scale; }
|
||||
bool hasModifier() { return _modifier.isValid(); }
|
||||
static const uint16_t ACTIONS_DEVICE;
|
||||
static const uint16_t STANDARD_DEVICE;
|
||||
|
||||
UserInputMapper();
|
||||
virtual ~UserInputMapper();
|
||||
|
||||
|
||||
static void registerControllerTypes(QScriptEngine* engine);
|
||||
|
||||
|
||||
void registerDevice(InputDevice* device);
|
||||
DeviceProxy::Pointer getDeviceProxy(const Input& input);
|
||||
QString getDeviceName(uint16 deviceID);
|
||||
|
||||
Input::NamedVector getAvailableInputs(uint16 deviceID) const;
|
||||
Input::NamedVector getActionInputs() const { return getAvailableInputs(ACTIONS_DEVICE); }
|
||||
Input::NamedVector getStandardInputs() const { return getAvailableInputs(STANDARD_DEVICE); }
|
||||
|
||||
int findDevice(QString name) const;
|
||||
QVector<QString> getDeviceNames();
|
||||
Input findDeviceInput(const QString& inputName) const;
|
||||
|
||||
QVector<Action> getAllActions() const;
|
||||
QString getActionName(Action action) const;
|
||||
float getActionState(Action action) const { return _actionStates[action]; }
|
||||
Pose getPoseState(Action action) const { return _poseStates[action]; }
|
||||
int findAction(const QString& actionName) const;
|
||||
QVector<QString> getActionNames() const;
|
||||
void assignDefaulActionScales();
|
||||
|
||||
void setActionState(Action action, float value) { _externalActionStates[action] = value; }
|
||||
void deltaActionState(Action action, float delta) { _externalActionStates[action] += delta; }
|
||||
|
||||
static Input makeStandardInput(controller::StandardButtonChannel button);
|
||||
static Input makeStandardInput(controller::StandardAxisChannel axis);
|
||||
static Input makeStandardInput(controller::StandardPoseChannel pose);
|
||||
|
||||
void removeDevice(int device);
|
||||
|
||||
// Update means go grab all the device input channels and update the output channel values
|
||||
void update(float deltaTime);
|
||||
|
||||
void setSensorToWorldMat(glm::mat4 sensorToWorldMat) { _sensorToWorldMat = sensorToWorldMat; }
|
||||
glm::mat4 getSensorToWorldMat() { return _sensorToWorldMat; }
|
||||
|
||||
DevicesMap getDevices() { return _registeredDevices; }
|
||||
uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
|
||||
DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
|
||||
|
||||
Mapping::Pointer newMapping(const QString& mappingName);
|
||||
Mapping::Pointer parseMapping(const QString& json);
|
||||
Mapping::Pointer loadMapping(const QString& jsonFile);
|
||||
|
||||
void enableMapping(const QString& mappingName, bool enable = true);
|
||||
float getValue(const Input& input) const;
|
||||
|
||||
signals:
|
||||
void actionEvent(int action, float state);
|
||||
void hardwareChanged();
|
||||
|
||||
protected:
|
||||
virtual void update();
|
||||
// GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
|
||||
uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
|
||||
|
||||
InputDevice::Pointer _standardController;
|
||||
DevicesMap _registeredDevices;
|
||||
uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
|
||||
|
||||
std::vector<float> _actionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
|
||||
std::vector<float> _externalActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
|
||||
std::vector<float> _actionScales = std::vector<float>(NUM_ACTIONS, 1.0f);
|
||||
std::vector<float> _lastActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
|
||||
std::vector<Pose> _poseStates = std::vector<Pose>(NUM_ACTIONS);
|
||||
|
||||
glm::mat4 _sensorToWorldMat;
|
||||
|
||||
int recordDeviceOfType(const QString& deviceName);
|
||||
QHash<const QString&, int> _deviceCounts;
|
||||
|
||||
float getValue(const Endpoint::Pointer& endpoint) const;
|
||||
friend class RouteBuilderProxy;
|
||||
friend class MappingBuilderProxy;
|
||||
Endpoint::Pointer endpointFor(const QJSValue& endpoint);
|
||||
Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
|
||||
Endpoint::Pointer endpointFor(const Input& endpoint) const;
|
||||
Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
|
||||
Mapping::Pointer parseMapping(const QJsonValue& json);
|
||||
Route::Pointer parseRoute(const QJsonValue& value);
|
||||
Endpoint::Pointer parseEndpoint(const QJsonValue& value);
|
||||
|
||||
InputToEndpointMap _endpointsByInput;
|
||||
EndpointToInputMap _inputsByEndpoint;
|
||||
EndpointPairMap _compositeEndpoints;
|
||||
|
||||
ValueMap _overrideValues;
|
||||
MappingNameMap _mappingsByName;
|
||||
Mapping::Pointer _defaultMapping{ std::make_shared<Mapping>("Default") };
|
||||
MappingDeviceMap _mappingsByDevice;
|
||||
MappingStack _activeMappings;
|
||||
};
|
||||
typedef std::vector< InputChannel > InputChannels;
|
||||
}
|
||||
|
||||
// Add a bunch of input channels, return the true number of channels that successfully were added
|
||||
int addInputChannels(const InputChannels& channels);
|
||||
// Remove the first found instance of the input channel from the input mapper, true if found
|
||||
bool removeInputChannel(InputChannel channel);
|
||||
void removeAllInputChannels();
|
||||
void removeAllInputChannelsForDevice(uint16 device);
|
||||
void removeDevice(int device);
|
||||
//Grab all the input channels currently in use, return the number
|
||||
int getInputChannels(InputChannels& channels) const;
|
||||
QVector<InputChannel> getAllInputsForDevice(uint16 device);
|
||||
QVector<InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
|
||||
std::multimap<Action, InputChannel> getActionToInputsMap() { return _actionToInputsMap; }
|
||||
Q_DECLARE_METATYPE(controller::UserInputMapper::InputPair)
|
||||
Q_DECLARE_METATYPE(controller::Pose)
|
||||
Q_DECLARE_METATYPE(QVector<controller::UserInputMapper::InputPair>)
|
||||
Q_DECLARE_METATYPE(controller::Input)
|
||||
Q_DECLARE_METATYPE(controller::Action)
|
||||
Q_DECLARE_METATYPE(QVector<controller::Action>)
|
||||
|
||||
// Update means go grab all the device input channels and update the output channel values
|
||||
void update(float deltaTime);
|
||||
|
||||
void setSensorToWorldMat(glm::mat4 sensorToWorldMat) { _sensorToWorldMat = sensorToWorldMat; }
|
||||
glm::mat4 getSensorToWorldMat() { return _sensorToWorldMat; }
|
||||
|
||||
UserInputMapper();
|
||||
|
||||
typedef std::map<int, DeviceProxy::Pointer> DevicesMap;
|
||||
DevicesMap getDevices() { return _registeredDevices; }
|
||||
|
||||
uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
|
||||
DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
|
||||
|
||||
signals:
|
||||
void actionEvent(int action, float state);
|
||||
|
||||
|
||||
protected:
|
||||
void registerStandardDevice();
|
||||
StandardControllerPointer _standardController;
|
||||
|
||||
DevicesMap _registeredDevices;
|
||||
uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1;
|
||||
|
||||
typedef std::map<int, Modifiers> InputToMoModifiersMap;
|
||||
InputToMoModifiersMap _inputToModifiersMap;
|
||||
|
||||
typedef std::multimap<Action, InputChannel> ActionToInputsMap;
|
||||
ActionToInputsMap _actionToInputsMap;
|
||||
|
||||
std::vector<float> _actionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
|
||||
std::vector<float> _externalActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
|
||||
std::vector<float> _actionScales = std::vector<float>(NUM_ACTIONS, 1.0f);
|
||||
std::vector<float> _lastActionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
|
||||
std::vector<PoseValue> _poseStates = std::vector<PoseValue>(NUM_ACTIONS);
|
||||
|
||||
glm::mat4 _sensorToWorldMat;
|
||||
|
||||
int recordDeviceOfType(const QString& deviceName);
|
||||
QHash<const QString&, int> _deviceCounts;
|
||||
};
|
||||
|
||||
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)
|
||||
Q_DECLARE_METATYPE(QVector<UserInputMapper::InputChannel>)
|
||||
Q_DECLARE_METATYPE(UserInputMapper::Action)
|
||||
Q_DECLARE_METATYPE(QVector<UserInputMapper::Action>)
|
||||
// Cheating.
|
||||
using UserInputMapper = controller::UserInputMapper;
|
||||
|
||||
#endif // hifi_UserInputMapper_h
|
||||
|
|
|
@ -22,7 +22,7 @@ using namespace controller;
|
|||
|
||||
QObject* MappingBuilderProxy::from(int input) {
|
||||
qCDebug(controllers) << "Creating new Route builder proxy from " << input;
|
||||
auto sourceEndpoint = _parent.endpointFor(UserInputMapper::Input(input));
|
||||
auto sourceEndpoint = _parent.endpointFor(Input(input));
|
||||
return from(sourceEndpoint);
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ QObject* MappingBuilderProxy::from(const QScriptValue& source) {
|
|||
QObject* MappingBuilderProxy::from(const Endpoint::Pointer& source) {
|
||||
if (source) {
|
||||
auto route = Route::Pointer(new Route());
|
||||
route->_source = source;
|
||||
route->source = source;
|
||||
return new RouteBuilderProxy(_parent, _mapping, route);
|
||||
} else {
|
||||
qCDebug(controllers) << "MappingBuilderProxy::from : source is null so no route created";
|
||||
|
@ -55,48 +55,8 @@ QObject* MappingBuilderProxy::makeAxis(const QJSValue& source1, const QJSValue&
|
|||
return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint));
|
||||
}
|
||||
|
||||
const QString JSON_NAME = QStringLiteral("name");
|
||||
const QString JSON_CHANNELS = QStringLiteral("channels");
|
||||
const QString JSON_CHANNEL_FROM = QStringLiteral("from");
|
||||
const QString JSON_CHANNEL_TO = QStringLiteral("to");
|
||||
const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
|
||||
|
||||
|
||||
void MappingBuilderProxy::parse(const QJsonObject& json) {
|
||||
_mapping->_name = json[JSON_NAME].toString();
|
||||
|
||||
_mapping->_channelMappings.clear();
|
||||
const auto& jsonChannels = json[JSON_CHANNELS].toArray();
|
||||
for (const auto& channelIt : jsonChannels) {
|
||||
parseRoute(channelIt);
|
||||
}
|
||||
}
|
||||
|
||||
void MappingBuilderProxy::parseRoute(const QJsonValue& json) {
|
||||
if (json.isObject()) {
|
||||
const auto& jsonChannel = json.toObject();
|
||||
|
||||
auto newRoute = from(jsonChannel[JSON_CHANNEL_FROM]);
|
||||
if (newRoute) {
|
||||
auto route = dynamic_cast<RouteBuilderProxy*>(newRoute);
|
||||
route->filters(jsonChannel[JSON_CHANNEL_FILTERS]);
|
||||
route->to(jsonChannel[JSON_CHANNEL_TO]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QObject* MappingBuilderProxy::from(const QJsonValue& json) {
|
||||
if (json.isString()) {
|
||||
return from(_parent.endpointFor(_parent.inputFor(json.toString())));
|
||||
} else if (json.isObject()) {
|
||||
// Endpoint is defined as an object, we expect a js function then
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QObject* MappingBuilderProxy::enable(bool enable) {
|
||||
_parent.enableMapping(_mapping->_name, enable);
|
||||
_parent.enableMapping(_mapping->name, enable);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,13 +22,14 @@ class QJsonValue;
|
|||
namespace controller {
|
||||
|
||||
class ScriptingInterface;
|
||||
class UserInputMapper;
|
||||
|
||||
// TODO migrate functionality to a MappingBuilder class and make the proxy defer to that
|
||||
// (for easier use in both C++ and JS)
|
||||
class MappingBuilderProxy : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MappingBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping)
|
||||
MappingBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping)
|
||||
: _parent(parent), _mapping(mapping) { }
|
||||
|
||||
Q_INVOKABLE QObject* from(int sourceInput);
|
||||
|
@ -39,19 +40,11 @@ public:
|
|||
Q_INVOKABLE QObject* enable(bool enable = true);
|
||||
Q_INVOKABLE QObject* disable() { return enable(false); }
|
||||
|
||||
|
||||
// JSON route creation point
|
||||
Q_INVOKABLE QObject* from(const QJsonValue& json);
|
||||
|
||||
|
||||
void parse(const QJsonObject& json);
|
||||
// void serialize(QJsonObject& json);
|
||||
|
||||
protected:
|
||||
QObject* from(const Endpoint::Pointer& source);
|
||||
|
||||
friend class RouteBuilderProxy;
|
||||
ScriptingInterface& _parent;
|
||||
UserInputMapper& _parent;
|
||||
Mapping::Pointer _mapping;
|
||||
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace controller {
|
|||
|
||||
void RouteBuilderProxy::to(int destinationInput) {
|
||||
qCDebug(controllers) << "Completing route " << destinationInput;
|
||||
auto destinationEndpoint = _parent.endpointFor(UserInputMapper::Input(destinationInput));
|
||||
auto destinationEndpoint = _parent.endpointFor(Input(destinationInput));
|
||||
return to(destinationEndpoint);
|
||||
}
|
||||
|
||||
|
@ -39,9 +39,9 @@ void RouteBuilderProxy::to(const QScriptValue& destination) {
|
|||
}
|
||||
|
||||
void RouteBuilderProxy::to(const Endpoint::Pointer& destination) {
|
||||
auto sourceEndpoint = _route->_source;
|
||||
_route->_destination = destination;
|
||||
_mapping->_channelMappings[sourceEndpoint].push_back(_route);
|
||||
auto sourceEndpoint = _route->source;
|
||||
_route->destination = destination;
|
||||
_mapping->channelMappings[sourceEndpoint].push_back(_route);
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
@ -104,37 +104,7 @@ void RouteBuilderProxy::addFilter(Filter::Lambda lambda) {
|
|||
}
|
||||
|
||||
void RouteBuilderProxy::addFilter(Filter::Pointer filter) {
|
||||
_route->_filters.push_back(filter);
|
||||
}
|
||||
|
||||
|
||||
QObject* RouteBuilderProxy::filters(const QJsonValue& json) {
|
||||
// We expect an array of objects to define the filters
|
||||
if (json.isArray()) {
|
||||
const auto& jsonFilters = json.toArray();
|
||||
for (auto jsonFilter : jsonFilters) {
|
||||
if (jsonFilter.isObject()) {
|
||||
// The filter is an object, now let s check for type and potential arguments
|
||||
Filter::Pointer filter = Filter::parse(jsonFilter.toObject());
|
||||
if (filter) {
|
||||
addFilter(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void RouteBuilderProxy::to(const QJsonValue& json) {
|
||||
if (json.isString()) {
|
||||
|
||||
return to(_parent.endpointFor(_parent.inputFor(json.toString())));
|
||||
} else if (json.isObject()) {
|
||||
// Endpoint is defined as an object, we expect a js function then
|
||||
//return to((Endpoint*) nullptr);
|
||||
}
|
||||
|
||||
_route->filters.push_back(filter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,10 +10,11 @@
|
|||
#define hifi_Controllers_Impl_RouteBuilderProxy_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "../Filter.h"
|
||||
#include "../Route.h"
|
||||
#include "../Mapping.h"
|
||||
|
||||
#include "../UserInputMapper.h"
|
||||
class QJSValue;
|
||||
class QScriptValue;
|
||||
class QJsonValue;
|
||||
|
@ -27,7 +28,7 @@ class ScriptingInterface;
|
|||
class RouteBuilderProxy : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
RouteBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route)
|
||||
RouteBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping, Route::Pointer route)
|
||||
: _parent(parent), _mapping(mapping), _route(route) { }
|
||||
|
||||
Q_INVOKABLE void to(int destination);
|
||||
|
@ -44,15 +45,11 @@ class RouteBuilderProxy : public QObject {
|
|||
Q_INVOKABLE QObject* constrainToInteger();
|
||||
Q_INVOKABLE QObject* constrainToPositiveInteger();
|
||||
|
||||
// JSON route creation point
|
||||
Q_INVOKABLE QObject* filters(const QJsonValue& json);
|
||||
Q_INVOKABLE void to(const QJsonValue& json);
|
||||
|
||||
private:
|
||||
private:
|
||||
void to(const Endpoint::Pointer& destination);
|
||||
void addFilter(Filter::Lambda lambda);
|
||||
void addFilter(Filter::Pointer filter);
|
||||
ScriptingInterface& _parent;
|
||||
UserInputMapper& _parent;
|
||||
Mapping::Pointer _mapping;
|
||||
Route::Pointer _route;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
set(TARGET_NAME entities-renderer)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
|
||||
setup_hifi_library(Widgets Network Script)
|
||||
link_hifi_libraries(shared gpu procedural model model-networking script-engine controllers render render-utils)
|
||||
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)
|
||||
|
||||
target_bullet()
|
||||
|
||||
|
|
|
@ -11,16 +11,15 @@
|
|||
|
||||
#include "Joystick.h"
|
||||
|
||||
#include <limits>
|
||||
#include <glm/glm.hpp>
|
||||
#include <PathUtils.h>
|
||||
|
||||
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),
|
||||
Joystick::Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameController) :
|
||||
InputDevice("GamePad"),
|
||||
_sdlGameController(sdlGameController),
|
||||
_sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
|
||||
_instanceId(instanceId)
|
||||
|
@ -72,136 +71,63 @@ void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
|
|||
|
||||
#endif
|
||||
|
||||
void Joystick::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
|
||||
using namespace controller;
|
||||
proxy->_name = _name;
|
||||
proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this](const Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
|
||||
QVector<Input::NamedPair> availableInputs{
|
||||
makePair(A, "A"),
|
||||
makePair(B, "B"),
|
||||
makePair(X, "X"),
|
||||
makePair(Y, "Y"),
|
||||
// DPad
|
||||
makePair(DU, "DU"),
|
||||
makePair(DD, "DD"),
|
||||
makePair(DL, "DL"),
|
||||
makePair(DR, "DR"),
|
||||
// Bumpers
|
||||
makePair(LB, "LB"),
|
||||
makePair(RB, "RB"),
|
||||
// Stick press
|
||||
makePair(LS, "LS"),
|
||||
makePair(RS, "RS"),
|
||||
// Center buttons
|
||||
makePair(START, "Start"),
|
||||
makePair(BACK, "Back"),
|
||||
// Analog sticks
|
||||
makePair(LX, "LX"),
|
||||
makePair(LY, "LY"),
|
||||
makePair(RX, "RX"),
|
||||
makePair(RY, "RY"),
|
||||
|
||||
// Triggers
|
||||
makePair(LT, "LT"),
|
||||
makePair(RT, "RT"),
|
||||
|
||||
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"));
|
||||
|
||||
// Aliases, PlayStation style names
|
||||
makePair(LB, "L1"),
|
||||
makePair(RB, "R1"),
|
||||
makePair(LT, "L2"),
|
||||
makePair(RT, "R2"),
|
||||
makePair(LS, "L3"),
|
||||
makePair(RS, "R3"),
|
||||
makePair(BACK, "Select"),
|
||||
makePair(A, "Cross"),
|
||||
makePair(B, "Circle"),
|
||||
makePair(X, "Square"),
|
||||
makePair(Y, "Triangle"),
|
||||
makePair(DU, "Up"),
|
||||
makePair(DD, "Down"),
|
||||
makePair(DL, "Left"),
|
||||
makePair(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
|
||||
}
|
||||
QString Joystick::getDefaultMappingConfig() {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/xbox.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <controllers/InputDevice.h>
|
||||
#include <controllers/StandardControls.h>
|
||||
|
||||
class Joystick : public QObject, public InputDevice {
|
||||
class Joystick : public QObject, public controller::InputDevice {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ getName)
|
||||
|
||||
|
@ -36,16 +36,16 @@ public:
|
|||
const QString& getName() const { return _name; }
|
||||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
|
||||
virtual QString getDefaultMappingConfig() override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
Joystick() : InputDevice("Joystick") {}
|
||||
Joystick() : InputDevice("GamePad") {}
|
||||
~Joystick();
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
|
||||
Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameController);
|
||||
#endif
|
||||
|
||||
void closeJoystick();
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QTouchEvent>
|
||||
|
||||
#include <controllers/UserInputMapper.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse";
|
||||
|
||||
|
@ -128,163 +130,153 @@ void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) {
|
|||
_lastTouch = currentPos;
|
||||
}
|
||||
|
||||
UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::Key code) {
|
||||
auto shortCode = (UserInputMapper::uint16)(code & KEYBOARD_MASK);
|
||||
controller::Input KeyboardMouseDevice::makeInput(Qt::Key code) {
|
||||
auto shortCode = (uint16_t)(code & KEYBOARD_MASK);
|
||||
if (shortCode != code) {
|
||||
shortCode |= 0x0800; // add this bit instead of the way Qt::Key add a bit on the 3rd byte for some keys
|
||||
}
|
||||
return UserInputMapper::Input(_deviceID, shortCode, UserInputMapper::ChannelType::BUTTON);
|
||||
return controller::Input(_deviceID, shortCode, controller::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) {
|
||||
controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) {
|
||||
switch (code) {
|
||||
case Qt::LeftButton:
|
||||
return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_LEFT, UserInputMapper::ChannelType::BUTTON);
|
||||
return controller::Input(_deviceID, MOUSE_BUTTON_LEFT, controller::ChannelType::BUTTON);
|
||||
case Qt::RightButton:
|
||||
return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_RIGHT, UserInputMapper::ChannelType::BUTTON);
|
||||
return controller::Input(_deviceID, MOUSE_BUTTON_RIGHT, controller::ChannelType::BUTTON);
|
||||
case Qt::MiddleButton:
|
||||
return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_MIDDLE, UserInputMapper::ChannelType::BUTTON);
|
||||
return controller::Input(_deviceID, MOUSE_BUTTON_MIDDLE, controller::ChannelType::BUTTON);
|
||||
default:
|
||||
return UserInputMapper::Input();
|
||||
return controller::Input();
|
||||
};
|
||||
}
|
||||
|
||||
UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) {
|
||||
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
|
||||
controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) {
|
||||
return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) {
|
||||
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
|
||||
controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) {
|
||||
return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) {
|
||||
return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
|
||||
controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) {
|
||||
return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
void KeyboardMouseDevice::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;
|
||||
void KeyboardMouseDevice::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
|
||||
using namespace controller;
|
||||
proxy->getButton = [this] (const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this] (const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this] () -> QVector<Input::NamedPair> {
|
||||
QVector<Input::NamedPair> availableInputs;
|
||||
for (int i = (int) Qt::Key_0; i <= (int) Qt::Key_9; i++) {
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
|
||||
}
|
||||
for (int i = (int) Qt::Key_A; i <= (int) Qt::Key_Z; i++) {
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
|
||||
}
|
||||
for (int i = (int) Qt::Key_Left; i <= (int) Qt::Key_Down; i++) {
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString()));
|
||||
}
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_Space), QKeySequence(Qt::Key_Space).toString()));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_Shift), "Shift"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString()));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString()));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Space), QKeySequence(Qt::Key_Space).toString()));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Shift), "Shift"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString()));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString()));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::LeftButton), "Left Mouse Click"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::MiddleButton), "Middle Mouse Click"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::RightButton), "Right Mouse Click"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "Left Mouse Click"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "Middle Mouse Click"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(Qt::RightButton), "Right Mouse Click"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_X_POS), "Mouse Move Right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_X_NEG), "Mouse Move Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_Y_POS), "Mouse Move Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_Y_NEG), "Mouse Move Down"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_POS), "Mouse Move Right"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_NEG), "Mouse Move Left"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_POS), "Mouse Move Up"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_NEG), "Mouse Move Down"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "Mouse Wheel Right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "Mouse Wheel Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "Mouse Wheel Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_X_NEG), "Mouse Wheel Down"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "Mouse Wheel Right"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "Mouse Wheel Left"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "Mouse Wheel Up"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_NEG), "Mouse Wheel Down"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_X_POS), "Touchpad Right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_X_NEG), "Touchpad Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_Y_POS), "Touchpad Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_Y_NEG), "Touchpad Down"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_POS), "Touchpad Right"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_NEG), "Touchpad Left"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_POS), "Touchpad Up"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_NEG), "Touchpad Down"));
|
||||
|
||||
return availableInputs;
|
||||
};
|
||||
proxy->resetDeviceBindings = [this, &mapper] () -> bool {
|
||||
mapper.removeAllInputChannelsForDevice(_deviceID);
|
||||
this->assignDefaultInputMapping(mapper);
|
||||
return true;
|
||||
};
|
||||
mapper.registerDevice(_deviceID, proxy);
|
||||
}
|
||||
|
||||
void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
const float BUTTON_MOVE_SPEED = 1.0f;
|
||||
const float BUTTON_YAW_SPEED = 0.75f;
|
||||
const float BUTTON_PITCH_SPEED = 0.5f;
|
||||
const float MOUSE_YAW_SPEED = 0.5f;
|
||||
const float MOUSE_PITCH_SPEED = 0.25f;
|
||||
const float TOUCH_YAW_SPEED = 0.5f;
|
||||
const float TOUCH_PITCH_SPEED = 0.25f;
|
||||
const float BUTTON_BOOM_SPEED = 0.1f;
|
||||
|
||||
// AWSD keys mapping
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_S), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_W), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_A), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_D), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_C), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_E), BUTTON_MOVE_SPEED);
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
|
||||
|
||||
// Arrow keys mapping
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED);
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
|
||||
|
||||
// Mouse move
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
|
||||
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
// wheel event modifier on Mac collide with the touchpad scroll event
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
|
||||
#else
|
||||
// Touch pad yaw pitch
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
|
||||
|
||||
// Wheel move
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED);
|
||||
|
||||
#endif
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(Qt::Key_Space));
|
||||
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(Qt::Key_R));
|
||||
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(Qt::Key_T));
|
||||
QString KeyboardMouseDevice::getDefaultMappingConfig() {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/keyboardMouse.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
||||
//void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
// const float BUTTON_MOVE_SPEED = 1.0f;
|
||||
// const float BUTTON_YAW_SPEED = 0.75f;
|
||||
// const float BUTTON_PITCH_SPEED = 0.5f;
|
||||
// const float MOUSE_YAW_SPEED = 0.5f;
|
||||
// const float MOUSE_PITCH_SPEED = 0.25f;
|
||||
// const float TOUCH_YAW_SPEED = 0.5f;
|
||||
// const float TOUCH_PITCH_SPEED = 0.25f;
|
||||
// const float BUTTON_BOOM_SPEED = 0.1f;
|
||||
//
|
||||
// // AWSD keys mapping
|
||||
//
|
||||
// mapper.addInputChannel(controller::BOOM_IN, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
|
||||
// mapper.addInputChannel(controller::BOOM_OUT, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
|
||||
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
|
||||
// mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
|
||||
//
|
||||
// // Arrow keys mapping
|
||||
// mapper.addInputChannel(controller::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED);
|
||||
// mapper.addInputChannel(controller::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED);
|
||||
// mapper.addInputChannel(controller::YAW_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED);
|
||||
// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED);
|
||||
// mapper.addInputChannel(controller::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED);
|
||||
// mapper.addInputChannel(controller::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED);
|
||||
//
|
||||
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
|
||||
// mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
|
||||
//
|
||||
// // Mouse move
|
||||
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
|
||||
// mapper.addInputChannel(controller::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
|
||||
// mapper.addInputChannel(controller::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
|
||||
//
|
||||
//
|
||||
//#ifdef Q_OS_MAC
|
||||
// // wheel event modifier on Mac collide with the touchpad scroll event
|
||||
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
|
||||
// mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
|
||||
// mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
|
||||
//#else
|
||||
// // Touch pad yaw pitch
|
||||
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
|
||||
// mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
|
||||
// mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
|
||||
//
|
||||
// // Wheel move
|
||||
// mapper.addInputChannel(controller::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED);
|
||||
// mapper.addInputChannel(controller::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED);
|
||||
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED);
|
||||
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED);
|
||||
//
|
||||
//#endif
|
||||
//
|
||||
// mapper.addInputChannel(controller::SHIFT, makeInput(Qt::Key_Space));
|
||||
// mapper.addInputChannel(controller::ACTION1, makeInput(Qt::Key_R));
|
||||
// mapper.addInputChannel(controller::ACTION2, makeInput(Qt::Key_T));
|
||||
//}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class QKeyEvent;
|
|||
class QMouseEvent;
|
||||
class QWheelEvent;
|
||||
|
||||
class KeyboardMouseDevice : public InputPlugin, public InputDevice {
|
||||
class KeyboardMouseDevice : public InputPlugin, public controller::InputDevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum KeyboardChannel {
|
||||
|
@ -72,8 +72,8 @@ public:
|
|||
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
|
||||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
|
||||
virtual QString getDefaultMappingConfig() override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
|
@ -91,11 +91,11 @@ public:
|
|||
void wheelEvent(QWheelEvent* event);
|
||||
|
||||
// Let's make it easy for Qt because we assume we love Qt forever
|
||||
UserInputMapper::Input makeInput(Qt::Key code);
|
||||
UserInputMapper::Input makeInput(Qt::MouseButton code);
|
||||
UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis);
|
||||
UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis);
|
||||
UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button);
|
||||
controller::Input makeInput(Qt::Key code);
|
||||
controller::Input makeInput(Qt::MouseButton code);
|
||||
controller::Input makeInput(MouseAxisChannel axis);
|
||||
controller::Input makeInput(TouchAxisChannel axis);
|
||||
controller::Input makeInput(TouchButtonChannel button);
|
||||
|
||||
static const QString NAME;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <HFActionEvent.h>
|
||||
#include <HFBackEvent.h>
|
||||
#include <PerfStat.h>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
|
||||
#include "SDL2Manager.h"
|
||||
|
||||
|
@ -47,11 +48,11 @@ void SDL2Manager::init() {
|
|||
if (controller) {
|
||||
SDL_JoystickID id = getInstanceId(controller);
|
||||
if (!_openJoysticks.contains(id)) {
|
||||
Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
|
||||
//Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
|
||||
Joystick* joystick = new Joystick(id, controller);
|
||||
_openJoysticks[id] = joystick;
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
joystick->registerToUserInputMapper(*userInputMapper);
|
||||
joystick->assignDefaultInputMapping(*userInputMapper);
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->registerDevice(joystick);
|
||||
emit joystickAdded(joystick);
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +93,7 @@ void SDL2Manager::pluginFocusOutEvent() {
|
|||
void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) {
|
||||
#ifdef HAVE_SDL2
|
||||
if (_isInitialized) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
for (auto joystick : _openJoysticks) {
|
||||
joystick->update(deltaTime, jointsCaptured);
|
||||
}
|
||||
|
@ -124,13 +125,11 @@ void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) {
|
|||
|
||||
} else if (event.type == SDL_CONTROLLERDEVICEADDED) {
|
||||
SDL_GameController* controller = SDL_GameControllerOpen(event.cdevice.which);
|
||||
|
||||
SDL_JoystickID id = getInstanceId(controller);
|
||||
if (!_openJoysticks.contains(id)) {
|
||||
Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
|
||||
_openJoysticks[id] = joystick;
|
||||
joystick->registerToUserInputMapper(*userInputMapper);
|
||||
joystick->assignDefaultInputMapping(*userInputMapper);
|
||||
// Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller);
|
||||
Joystick* joystick = new Joystick(id, controller);
|
||||
userInputMapper->registerDevice(joystick);
|
||||
emit joystickAdded(joystick);
|
||||
}
|
||||
} else if (event.type == SDL_CONTROLLERDEVICEREMOVED) {
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
#include <PerfStat.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <PathUtils.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
#include "SixenseManager.h"
|
||||
#include "UserActivityLogger.h"
|
||||
|
||||
|
||||
#ifdef HAVE_SIXENSE
|
||||
#include "sixense.h"
|
||||
|
@ -119,8 +122,8 @@ void SixenseManager::activate() {
|
|||
loadSettings();
|
||||
sixenseInit();
|
||||
_activated = true;
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
registerToUserInputMapper(*userInputMapper);
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->registerDevice(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -171,7 +174,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
|
|||
(SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");
|
||||
#endif
|
||||
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
|
||||
if (sixenseGetNumActiveControllers() == 0) {
|
||||
_poseStateMap.clear();
|
||||
|
@ -232,7 +235,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
|
|||
_poseStateMap.clear();
|
||||
}
|
||||
} else {
|
||||
_poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = UserInputMapper::PoseValue();
|
||||
_poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = controller::Pose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -440,8 +443,7 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, boo
|
|||
// TODO: find a shortcut with fewer rotations.
|
||||
rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand;
|
||||
|
||||
_poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] =
|
||||
UserInputMapper::PoseValue(position, rotation);
|
||||
_poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = controller::Pose(position, rotation);
|
||||
#endif // HAVE_SIXENSE
|
||||
}
|
||||
|
||||
|
@ -456,85 +458,91 @@ 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();
|
||||
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->getPose = [this](const UserInputMapper::Input& input, int timestamp) -> UserInputMapper::PoseValue { return this->getPose(input.getChannel()); };
|
||||
using namespace controller;
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<UserInputMapper::InputPair> {
|
||||
QVector<UserInputMapper::InputPair> availableInputs;
|
||||
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(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"));
|
||||
using namespace controller;
|
||||
|
||||
void SixenseManager::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
|
||||
proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this](const Input& input, int timestamp) -> float {
|
||||
return this->getAxis(input.getChannel());
|
||||
};
|
||||
proxy->getPose = [this](const Input& input, int timestamp) -> Pose { return this->getPose(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
|
||||
QVector<Input::NamedPair> availableInputs;
|
||||
availableInputs.append(Input::NamedPair(makeInput(L0), "L0"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(L1), "L1"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(L2), "L2"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(L3), "L3"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(L4), "L4"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(LB), "LB"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(LS), "LS"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(LX), "LX"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(LY), "LY"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(LT), "LT"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(R0), "R0"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(R1), "R1"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(R2), "R2"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(R3), "R3"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(R4), "R4"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(RB), "RB"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(RS), "RS"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(RX), "RX"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(RY), "RY"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(RT), "RT"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(LEFT), "LeftPose"));
|
||||
availableInputs.append(Input::NamedPair(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));
|
||||
|
||||
QString SixenseManager::getDefaultMappingConfig() {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/hydra.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
||||
//
|
||||
//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;
|
||||
|
|
|
@ -42,7 +42,7 @@ const unsigned int BUTTON_TRIGGER = 1U << 8;
|
|||
const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
|
||||
|
||||
// Handles interaction with the Sixense SDK (e.g., Razer Hydra).
|
||||
class SixenseManager : public InputPlugin, public InputDevice {
|
||||
class SixenseManager : public InputPlugin, public controller::InputDevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SixenseManager();
|
||||
|
@ -60,8 +60,8 @@ public:
|
|||
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
|
||||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
|
||||
virtual QString getDefaultMappingConfig() override;
|
||||
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
|
|
@ -12,15 +12,19 @@
|
|||
#include "ViveControllerManager.h"
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "GeometryCache.h"
|
||||
#include <PathUtils.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <display-plugins/openvr/OpenVrHelpers.h>
|
||||
#include "NumericalConstants.h"
|
||||
#include <NumericalConstants.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include "UserActivityLogger.h"
|
||||
#include <UserActivityLogger.h>
|
||||
|
||||
#include <controllers/UserInputMapper.h>
|
||||
|
||||
#include <controllers/StandardControls.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
extern vr::IVRSystem* _hmd;
|
||||
|
@ -29,18 +33,6 @@ extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]
|
|||
extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
|
||||
#endif
|
||||
|
||||
const unsigned int LEFT_MASK = 0U;
|
||||
const unsigned int RIGHT_MASK = 1U;
|
||||
|
||||
const uint64_t VR_BUTTON_A = 1U << 1;
|
||||
const uint64_t VR_GRIP_BUTTON = 1U << 2;
|
||||
const uint64_t VR_TRACKPAD_BUTTON = 1ULL << 32;
|
||||
const uint64_t VR_TRIGGER_BUTTON = 1ULL << 33;
|
||||
|
||||
const unsigned int BUTTON_A = 1U << 1;
|
||||
const unsigned int GRIP_BUTTON = 1U << 2;
|
||||
const unsigned int TRACKPAD_BUTTON = 1U << 3;
|
||||
const unsigned int TRIGGER_BUTTON = 1U << 4;
|
||||
|
||||
const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
|
||||
const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
|
||||
|
@ -173,8 +165,8 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint
|
|||
//pendingChanges.updateItem(_leftHandRenderID, );
|
||||
|
||||
|
||||
UserInputMapper::PoseValue leftHand = _poseStateMap[makeInput(JointChannel::LEFT_HAND).getChannel()];
|
||||
UserInputMapper::PoseValue rightHand = _poseStateMap[makeInput(JointChannel::RIGHT_HAND).getChannel()];
|
||||
controller::Pose leftHand = _poseStateMap[controller::StandardPoseChannel::LEFT];
|
||||
controller::Pose rightHand = _poseStateMap[controller::StandardPoseChannel::RIGHT];
|
||||
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
@ -186,21 +178,20 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint
|
|||
//batch._glBindTexture(GL_TEXTURE_2D, _uexture);
|
||||
|
||||
if (leftHand.isValid()) {
|
||||
renderHand(leftHand, batch, LEFT_HAND);
|
||||
renderHand(leftHand, batch, 1);
|
||||
}
|
||||
if (rightHand.isValid()) {
|
||||
renderHand(rightHand, batch, RIGHT_HAND);
|
||||
renderHand(rightHand, batch, -1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
Transform transform(userInputMapper->getSensorToWorldMat());
|
||||
transform.postTranslate(pose.getTranslation() + pose.getRotation() * glm::vec3(0, 0, CONTROLLER_LENGTH_OFFSET));
|
||||
|
||||
int sign = index == LEFT_HAND ? 1 : -1;
|
||||
glm::quat rotation = pose.getRotation() * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(sign * PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
transform.postRotate(rotation);
|
||||
|
||||
|
@ -251,6 +242,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
|
|||
}
|
||||
|
||||
numTrackedControllers++;
|
||||
bool left = numTrackedControllers == 1;
|
||||
|
||||
const mat4& mat = _trackedDevicePoseMat4[device];
|
||||
|
||||
|
@ -264,14 +256,18 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
|
|||
//qDebug() << (numTrackedControllers == 1 ? "Left: " : "Right: ");
|
||||
//qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y;
|
||||
//qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y;
|
||||
handleButtonEvent(controllerState.ulButtonPressed, numTrackedControllers - 1);
|
||||
for (int i = 0; i < vr::k_unControllerStateAxisCount; i++) {
|
||||
handleAxisEvent(Axis(i), controllerState.rAxis[i].x, controllerState.rAxis[i].y, numTrackedControllers - 1);
|
||||
for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) {
|
||||
auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i);
|
||||
bool pressed = 0 != (controllerState.ulButtonPressed & mask);
|
||||
handleButtonEvent(i, pressed, left);
|
||||
}
|
||||
for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) {
|
||||
handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
|
||||
if (numTrackedControllers == 0) {
|
||||
if (_deviceID != 0) {
|
||||
|
@ -282,8 +278,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
|
|||
}
|
||||
|
||||
if (_trackedControllers == 0 && numTrackedControllers > 0) {
|
||||
registerToUserInputMapper(*userInputMapper);
|
||||
assignDefaultInputMapping(*userInputMapper);
|
||||
userInputMapper->registerDevice(this);
|
||||
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "steamVR");
|
||||
}
|
||||
|
||||
|
@ -296,33 +291,41 @@ void ViveControllerManager::focusOutEvent() {
|
|||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
void ViveControllerManager::handleAxisEvent(Axis axis, float x, float y, int index) {
|
||||
if (axis == TRACKPAD_AXIS) {
|
||||
_axisStateMap[makeInput(AXIS_Y_POS, index).getChannel()] = (y > 0.0f) ? y : 0.0f;
|
||||
_axisStateMap[makeInput(AXIS_Y_NEG, index).getChannel()] = (y < 0.0f) ? -y : 0.0f;
|
||||
_axisStateMap[makeInput(AXIS_X_POS, index).getChannel()] = (x > 0.0f) ? x : 0.0f;
|
||||
_axisStateMap[makeInput(AXIS_X_NEG, index).getChannel()] = (x < 0.0f) ? -x : 0.0f;
|
||||
} else if (axis == TRIGGER_AXIS) {
|
||||
_axisStateMap[makeInput(BACK_TRIGGER, index).getChannel()] = x;
|
||||
// These functions do translation from the Steam IDs to the standard controller IDs
|
||||
void ViveControllerManager::handleAxisEvent(uint32_t axis, float x, float y, bool left) {
|
||||
#ifdef Q_OS_WIN
|
||||
using namespace controller;
|
||||
if (axis == vr::k_EButton_SteamVR_Touchpad) {
|
||||
_axisStateMap[left ? LX : RX] = x;
|
||||
_axisStateMap[left ? LY : RY] = y;
|
||||
} else if (axis == vr::k_EButton_SteamVR_Trigger) {
|
||||
_axisStateMap[left ? LT : RT] = x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ViveControllerManager::handleButtonEvent(uint64_t buttons, int index) {
|
||||
if (buttons & VR_BUTTON_A) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_A, index).getChannel());
|
||||
// These functions do translation from the Steam IDs to the standard controller IDs
|
||||
void ViveControllerManager::handleButtonEvent(uint32_t button, bool pressed, bool left) {
|
||||
#ifdef Q_OS_WIN
|
||||
if (!pressed) {
|
||||
return;
|
||||
}
|
||||
if (buttons & VR_GRIP_BUTTON) {
|
||||
_buttonPressedMap.insert(makeInput(GRIP_BUTTON, index).getChannel());
|
||||
}
|
||||
if (buttons & VR_TRACKPAD_BUTTON) {
|
||||
_buttonPressedMap.insert(makeInput(TRACKPAD_BUTTON, index).getChannel());
|
||||
}
|
||||
if (buttons & VR_TRIGGER_BUTTON) {
|
||||
_buttonPressedMap.insert(makeInput(TRIGGER_BUTTON, index).getChannel());
|
||||
|
||||
if (button == vr::k_EButton_ApplicationMenu) {
|
||||
// FIXME?
|
||||
_buttonPressedMap.insert(left ? controller::A : controller::A);
|
||||
} else if (button == vr::k_EButton_Grip) {
|
||||
// Tony says these are harder to reach, so make them the meta buttons
|
||||
_buttonPressedMap.insert(left ? controller::BACK : controller::START);
|
||||
} else if (button == vr::k_EButton_SteamVR_Trigger) {
|
||||
_buttonPressedMap.insert(left ? controller::LB : controller::RB);
|
||||
} else if (button == vr::k_EButton_SteamVR_Touchpad) {
|
||||
_buttonPressedMap.insert(left ? controller::LS : controller::RS);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) {
|
||||
void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) {
|
||||
glm::vec3 position = extractTranslation(mat);
|
||||
glm::quat rotation = glm::quat_cast(mat);
|
||||
|
||||
|
@ -378,7 +381,7 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) {
|
|||
|
||||
const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
float sign = (index == LEFT_HAND) ? -1.0f : 1.0f;
|
||||
float sign = left ? -1.0f : 1.0f;
|
||||
const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
const glm::quat offset = glm::inverse(signedQuaterZ * eighthX);
|
||||
|
@ -386,92 +389,93 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) {
|
|||
|
||||
position += rotation * glm::vec3(0, 0, -CONTROLLER_LENGTH_OFFSET);
|
||||
|
||||
_poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation);
|
||||
_poseStateMap[left ? controller::LEFT : controller::RIGHT] = controller::Pose(position, rotation);
|
||||
}
|
||||
|
||||
void ViveControllerManager::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||
// Grab the current free device ID
|
||||
_deviceID = mapper.getFreeDeviceID();
|
||||
|
||||
auto proxy = UserInputMapper::DeviceProxy::Pointer(new 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->getPose = [this](const UserInputMapper::Input& input, int timestamp) -> UserInputMapper::PoseValue { return this->getPose(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
|
||||
QVector<UserInputMapper::InputPair> availableInputs;
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_HAND), "Left Hand"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_A, 0), "Left Button A"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(TRIGGER_BUTTON, 0), "Left Trigger Button"));
|
||||
void ViveControllerManager::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
|
||||
using namespace controller;
|
||||
proxy->_name = _name;
|
||||
proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this](const Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getPose = [this](const Input& input, int timestamp) -> Pose { return this->getPose(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<Input::NamedPair> {
|
||||
QVector<Input::NamedPair> availableInputs{
|
||||
// Trackpad analogs
|
||||
makePair(LX, "LX"),
|
||||
makePair(LY, "LY"),
|
||||
makePair(RX, "RX"),
|
||||
makePair(RY, "RY"),
|
||||
// trigger analogs
|
||||
makePair(LT, "LT"),
|
||||
makePair(RT, "RT"),
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 0), "Left Trackpad Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 0), "Left Trackpad Down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 0), "Left Trackpad Right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 0), "Left Trackpad Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 0), "Left Back Trigger"));
|
||||
makePair(LB, "LB"),
|
||||
makePair(RB, "RB"),
|
||||
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_HAND), "Right Hand"));
|
||||
makePair(LS, "LS"),
|
||||
makePair(RS, "RS"),
|
||||
};
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_A, 1), "Right Button A"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(GRIP_BUTTON, 1), "Right Grip Button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(TRACKPAD_BUTTON, 1), "Right Trackpad Button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(TRIGGER_BUTTON, 1), "Right Trigger Button"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(LEFT_HAND), "Left Hand"));
|
||||
|
||||
//availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 0), "Left Button A"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 0), "Left Trigger Button"));
|
||||
|
||||
//availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_POS, 0), "Left Trackpad Up"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_NEG, 0), "Left Trackpad Down"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(AXIS_X_POS, 0), "Left Trackpad Right"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(AXIS_X_NEG, 0), "Left Trackpad Left"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 0), "Left Back Trigger"));
|
||||
|
||||
|
||||
//availableInputs.append(Input::NamedPair(makeInput(RIGHT_HAND), "Right Hand"));
|
||||
|
||||
//availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 1), "Right Button A"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 1), "Right Grip Button"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 1), "Right Trackpad Button"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 1), "Right Trigger Button"));
|
||||
|
||||
//availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_POS, 1), "Right Trackpad Up"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_NEG, 1), "Right Trackpad Down"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(AXIS_X_POS, 1), "Right Trackpad Right"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(AXIS_X_NEG, 1), "Right Trackpad Left"));
|
||||
//availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 1), "Right Back Trigger"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 1), "Right Trackpad Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 1), "Right Trackpad Down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 1), "Right Trackpad Right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 1), "Right Trackpad Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 1), "Right Back Trigger"));
|
||||
|
||||
return availableInputs;
|
||||
};
|
||||
proxy->resetDeviceBindings = [this, &mapper] () -> bool {
|
||||
mapper.removeAllInputChannelsForDevice(_deviceID);
|
||||
this->assignDefaultInputMapping(mapper);
|
||||
return true;
|
||||
};
|
||||
mapper.registerDevice(_deviceID, proxy);
|
||||
}
|
||||
|
||||
void ViveControllerManager::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
|
||||
// Left Trackpad: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(AXIS_X_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(AXIS_X_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
||||
|
||||
// Right Trackpad: Vertical movement, zooming
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(AXIS_Y_POS, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(AXIS_Y_NEG, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
|
||||
|
||||
// Buttons
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 0));
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 1));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(GRIP_BUTTON, 0));
|
||||
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(GRIP_BUTTON, 1));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0));
|
||||
mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1));
|
||||
|
||||
// Hands
|
||||
mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
|
||||
mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
|
||||
QString ViveControllerManager::getDefaultMappingConfig() {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
||||
UserInputMapper::Input ViveControllerManager::makeInput(unsigned int button, int index) {
|
||||
return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
UserInputMapper::Input ViveControllerManager::makeInput(ViveControllerManager::JoystickAxisChannel axis, int index) {
|
||||
return UserInputMapper::Input(_deviceID, axis | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
UserInputMapper::Input ViveControllerManager::makeInput(JointChannel joint) {
|
||||
return UserInputMapper::Input(_deviceID, joint, UserInputMapper::ChannelType::POSE);
|
||||
}
|
||||
//void ViveControllerManager::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
// const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
//
|
||||
// // Left Trackpad: Movement, strafing
|
||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(AXIS_X_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(AXIS_X_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
||||
//
|
||||
// // Right Trackpad: Vertical movement, zooming
|
||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(AXIS_Y_POS, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(AXIS_Y_NEG, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
|
||||
//
|
||||
// // Buttons
|
||||
// mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 0));
|
||||
// mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 1));
|
||||
//
|
||||
// mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(GRIP_BUTTON, 0));
|
||||
// mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(GRIP_BUTTON, 1));
|
||||
//
|
||||
// mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0));
|
||||
// mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1));
|
||||
//
|
||||
// // Hands
|
||||
// mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
|
||||
// mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
|
||||
//}
|
||||
|
|
|
@ -24,30 +24,9 @@
|
|||
#include <RenderArgs.h>
|
||||
#include <render/Scene.h>
|
||||
|
||||
class ViveControllerManager : public InputPlugin, public InputDevice {
|
||||
class ViveControllerManager : public InputPlugin, public controller::InputDevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum JoystickAxisChannel {
|
||||
AXIS_Y_POS = 1U << 1,
|
||||
AXIS_Y_NEG = 1U << 2,
|
||||
AXIS_X_POS = 1U << 3,
|
||||
AXIS_X_NEG = 1U << 4,
|
||||
BACK_TRIGGER = 1U << 5,
|
||||
};
|
||||
|
||||
enum Axis {
|
||||
TRACKPAD_AXIS = 0,
|
||||
TRIGGER_AXIS,
|
||||
AXIS_2,
|
||||
AXIS_3,
|
||||
AXIS_4,
|
||||
};
|
||||
|
||||
enum JointChannel {
|
||||
LEFT_HAND = 0,
|
||||
RIGHT_HAND,
|
||||
};
|
||||
|
||||
ViveControllerManager();
|
||||
|
||||
// Plugin functions
|
||||
|
@ -62,8 +41,8 @@ public:
|
|||
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
|
||||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
|
||||
virtual QString getDefaultMappingConfig() override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
|
@ -71,16 +50,12 @@ public:
|
|||
|
||||
void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; }
|
||||
|
||||
UserInputMapper::Input makeInput(unsigned int button, int index);
|
||||
UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index);
|
||||
UserInputMapper::Input makeInput(JointChannel joint);
|
||||
|
||||
private:
|
||||
void renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index);
|
||||
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
|
||||
|
||||
void handleButtonEvent(uint64_t buttons, int index);
|
||||
void handleAxisEvent(Axis axis, float x, float y, int index);
|
||||
void handlePoseEvent(const mat4& mat, int index);
|
||||
void handleButtonEvent(uint32_t button, bool pressed, bool left);
|
||||
void handleAxisEvent(uint32_t axis, float x, float y, bool left);
|
||||
void handlePoseEvent(const mat4& mat, bool left);
|
||||
|
||||
int _trackedControllers;
|
||||
|
||||
|
|
|
@ -28,7 +28,9 @@
|
|||
#include <udt/PacketHeaders.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "AnimationObject.h"
|
||||
#include <controllers/ScriptingInterface.h>
|
||||
#include <AnimationObject.h>
|
||||
|
||||
#include "ArrayBufferViewClass.h"
|
||||
#include "BatchLoader.h"
|
||||
#include "DataViewClass.h"
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
#include <LimitedNodeList.h>
|
||||
#include <EntityItemID.h>
|
||||
#include <EntitiesScriptEngineProvider.h>
|
||||
#include <controllers/ScriptingInterface.h>
|
||||
|
||||
|
||||
#include "MouseEvent.h"
|
||||
#include "ArrayBufferClass.h"
|
||||
|
|
|
@ -123,20 +123,20 @@ int main(int argc, char** argv) {
|
|||
inputPlugin->pluginUpdate(delta, false);
|
||||
}
|
||||
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->update(delta);
|
||||
});
|
||||
timer.start(50);
|
||||
|
||||
{
|
||||
DependencyManager::set<UserInputMapper>();
|
||||
DependencyManager::set<controller::UserInputMapper>();
|
||||
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
|
||||
QString name = inputPlugin->getName();
|
||||
inputPlugin->activate();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
if (name == KeyboardMouseDevice::NAME) {
|
||||
auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
|
||||
keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
|
||||
userInputMapper->registerDevice(keyboardMouseDevice);
|
||||
}
|
||||
inputPlugin->pluginUpdate(0, false);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue