mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Update hydra mappings and test code
This commit is contained in:
parent
1dcf03d61e
commit
db0fa6b8ed
15 changed files with 321 additions and 200 deletions
30
examples/tests/controllerInterfaceTest.js
Normal file
30
examples/tests/controllerInterfaceTest.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
ControllerTest = function() {
|
||||
|
||||
print("Actions");
|
||||
for (var prop in Controller.Actions) {
|
||||
print("\t" + prop);
|
||||
}
|
||||
print("Standard");
|
||||
for (var prop in Controller.Standard) {
|
||||
print("\t" + prop);
|
||||
}
|
||||
print("Hardware");
|
||||
for (var prop in Controller.Hardware) {
|
||||
print("\t" + prop);
|
||||
for (var prop2 in Controller.Hardware[prop]) {
|
||||
print("\t\t" + prop2);
|
||||
}
|
||||
}
|
||||
print("Done");
|
||||
|
||||
var that = this;
|
||||
Script.scriptEnding.connect(function() {
|
||||
that.onCleanup();
|
||||
});
|
||||
}
|
||||
|
||||
ControllerTest.prototype.onCleanup = function() {
|
||||
}
|
||||
|
||||
|
||||
new ControllerTest();
|
28
interface/resources/controllers/hydra.json
Normal file
28
interface/resources/controllers/hydra.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "Hydra to Standard",
|
||||
"channels": [
|
||||
{ "from": "Hydra.LY", "to": "Standard.LY" },
|
||||
{ "from": "Hydra.LX", "to": "Standard.LX" },
|
||||
{ "from": "Hydra.LT", "to": "Standard.LT" },
|
||||
{ "from": "Hydra.RY", "to": "Standard.RY" },
|
||||
{ "from": "Hydra.RX", "to": "Standard.RX" },
|
||||
{ "from": "Hydra.RT", "to": "Standard.RT" },
|
||||
|
||||
{ "from": "Hydra.LB", "to": "Standard.LB" },
|
||||
{ "from": "Hydra.LS", "to": "Standard.LS" },
|
||||
{ "from": "Hydra.RB", "to": "Standard.RB" },
|
||||
{ "from": "Hydra.RS", "to": "Standard.RS" },
|
||||
|
||||
{ "from": "Hydra.L0", "to": "Standard.Back" },
|
||||
{ "from": "Hydra.L1", "to": "Standard.DL" },
|
||||
{ "from": "Hydra.L2", "to": "Standard.DD" },
|
||||
{ "from": "Hydra.L3", "to": "Standard.DR" },
|
||||
{ "from": "Hydra.L4", "to": "Standard.DU" },
|
||||
|
||||
{ "from": "Hydra.R0", "to": "Standard.Start" },
|
||||
{ "from": "Hydra.R1", "to": "Standard.X" },
|
||||
{ "from": "Hydra.R2", "to": "Standard.A" },
|
||||
{ "from": "Hydra.R3", "to": "Standard.B" },
|
||||
{ "from": "Hydra.R4", "to": "Standard.Y" }
|
||||
]
|
||||
}
|
29
interface/resources/controllers/xbox.json
Normal file
29
interface/resources/controllers/xbox.json
Normal file
|
@ -0,0 +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": "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": "XBox.Back", "to": "Standard.Back" },
|
||||
{ "from": "XBox.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": "XBox.A", "to": "Standard.A" },
|
||||
{ "from": "XBox.B", "to": "Standard.B" },
|
||||
{ "from": "XBox.X", "to": "Standard.X" },
|
||||
{ "from": "XBox.Y", "to": "Standard.Y" }
|
||||
]
|
||||
}
|
|
@ -143,22 +143,3 @@ void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
|
|||
mapper.registerDevice(_deviceID, proxy);
|
||||
}
|
||||
|
||||
void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
#ifdef HAVE_SDL2
|
||||
const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
const float DPAD_MOVE_SPEED = 0.5f;
|
||||
const float JOYSTICK_YAW_SPEED = 0.5f;
|
||||
const float JOYSTICK_PITCH_SPEED = 0.25f;
|
||||
const float BOOM_SPEED = 0.1f;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
UserInputMapper::Input Joystick::makeInput(controller::StandardButtonChannel button) {
|
||||
return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
UserInputMapper::Input Joystick::makeInput(controller::StandardAxisChannel axis) {
|
||||
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,16 +37,12 @@ public:
|
|||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
Joystick() : InputDevice("Joystick") {}
|
||||
~Joystick();
|
||||
|
||||
UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
|
||||
UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
|
||||
#endif
|
||||
|
|
|
@ -123,6 +123,8 @@ void SixenseManager::activate() {
|
|||
loadSettings();
|
||||
sixenseInit();
|
||||
_activated = true;
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
registerToUserInputMapper(*userInputMapper);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -176,23 +178,13 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
|
|||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
|
||||
if (sixenseGetNumActiveControllers() == 0) {
|
||||
if (_hydrasConnected) {
|
||||
qCDebug(inputplugins, "hydra disconnected");
|
||||
}
|
||||
_hydrasConnected = false;
|
||||
if (_deviceID != 0) {
|
||||
userInputMapper->removeDevice(_deviceID);
|
||||
_deviceID = 0;
|
||||
_poseStateMap.clear();
|
||||
}
|
||||
_poseStateMap.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
PerformanceTimer perfTimer("sixense");
|
||||
if (!_hydrasConnected) {
|
||||
_hydrasConnected = true;
|
||||
registerToUserInputMapper(*userInputMapper);
|
||||
assignDefaultInputMapping(*userInputMapper);
|
||||
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
|
||||
}
|
||||
|
||||
|
@ -226,12 +218,15 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
|
|||
// NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters.
|
||||
glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]);
|
||||
position *= METERS_PER_MILLIMETER;
|
||||
|
||||
bool left = i == 0;
|
||||
using namespace controller;
|
||||
// Check to see if this hand/controller is on the base
|
||||
const float CONTROLLER_AT_BASE_DISTANCE = 0.075f;
|
||||
if (glm::length(position) >= CONTROLLER_AT_BASE_DISTANCE) {
|
||||
handleButtonEvent(data->buttons, numActiveControllers - 1);
|
||||
handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1);
|
||||
handleButtonEvent(data->buttons, left);
|
||||
_axisStateMap[left ? LX : RX] = data->joystick_x;
|
||||
_axisStateMap[left ? LY : RY] = data->joystick_y;
|
||||
_axisStateMap[left ? LT : RT] = data->trigger;
|
||||
|
||||
if (!jointsCaptured) {
|
||||
// Rotation of Palm
|
||||
|
@ -241,13 +236,8 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
|
|||
_poseStateMap.clear();
|
||||
}
|
||||
} else {
|
||||
_poseStateMap[(numActiveControllers - 1) == 0 ? LEFT_HAND : RIGHT_HAND] = UserInputMapper::PoseValue();
|
||||
_poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = UserInputMapper::PoseValue();
|
||||
}
|
||||
|
||||
// // Read controller buttons and joystick into the hand
|
||||
// palm->setControllerButtons(data->buttons);
|
||||
// palm->setTrigger(data->trigger);
|
||||
// palm->setJoystick(data->joystick_x, data->joystick_y);
|
||||
}
|
||||
|
||||
if (numActiveControllers == 2) {
|
||||
|
@ -367,39 +357,35 @@ void SixenseManager::focusOutEvent() {
|
|||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
void SixenseManager::handleAxisEvent(float stickX, float stickY, float trigger, int index) {
|
||||
_axisStateMap[makeInput(AXIS_Y_POS, index).getChannel()] = (stickY > 0.0f) ? stickY : 0.0f;
|
||||
_axisStateMap[makeInput(AXIS_Y_NEG, index).getChannel()] = (stickY < 0.0f) ? -stickY : 0.0f;
|
||||
_axisStateMap[makeInput(AXIS_X_POS, index).getChannel()] = (stickX > 0.0f) ? stickX : 0.0f;
|
||||
_axisStateMap[makeInput(AXIS_X_NEG, index).getChannel()] = (stickX < 0.0f) ? -stickX : 0.0f;
|
||||
_axisStateMap[makeInput(BACK_TRIGGER, index).getChannel()] = trigger;
|
||||
void SixenseManager::handleAxisEvent(float stickX, float stickY, float trigger, bool left) {
|
||||
}
|
||||
|
||||
void SixenseManager::handleButtonEvent(unsigned int buttons, int index) {
|
||||
void SixenseManager::handleButtonEvent(unsigned int buttons, bool left) {
|
||||
using namespace controller;
|
||||
if (buttons & BUTTON_0) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_0, index).getChannel());
|
||||
_buttonPressedMap.insert(left ? BACK : START);
|
||||
}
|
||||
if (buttons & BUTTON_1) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_1, index).getChannel());
|
||||
_buttonPressedMap.insert(left ? DL : X);
|
||||
}
|
||||
if (buttons & BUTTON_2) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_2, index).getChannel());
|
||||
_buttonPressedMap.insert(left ? DD : A);
|
||||
}
|
||||
if (buttons & BUTTON_3) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_3, index).getChannel());
|
||||
_buttonPressedMap.insert(left ? DR : B);
|
||||
}
|
||||
if (buttons & BUTTON_4) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_4, index).getChannel());
|
||||
_buttonPressedMap.insert(left ? DU : Y);
|
||||
}
|
||||
if (buttons & BUTTON_FWD) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_FWD, index).getChannel());
|
||||
_buttonPressedMap.insert(left ? LB : RB);
|
||||
}
|
||||
if (buttons & BUTTON_TRIGGER) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_TRIGGER, index).getChannel());
|
||||
_buttonPressedMap.insert(left ? LS : RS);
|
||||
}
|
||||
}
|
||||
|
||||
void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int index) {
|
||||
void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, bool left) {
|
||||
#ifdef HAVE_SIXENSE
|
||||
// From ABOVE the sixense coordinate frame looks like this:
|
||||
//
|
||||
|
@ -443,7 +429,7 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int
|
|||
// In addition to Qsh each hand has pre-offset introduced by the shape of the sixense controllers
|
||||
// and how they fit into the hand in their relaxed state. This offset is a quarter turn about
|
||||
// the sixense's z-axis, with its direction different for the two hands:
|
||||
float sign = (index == 0) ? 1.0f : -1.0f;
|
||||
float sign = left ? 1.0f : -1.0f;
|
||||
const glm::quat preOffset = glm::angleAxis(sign * PI / 2.0f, Vectors::UNIT_Z);
|
||||
|
||||
// Finally, there is a post-offset (same for both hands) to get the hand's rest orientation
|
||||
|
@ -458,104 +444,46 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int
|
|||
// TODO: find a shortcut with fewer rotations.
|
||||
rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand;
|
||||
|
||||
_poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation);
|
||||
_poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] =
|
||||
UserInputMapper::PoseValue(position, rotation);
|
||||
#endif // HAVE_SIXENSE
|
||||
}
|
||||
|
||||
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()); };
|
||||
proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
|
||||
using namespace controller;
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<UserInputMapper::InputPair> {
|
||||
QVector<UserInputMapper::InputPair> availableInputs;
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_0, 0), "Left Start"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_1, 0), "Left Button 1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_2, 0), "Left Button 2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_3, 0), "Left Button 3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_4, 0), "Left Button 4"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_FWD, 0), "L1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 0), "L2"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 0), "Left Stick Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 0), "Left Stick Down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 0), "Left Stick Right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 0), "Left Stick Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_TRIGGER, 0), "Left Trigger Press"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_0, 1), "Right Start"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_1, 1), "Right Button 1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_2, 1), "Right Button 2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_3, 1), "Right Button 3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_4, 1), "Right Button 4"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_FWD, 1), "R1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 1), "R2"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 1), "Right Stick Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 1), "Right Stick Down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 1), "Right Stick Right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 1), "Right Stick Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_TRIGGER, 1), "Right Trigger Press"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BACK), "L0"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(DL), "L1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(DD), "L2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(DR), "L3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(DU), "L4"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LB), "LB"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LS), "LS"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LX), "LX"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LY), "LY"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LT), "LT"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(START), "R0"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(X), "R1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(A), "R2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(B), "R3"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(Y), "R4"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(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"));
|
||||
return availableInputs;
|
||||
};
|
||||
proxy->resetDeviceBindings = [this, &mapper] () -> bool {
|
||||
mapper.removeAllInputChannelsForDevice(_deviceID);
|
||||
this->assignDefaultInputMapping(mapper);
|
||||
return true;
|
||||
};
|
||||
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;
|
||||
|
||||
// Left Joystick: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(AXIS_X_POS, 0), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(AXIS_X_NEG, 0), JOYSTICK_MOVE_SPEED);
|
||||
|
||||
// Right Joystick: Camera orientation
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(AXIS_X_POS, 1), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(AXIS_X_NEG, 1), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(AXIS_Y_POS, 1), JOYSTICK_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(AXIS_Y_NEG, 1), JOYSTICK_PITCH_SPEED);
|
||||
|
||||
// Buttons
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_3, 0), BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_1, 0), BOOM_SPEED);
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(BUTTON_3, 1), BUTTON_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(BUTTON_1, 1), BUTTON_MOVE_SPEED);
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_2, 0));
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_2, 1));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(BUTTON_4, 0));
|
||||
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(BUTTON_4, 1));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
|
||||
mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0));
|
||||
mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1));
|
||||
|
||||
// TODO find a mechanism to allow users to navigate the context menu via
|
||||
mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(BUTTON_0, 0));
|
||||
mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(BUTTON_0, 1));
|
||||
|
||||
}
|
||||
|
||||
// virtual
|
||||
void SixenseManager::saveSettings() const {
|
||||
Settings settings;
|
||||
|
@ -580,15 +508,3 @@ void SixenseManager::loadSettings() {
|
|||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
UserInputMapper::Input SixenseManager::makeInput(unsigned int button, int index) {
|
||||
return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
UserInputMapper::Input SixenseManager::makeInput(SixenseManager::JoystickAxisChannel axis, int index) {
|
||||
return UserInputMapper::Input(_deviceID, axis | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
UserInputMapper::Input SixenseManager::makeInput(JointChannel joint) {
|
||||
return UserInputMapper::Input(_deviceID, joint, UserInputMapper::ChannelType::POSE);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#endif
|
||||
|
||||
#include <controllers/InputDevice.h>
|
||||
#include <controllers/StandardControls.h>
|
||||
|
||||
#include "InputPlugin.h"
|
||||
|
||||
|
@ -44,19 +45,6 @@ const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
|
|||
class SixenseManager : public InputPlugin, public InputDevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum JoystickAxisChannel {
|
||||
AXIS_Y_POS = 1U << 0,
|
||||
AXIS_Y_NEG = 1U << 3,
|
||||
AXIS_X_POS = 1U << 4,
|
||||
AXIS_X_NEG = 1U << 5,
|
||||
BACK_TRIGGER = 1U << 6,
|
||||
};
|
||||
|
||||
enum JointChannel {
|
||||
LEFT_HAND = 0,
|
||||
RIGHT_HAND,
|
||||
};
|
||||
|
||||
SixenseManager();
|
||||
|
||||
// Plugin functions
|
||||
|
@ -73,14 +61,9 @@ public:
|
|||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
UserInputMapper::Input makeInput(unsigned int button, int index);
|
||||
UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index);
|
||||
UserInputMapper::Input makeInput(JointChannel joint);
|
||||
|
||||
virtual void saveSettings() const override;
|
||||
virtual void loadSettings() override;
|
||||
|
||||
|
@ -88,9 +71,9 @@ public slots:
|
|||
void setSixenseFilter(bool filter);
|
||||
|
||||
private:
|
||||
void handleButtonEvent(unsigned int buttons, int index);
|
||||
void handleAxisEvent(float x, float y, float trigger, int index);
|
||||
void handlePoseEvent(glm::vec3 position, glm::quat rotation, int index);
|
||||
void handleButtonEvent(unsigned int buttons, bool left);
|
||||
void handleAxisEvent(float x, float y, float trigger, bool left);
|
||||
void handlePoseEvent(glm::vec3 position, glm::quat rotation, bool left);
|
||||
|
||||
void updateCalibration(void* controllers);
|
||||
|
||||
|
|
35
tests/controllers/qml/Hydra.qml
Normal file
35
tests/controllers/qml/Hydra.qml
Normal file
|
@ -0,0 +1,35 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import "./hydra"
|
||||
import "./controls"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 480
|
||||
height: width * 3.0 / 4.0
|
||||
property var device
|
||||
property real scale: width / 480
|
||||
property real rightOffset: (width / 2) * scale
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: "hydra/hydra.png"
|
||||
|
||||
HydraStick {
|
||||
leftStick: true
|
||||
scale: root.scale
|
||||
device: root.device
|
||||
}
|
||||
|
||||
|
||||
HydraStick {
|
||||
leftStick: false
|
||||
scale: root.scale
|
||||
device: root.device
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -8,14 +8,20 @@ import "./controls"
|
|||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property real aspect: 300.0 / 215.0
|
||||
width: 300
|
||||
height: width / aspect
|
||||
property var device
|
||||
|
||||
property real scale: 1.0
|
||||
width: 300 * scale
|
||||
height: 215 * scale
|
||||
property string label: ""
|
||||
property real scale: width / 300.0
|
||||
|
||||
Image {
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
text: root.label
|
||||
visible: root.label != ""
|
||||
}
|
||||
anchors.fill: parent
|
||||
source: "xbox/xbox360-controller-md.png"
|
||||
|
||||
|
|
|
@ -10,16 +10,24 @@ Column {
|
|||
id: root
|
||||
property var actions: Controllers.Actions
|
||||
property var standard: Controllers.Standard
|
||||
property var hydra: null
|
||||
property var testMapping: null
|
||||
property var xbox: null
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
var patt = /^X360Controller/;
|
||||
var xboxRegex = /^X360Controller/;
|
||||
var hydraRegex = /^Hydra/;
|
||||
for (var prop in Controllers.Hardware) {
|
||||
if(patt.test(prop)) {
|
||||
if(xboxRegex.test(prop)) {
|
||||
root.xbox = Controllers.Hardware[prop]
|
||||
break
|
||||
print("found xbox")
|
||||
continue
|
||||
}
|
||||
if (hydraRegex.test(prop)) {
|
||||
root.hydra = Controllers.Hardware[prop]
|
||||
print("found hydra")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,23 +87,15 @@ Column {
|
|||
mapping.join(standard.LB, standard.RB).to(actions.Yaw);
|
||||
mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT);
|
||||
mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT);
|
||||
|
||||
// mapping.modifier(keyboard.Ctrl).scale(2.0)
|
||||
|
||||
// mapping.from(keyboard.A).to(actions.TranslateLeft)
|
||||
// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
|
||||
// mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft)
|
||||
|
||||
// // First loopbacks
|
||||
// // Then non-loopbacks by constraint level (number of inputs)
|
||||
// mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX)
|
||||
|
||||
// mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft)
|
||||
|
||||
|
||||
// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft)
|
||||
|
||||
|
||||
// mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward)
|
||||
testMapping = mapping;
|
||||
enabled = false
|
||||
|
@ -114,12 +114,19 @@ Column {
|
|||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Xbox { device: root.standard; label: "Standard"; width: 360 }
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 8
|
||||
Xbox { device: root.xbox }
|
||||
Xbox { device: root.standard }
|
||||
Xbox { device: root.xbox; label: "XBox"; width: 360 }
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 8
|
||||
Hydra { device: root.hydra; width: 360 }
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 8
|
||||
|
|
|
@ -8,6 +8,8 @@ Item {
|
|||
property int size: 64
|
||||
width: size
|
||||
height: size
|
||||
property bool invertY: false
|
||||
|
||||
|
||||
property int halfSize: size / 2
|
||||
property var controlIds: [ 0, 0 ]
|
||||
|
@ -18,6 +20,9 @@ Item {
|
|||
Controllers.getValue(controlIds[0]),
|
||||
Controllers.getValue(controlIds[1])
|
||||
);
|
||||
if (root.invertY) {
|
||||
value.y = value.y * -1.0
|
||||
}
|
||||
canvas.requestPaint();
|
||||
}
|
||||
|
||||
|
|
18
tests/controllers/qml/hydra/HydraButtons.qml
Normal file
18
tests/controllers/qml/hydra/HydraButtons.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import "./../controls"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 72 * scale
|
||||
height: 48 * scale
|
||||
property var device
|
||||
property real scale: 1.0
|
||||
property bool leftStick: true
|
||||
|
||||
}
|
||||
|
||||
|
91
tests/controllers/qml/hydra/HydraStick.qml
Normal file
91
tests/controllers/qml/hydra/HydraStick.qml
Normal file
|
@ -0,0 +1,91 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import "./../controls"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property var device
|
||||
property real scale: 1.0
|
||||
property bool leftStick: true
|
||||
width: parent.width / 2; height: parent.height
|
||||
x: leftStick ? 0 : parent.width / 2
|
||||
|
||||
Text {
|
||||
x: parent.width / 2 - width / 2; y: parent.height / 2 - height / 2
|
||||
text: root.leftStick ? "L" : "R"
|
||||
color: 'green'
|
||||
}
|
||||
|
||||
// Analog Stick
|
||||
AnalogStick {
|
||||
size: 64 * root.scale
|
||||
x: 127 * root.scale - width / 2; y: 45 * root.scale - width / 2; z: 100
|
||||
invertY: true
|
||||
controlIds: [
|
||||
root.leftStick ? root.device.LX : root.device.RX,
|
||||
root.leftStick ? root.device.LY : root.device.RY
|
||||
]
|
||||
}
|
||||
|
||||
// Stick press
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.LS : root.device.RS
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 127 * root.scale - width / 2; y: 45 * root.scale - width / 2;
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
// Trigger
|
||||
AnalogButton {
|
||||
controlId: root.leftStick ? root.device.LT : root.device.RT
|
||||
width: 8 * root.scale ; height: 64 * root.scale
|
||||
y: 24 * root.scale
|
||||
x: root.leftStick ? (48 * root.scale) : root.width - (48 * root.scale) - width / 2
|
||||
}
|
||||
|
||||
// Bumper
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.LB : root.device.RB
|
||||
height: 16 * root.scale; width: 32 * root.scale
|
||||
x: 128 * root.scale - width / 2; y: 24 * root.scale
|
||||
color: 'red'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L0 : root.device.R0
|
||||
height: 16 * root.scale; width: 4 * root.scale
|
||||
x: 128 * root.scale - width / 2; y: 109 * root.scale
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L1 : root.device.R1
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 103 * root.scale - width / 2; y: 100 * root.scale - height / 2
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L2 : root.device.R2
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 148 * root.scale - width / 2; y: 100 * root.scale - height / 2
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L3 : root.device.R3
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 97 * root.scale - width / 2; y: 76 * root.scale - height / 2
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L4 : root.device.R4
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 155 * root.scale - width / 2; y: 76 * root.scale - height / 2
|
||||
color: 'yellow'
|
||||
}
|
||||
}
|
BIN
tests/controllers/qml/hydra/hydra.png
Normal file
BIN
tests/controllers/qml/hydra/hydra.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
|
@ -88,14 +88,9 @@ public:
|
|||
int main(int argc, char** argv) {
|
||||
QGuiApplication app(argc, argv);
|
||||
QQmlApplicationEngine engine;
|
||||
for (auto path : qApp->libraryPaths()) {
|
||||
qDebug() << path;
|
||||
}
|
||||
|
||||
for (auto path : qApp->libraryPaths()) {
|
||||
qDebug() << path;
|
||||
}
|
||||
new PluginContainerProxy();
|
||||
|
||||
// Simulate our application idle loop
|
||||
QTimer timer;
|
||||
QObject::connect(&timer, &QTimer::timeout, [] {
|
||||
static float last = secTimestampNow();
|
||||
|
@ -122,11 +117,12 @@ int main(int argc, char** argv) {
|
|||
auto keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
|
||||
keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
|
||||
}
|
||||
inputPlugin->pluginUpdate(0, false);
|
||||
}
|
||||
//new PluginContainerProxy();
|
||||
auto rootContext = engine.rootContext();
|
||||
rootContext->setContextProperty("Controllers", new MyControllerScriptingInterface());
|
||||
}
|
||||
|
||||
engine.load(getQmlDir() + "main.qml");
|
||||
app.exec();
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue