mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 09:44:21 +02:00
userinputmapper supports hydra, but some hydra events still register as mouse events
This commit is contained in:
parent
b4e108cd3b
commit
1a8df6509f
5 changed files with 189 additions and 5 deletions
|
@ -1456,6 +1456,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
|
|||
|
||||
void Application::focusOutEvent(QFocusEvent* event) {
|
||||
_keyboardMouseDevice.focusOutEvent(event);
|
||||
SixenseManager::getInstance().focusOutEvent();
|
||||
SDL2Manager::getInstance()->focusOutEvent();
|
||||
|
||||
// synthesize events for keys currently pressed, since we may not get their release events
|
||||
|
|
|
@ -82,6 +82,8 @@ void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
|
|||
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
||||
_axisStateMap[makeInput(LEFT_SHOULDER).getChannel()] = event.value / MAX_AXIS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,8 +104,8 @@ void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
|
|||
_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._channel); };
|
||||
proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input._channel); };
|
||||
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;
|
||||
#ifdef HAVE_SDL2
|
||||
|
|
|
@ -160,8 +160,8 @@ void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) {
|
|||
_deviceID = mapper.getFreeDeviceID();
|
||||
|
||||
auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("Keyboard"));
|
||||
proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input._channel); };
|
||||
proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input._channel); };
|
||||
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;
|
||||
for (int i = (int) Qt::Key_0; i <= (int) Qt::Key_9; i++) {
|
||||
|
|
|
@ -38,6 +38,10 @@ typedef int (*SixenseTakeIntFunction)(int);
|
|||
typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData*);
|
||||
#endif
|
||||
|
||||
// These bits aren't used for buttons, so they can be used as masks:
|
||||
const unsigned int LEFT_MASK = 0;
|
||||
const unsigned int RIGHT_MASK = 1U << 1;
|
||||
|
||||
#endif
|
||||
|
||||
SixenseManager& SixenseManager::getInstance() {
|
||||
|
@ -147,6 +151,7 @@ void SixenseManager::update(float deltaTime) {
|
|||
#ifdef HAVE_SIXENSE
|
||||
Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
|
||||
if (_isInitialized && _isEnabled) {
|
||||
_buttonPressedMap.clear();
|
||||
#ifdef __APPLE__
|
||||
SixenseBaseFunction sixenseGetNumActiveControllers =
|
||||
(SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");
|
||||
|
@ -154,12 +159,18 @@ void SixenseManager::update(float deltaTime) {
|
|||
|
||||
if (sixenseGetNumActiveControllers() == 0) {
|
||||
_hydrasConnected = false;
|
||||
if (_deviceID) {
|
||||
Application::getUserInputMapper()->removeDevice(_deviceID);
|
||||
_deviceID = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
PerformanceTimer perfTimer("sixense");
|
||||
if (!_hydrasConnected) {
|
||||
_hydrasConnected = true;
|
||||
registerToUserInputMapper(*Application::getUserInputMapper());
|
||||
getInstance().assignDefaultInputMapping(*Application::getUserInputMapper());
|
||||
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
|
||||
}
|
||||
|
||||
|
@ -216,12 +227,14 @@ void SixenseManager::update(float deltaTime) {
|
|||
palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive
|
||||
}
|
||||
|
||||
|
||||
// Read controller buttons and joystick into the hand
|
||||
palm->setControllerButtons(data->buttons);
|
||||
palm->setTrigger(data->trigger);
|
||||
palm->setJoystick(data->joystick_x, data->joystick_y);
|
||||
|
||||
handleButtonEvent(data->buttons, numActiveControllers - 1);
|
||||
handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1);
|
||||
|
||||
// Emulate the mouse so we can use scripts
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) {
|
||||
emulateMouse(palm, numActiveControllers - 1);
|
||||
|
@ -590,3 +603,137 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
|||
|
||||
#endif // HAVE_SIXENSE
|
||||
|
||||
void SixenseManager::focusOutEvent() {
|
||||
_axisStateMap.clear();
|
||||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
void SixenseManager::handleAxisEvent(float stickX, float stickY, float trigger, int index) {
|
||||
_axisStateMap[makeInput(AXIS_Y_POS, index).getChannel()] = (stickY > 0) ? stickY : 0.0f;
|
||||
_axisStateMap[makeInput(AXIS_Y_NEG, index).getChannel()] = (stickY < 0) ? -stickY : 0.0f;
|
||||
_axisStateMap[makeInput(AXIS_X_POS, index).getChannel()] = (stickX > 0) ? stickX : 0.0f;
|
||||
_axisStateMap[makeInput(AXIS_X_NEG, index).getChannel()] = (stickX < 0) ? -stickX : 0.0f;
|
||||
_axisStateMap[makeInput(BACK_TRIGGER, index).getChannel()] = trigger;
|
||||
}
|
||||
|
||||
void SixenseManager::handleButtonEvent(unsigned int buttons, int index) {
|
||||
if (buttons & BUTTON_0) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_0, index).getChannel());
|
||||
}
|
||||
if (buttons & BUTTON_1) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_1, index).getChannel());
|
||||
}
|
||||
if (buttons & BUTTON_2) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_2, index).getChannel());
|
||||
}
|
||||
if (buttons & BUTTON_3) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_3, index).getChannel());
|
||||
}
|
||||
if (buttons & BUTTON_4) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_4, index).getChannel());
|
||||
}
|
||||
if (buttons & BUTTON_FWD) {
|
||||
_buttonPressedMap.insert(makeInput(BUTTON_FWD, index).getChannel());
|
||||
}
|
||||
}
|
||||
|
||||
void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||
// Grab the current free device ID
|
||||
_deviceID = mapper.getFreeDeviceID();
|
||||
|
||||
auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("Hydra"));
|
||||
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_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_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"));
|
||||
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 = .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);
|
||||
}
|
||||
|
||||
float SixenseManager::getButton(int channel) const {
|
||||
if (!_buttonPressedMap.empty()) {
|
||||
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
|
||||
return 1.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float SixenseManager::getAxis(int channel) const {
|
||||
auto axis = _axisStateMap.find(channel);
|
||||
if (axis != _axisStateMap.end()) {
|
||||
return (*axis).second;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_SixenseManager_h
|
||||
|
||||
#include <QObject>
|
||||
#include <unordered_set>
|
||||
|
||||
#ifdef HAVE_SIXENSE
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -25,6 +26,8 @@
|
|||
|
||||
#endif
|
||||
|
||||
#include "ui/UserInputMapper.h"
|
||||
|
||||
class PalmData;
|
||||
|
||||
const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2
|
||||
|
@ -45,6 +48,14 @@ const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
|
|||
class SixenseManager : public QObject {
|
||||
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,
|
||||
};
|
||||
|
||||
static SixenseManager& getInstance();
|
||||
|
||||
void initialize();
|
||||
|
@ -60,6 +71,21 @@ public:
|
|||
bool getInvertButtons() const { return _invertButtons; }
|
||||
void setInvertButtons(bool invertSixenseButtons) { _invertButtons = invertSixenseButtons; }
|
||||
|
||||
typedef std::unordered_set<int> ButtonPressedMap;
|
||||
typedef std::map<int, float> AxisStateMap;
|
||||
|
||||
float getButton(int channel) const;
|
||||
float getAxis(int channel) const;
|
||||
|
||||
UserInputMapper::Input makeInput(unsigned int button, int index);
|
||||
UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index);
|
||||
|
||||
void registerToUserInputMapper(UserInputMapper& mapper);
|
||||
void assignDefaultInputMapping(UserInputMapper& mapper);
|
||||
|
||||
void update();
|
||||
void focusOutEvent();
|
||||
|
||||
public slots:
|
||||
void toggleSixense(bool shouldEnable);
|
||||
void setFilter(bool filter);
|
||||
|
@ -70,6 +96,8 @@ private:
|
|||
~SixenseManager();
|
||||
|
||||
#ifdef HAVE_SIXENSE
|
||||
void handleButtonEvent(unsigned int buttons, int index);
|
||||
void handleAxisEvent(float x, float y, float trigger, int index);
|
||||
void updateCalibration(const sixenseControllerData* controllers);
|
||||
void emulateMouse(PalmData* palm, int index);
|
||||
|
||||
|
@ -110,6 +138,12 @@ private:
|
|||
|
||||
float _reticleMoveSpeed = DEFAULT_SIXENSE_RETICLE_MOVE_SPEED;
|
||||
bool _invertButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS;
|
||||
|
||||
protected:
|
||||
int _deviceID = 0;
|
||||
|
||||
ButtonPressedMap _buttonPressedMap;
|
||||
AxisStateMap _axisStateMap;
|
||||
};
|
||||
|
||||
#endif // hifi_SixenseManager_h
|
||||
|
|
Loading…
Reference in a new issue