input plugin architecture, fixed sixense

This commit is contained in:
Anthony J. Thibault 2015-07-15 18:50:44 -07:00
parent fb62fda2d2
commit 56e7af081e
23 changed files with 344 additions and 326 deletions

View file

@ -2,7 +2,7 @@ set(TARGET_NAME interface)
project(${TARGET_NAME}) project(${TARGET_NAME})
# set a default root dir for each of our optional externals if it was not passed # set a default root dir for each of our optional externals if it was not passed
set(OPTIONAL_EXTERNALS "Faceshift" "LeapMotion" "RtMidi" "SDL2" "RSSDK") set(OPTIONAL_EXTERNALS "Faceshift" "LeapMotion" "RtMidi" "RSSDK")
foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)

View file

@ -124,6 +124,7 @@
#include "devices/RealSense.h" #include "devices/RealSense.h"
#include "devices/MIDIManager.h" #include "devices/MIDIManager.h"
#include <input-plugins/SDL2Manager.h> #include <input-plugins/SDL2Manager.h>
#include <input-plugins/SixenseManager.h>
#include <input-plugins/ViveControllerManager.h> #include <input-plugins/ViveControllerManager.h>
#include "RenderDeferredTask.h" #include "RenderDeferredTask.h"
#include "scripting/AccountScriptingInterface.h" #include "scripting/AccountScriptingInterface.h"
@ -675,9 +676,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
connect(ddeTracker.data(), &FaceTracker::muteToggled, this, &Application::faceTrackerMuteToggled); connect(ddeTracker.data(), &FaceTracker::muteToggled, this, &Application::faceTrackerMuteToggled);
#endif #endif
ViveControllerManager::getInstance().init();
if (ViveControllerManager::getInstance().isSupported()) { if (ViveControllerManager::getInstance().isSupported()) {
ViveControllerManager::getInstance().activate(); ViveControllerManager::getInstance().init();
ViveControllerManager::getInstance().activate(NULL);
} }
_oldHandMouseX[0] = -1; _oldHandMouseX[0] = -1;
@ -1640,10 +1641,10 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
} }
void Application::focusOutEvent(QFocusEvent* event) { void Application::focusOutEvent(QFocusEvent* event) {
_keyboardMouseDevice.focusOutEvent(event); _keyboardMouseDevice.pluginFocusOutEvent();
SixenseManager::getInstance().focusOutEvent(); SixenseManager::getInstance().pluginFocusOutEvent();
SDL2Manager::getInstance()->focusOutEvent(); SDL2Manager::getInstance()->pluginFocusOutEvent();
ViveControllerManager::getInstance().focusOutEvent(); ViveControllerManager::getInstance().pluginFocusOutEvent();
// synthesize events for keys currently pressed, since we may not get their release events // synthesize events for keys currently pressed, since we may not get their release events
foreach (int key, _keysPressed) { foreach (int key, _keysPressed) {
@ -2615,15 +2616,16 @@ void Application::update(float deltaTime) {
_lastFaceTrackerUpdate = 0; _lastFaceTrackerUpdate = 0;
} }
SixenseManager::getInstance().update(deltaTime);
SDL2Manager::getInstance()->update();
ViveControllerManager::getInstance().update();
} }
auto userInputMapper = DependencyManager::get<UserInputMapper>(); auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->setSensorToWorldMat(_myAvatar->getSensorToWorldMatrix()); userInputMapper->setSensorToWorldMat(_myAvatar->getSensorToWorldMatrix());
userInputMapper->update(deltaTime); userInputMapper->update(deltaTime);
_keyboardMouseDevice.update();
_keyboardMouseDevice.pluginUpdate(deltaTime);
SixenseManager::getInstance().pluginUpdate(deltaTime);
SDL2Manager::getInstance()->pluginUpdate(deltaTime);
ViveControllerManager::getInstance().pluginUpdate(deltaTime);
// Dispatch input events // Dispatch input events
_controllerScriptingInterface.updateInputControllers(); _controllerScriptingInterface.updateInputControllers();
@ -3734,7 +3736,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
} }
renderArgs->_debugFlags = renderDebugFlags; renderArgs->_debugFlags = renderDebugFlags;
_entities.render(renderArgs); _entities.render(renderArgs);
ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges); //ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges);
} }
// render the ambient occlusion effect if enabled // render the ambient occlusion effect if enabled

View file

@ -54,7 +54,6 @@
#include "Stars.h" #include "Stars.h"
#include "avatar/Avatar.h" #include "avatar/Avatar.h"
#include "avatar/MyAvatar.h" #include "avatar/MyAvatar.h"
#include "devices/SixenseManager.h"
#include "scripting/ControllerScriptingInterface.h" #include "scripting/ControllerScriptingInterface.h"
#include "scripting/WebWindowClass.h" #include "scripting/WebWindowClass.h"
#include "ui/BandwidthDialog.h" #include "ui/BandwidthDialog.h"

View file

@ -30,7 +30,7 @@
#include "devices/DdeFaceTracker.h" #include "devices/DdeFaceTracker.h"
#include "devices/Faceshift.h" #include "devices/Faceshift.h"
#include "devices/RealSense.h" #include "devices/RealSense.h"
//#include "devices/SixenseManager.h" #include <input-plugins\SixenseManager.h> // TODO: should be able to remove this once input plugin architecture is finished
#include "MainWindow.h" #include "MainWindow.h"
#include "scripting/MenuScriptingInterface.h" #include "scripting/MenuScriptingInterface.h"
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) #if defined(Q_OS_MAC) || defined(Q_OS_WIN)

View file

@ -11,7 +11,9 @@
// //
#include "KeyboardMouseDevice.h" #include "KeyboardMouseDevice.h"
void KeyboardMouseDevice::update() { const QString KeyboardMouseDevice::NAME = "Keyboard";
void KeyboardMouseDevice::update(float deltaTime) {
_axisStateMap.clear(); _axisStateMap.clear();
// For touch event, we need to check that the last event is not too long ago // For touch event, we need to check that the last event is not too long ago
@ -27,7 +29,7 @@ void KeyboardMouseDevice::update() {
} }
} }
void KeyboardMouseDevice::focusOutEvent(QFocusEvent* event) { void KeyboardMouseDevice::focusOutEvent() {
_buttonPressedMap.clear(); _buttonPressedMap.clear();
}; };
@ -159,7 +161,7 @@ void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) {
// Grab the current free device ID // Grab the current free device ID
_deviceID = mapper.getFreeDeviceID(); _deviceID = mapper.getFreeDeviceID();
auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("Keyboard")); 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->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->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> { proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
@ -282,23 +284,3 @@ void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) {
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(Qt::Key_T)); mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(Qt::Key_T));
} }
float KeyboardMouseDevice::getButton(int channel) const {
if (!_buttonPressedMap.empty()) {
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
return 1.0f;
} else {
return 0.0f;
}
}
return 0.0f;
}
float KeyboardMouseDevice::getAxis(int channel) const {
auto axis = _axisStateMap.find(channel);
if (axis != _axisStateMap.end()) {
return (*axis).second;
} else {
return 0.0f;
}
}

View file

@ -14,11 +14,12 @@
#include <QTouchEvent> #include <QTouchEvent>
#include <chrono> #include <chrono>
#include <input-plugins/UserInputMapper.h> #include <input-plugins/InputDevice.h>
#include <input-plugins/InputPlugin.h>
class KeyboardMouseDevice { class KeyboardMouseDevice : public InputPlugin, public InputDevice {
Q_OBJECT
public: public:
enum KeyboardChannel { enum KeyboardChannel {
KEYBOARD_FIRST = 0, KEYBOARD_FIRST = 0,
KEYBOARD_LAST = 255, KEYBOARD_LAST = 255,
@ -53,10 +54,27 @@ public:
TOUCH_BUTTON_PRESS = TOUCH_AXIS_Y_NEG + 1, TOUCH_BUTTON_PRESS = TOUCH_AXIS_Y_NEG + 1,
}; };
typedef std::unordered_set<int> ButtonPressedMap; KeyboardMouseDevice() : InputDevice("Keyboard") {}
typedef std::map<int, float> AxisStateMap; // 8 axes
void focusOutEvent(QFocusEvent* event); // Plugin functions
virtual bool isSupported() const override { return true; }
virtual bool isHandController() const override { return false; }
const QString& getName() const { return NAME; }
virtual void init() override {};
virtual void deinit() override {};
virtual void activate(PluginContainer * container) override {};
virtual void deactivate() override {};
virtual void idle() override {};
virtual void pluginFocusOutEvent() override { focusOutEvent(); }
virtual void pluginUpdate(float deltaTime) override { update(deltaTime); }
// Device functions
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
virtual void update(float deltaTime) override;
virtual void focusOutEvent() override;
void keyPressEvent(QKeyEvent* event); void keyPressEvent(QKeyEvent* event);
void keyReleaseEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event);
@ -70,32 +88,15 @@ public:
void touchUpdateEvent(const QTouchEvent* event); void touchUpdateEvent(const QTouchEvent* event);
void wheelEvent(QWheelEvent* event); void wheelEvent(QWheelEvent* event);
// Get current state for each channels
float getButton(int channel) const;
float getAxis(int channel) const;
// Let's make it easy for Qt because we assume we love Qt forever // Let's make it easy for Qt because we assume we love Qt forever
UserInputMapper::Input makeInput(Qt::Key code); UserInputMapper::Input makeInput(Qt::Key code);
UserInputMapper::Input makeInput(Qt::MouseButton code); UserInputMapper::Input makeInput(Qt::MouseButton code);
UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis); UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis);
UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis); UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis);
UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button); UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button);
KeyboardMouseDevice() {}
void registerToUserInputMapper(UserInputMapper& mapper);
void assignDefaultInputMapping(UserInputMapper& mapper);
// Update call MUST be called once per simulation loop
// It takes care of updating the action states and deltas
void update();
protected: protected:
ButtonPressedMap _buttonPressedMap;
AxisStateMap _axisStateMap;
int _deviceID = 0;
QPoint _lastCursor; QPoint _lastCursor;
glm::vec2 _lastTouch; glm::vec2 _lastTouch;
bool _isTouching = false; bool _isTouching = false;
@ -103,6 +104,9 @@ protected:
glm::vec2 evalAverageTouchPoints(const QList<QTouchEvent::TouchPoint>& points) const; glm::vec2 evalAverageTouchPoints(const QList<QTouchEvent::TouchPoint>& points) const;
std::chrono::high_resolution_clock _clock; std::chrono::high_resolution_clock _clock;
std::chrono::high_resolution_clock::time_point _lastTouchTime; std::chrono::high_resolution_clock::time_point _lastTouchTime;
private:
static const QString NAME;
}; };
#endif // hifi_KeyboardMouseDevice_h #endif // hifi_KeyboardMouseDevice_h

View file

@ -16,9 +16,11 @@
#include "Application.h" #include "Application.h"
#include "devices/MotionTracker.h" #include "devices/MotionTracker.h"
//#include "devices/SixenseManager.h"
#include "ControllerScriptingInterface.h" #include "ControllerScriptingInterface.h"
// TODO: this needs to be removed, as well as any related controller-specific information
#include <input-plugins\SixenseManager.h>
ControllerScriptingInterface::ControllerScriptingInterface() : ControllerScriptingInterface::ControllerScriptingInterface() :
_mouseCaptured(false), _mouseCaptured(false),

View file

@ -22,6 +22,7 @@
#include "Tooltip.h" #include "Tooltip.h"
#include "Application.h" #include "Application.h"
#include <input-plugins\SixenseManager.h> // TODO: any references to sixense should be removed here
// Used to animate the magnification windows // Used to animate the magnification windows

View file

@ -15,7 +15,6 @@
#include <AudioClient.h> #include <AudioClient.h>
#include <avatar/AvatarManager.h> #include <avatar/AvatarManager.h>
#include <devices/Faceshift.h> #include <devices/Faceshift.h>
#include <devices/SixenseManager.h>
#include <NetworkingConstants.h> #include <NetworkingConstants.h>
#include "Application.h" #include "Application.h"

View file

@ -16,7 +16,7 @@
#include <avatar/AvatarManager.h> #include <avatar/AvatarManager.h>
#include <devices/DdeFaceTracker.h> #include <devices/DdeFaceTracker.h>
#include <devices/Faceshift.h> #include <devices/Faceshift.h>
#include <devices/SixenseManager.h> #include <input-plugins/SixenseManager.h> // TODO: This should be replaced with InputDevice/InputPlugin, or something similar
#include <NetworkingConstants.h> #include <NetworkingConstants.h>
#include "Application.h" #include "Application.h"

View file

@ -1,5 +1,15 @@
set(TARGET_NAME input-plugins) set(TARGET_NAME input-plugins)
# set a default root dir for each of our optional externals if it was not passed
set(OPTIONAL_EXTERNALS "SDL2" "Sixense")
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
string(TOLOWER ${EXTERNAL} ${EXTERNAL}_LOWERCASE)
set(${${EXTERNAL}_UPPERCASE}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${${EXTERNAL}_LOWERCASE}")
endif ()
endforeach()
setup_hifi_library() setup_hifi_library()
# use setup_hifi_library macro to setup our project and link appropriate Qt modules # use setup_hifi_library macro to setup our project and link appropriate Qt modules
@ -16,7 +26,45 @@ find_package(OpenVR REQUIRED)
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS}) target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES}) target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
add_dependency_external_projects(Sixense) #add_dependency_external_projects(Sixense)
find_package(Sixense REQUIRED) #find_package(Sixense REQUIRED)
target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) #target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) #target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES})
# perform standard include and linking for found externals
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
if (${${EXTERNAL}_UPPERCASE}_REQUIRED)
find_package(${EXTERNAL} REQUIRED)
else ()
find_package(${EXTERNAL})
endif ()
if (${${EXTERNAL}_UPPERCASE}_FOUND AND NOT DISABLE_${${EXTERNAL}_UPPERCASE})
add_definitions(-DHAVE_${${EXTERNAL}_UPPERCASE})
# include the library directories (ignoring warnings)
if (NOT ${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS)
set(${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIR})
endif ()
include_directories(SYSTEM ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
# perform the system include hack for OS X to ignore warnings
if (APPLE)
foreach(EXTERNAL_INCLUDE_DIR ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}")
endforeach()
endif ()
if (NOT ${${EXTERNAL}_UPPERCASE}_LIBRARIES)
set(${${EXTERNAL}_UPPERCASE}_LIBRARIES ${${${EXTERNAL}_UPPERCASE}_LIBRARY})
endif ()
if (NOT APPLE OR NOT ${${EXTERNAL}_UPPERCASE} MATCHES "SIXENSE")
target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES})
elseif (APPLE AND NOT INSTALLER_BUILD)
add_definitions(-DSIXENSE_LIB_FILENAME=\"${${${EXTERNAL}_UPPERCASE}_LIBRARY_RELEASE}\")
endif ()
endif ()
endforeach()

View file

@ -0,0 +1,40 @@
//
// Created by Sam Gondelman on 7/15/2015
// 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 "InputDevice.h"
float InputDevice::getButton(int channel) const {
if (!_buttonPressedMap.empty()) {
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
return 1.0f;
}
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;
}
else {
return 0.0f;
}
}
UserInputMapper::PoseValue InputDevice::getPose(int channel) const {
auto pose = _poseStateMap.find(channel);
if (pose != _poseStateMap.end()) {
return (*pose).second;
}
else {
return UserInputMapper::PoseValue();
}
}

View file

@ -0,0 +1,51 @@
//
// Created by Sam Gondelman on 7/15/2015
// 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
#include "UserInputMapper.h"
// Event types for each controller
const unsigned int CONTROLLER_0_EVENT = 1500U;
const unsigned int CONTROLLER_1_EVENT = 1501U;
// 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
class InputDevice {
public:
InputDevice::InputDevice(const QString& name) : _name(name) {}
typedef std::unordered_set<int> ButtonPressedMap;
typedef std::map<int, float> AxisStateMap;
typedef std::map<int, UserInputMapper::PoseValue> PoseStateMap;
// Get current state for each channel
float getButton(int channel) const;
float getAxis(int channel) const;
UserInputMapper::PoseValue getPose(int channel) const;
virtual void registerToUserInputMapper(UserInputMapper& mapper) = 0;
virtual void assignDefaultInputMapping(UserInputMapper& mapper) = 0;
// Update call MUST be called once per simulation loop
// It takes care of updating the action states and deltas
virtual void update(float deltaTime) = 0;
virtual void focusOutEvent() = 0;
int getDeviceID() { return _deviceID; }
protected:
int _deviceID = 0;
QString _name;
ButtonPressedMap _buttonPressedMap;
AxisStateMap _axisStateMap;
PoseStateMap _poseStateMap;
};

View file

@ -5,4 +5,4 @@
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "InputPlugin.h" #include "InputPlugin.h"

View file

@ -9,9 +9,14 @@
#include <plugins/Plugin.h> #include <plugins/Plugin.h>
const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
class InputPlugin : public Plugin { class InputPlugin : public Plugin {
Q_OBJECT
public: public:
virtual bool isHandController() = 0; virtual bool isHandController() const = 0;
virtual void pluginFocusOutEvent() = 0;
virtual void pluginUpdate(float deltaTime) = 0;
}; };

View file

@ -21,6 +21,7 @@ const float CONTROLLER_THRESHOLD = 0.3f;
const float MAX_AXIS = 32768.0f; const float MAX_AXIS = 32768.0f;
Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) : Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
InputDevice(name),
_sdlGameController(sdlGameController), _sdlGameController(sdlGameController),
_sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)), _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
_instanceId(instanceId) _instanceId(instanceId)
@ -40,7 +41,7 @@ void Joystick::closeJoystick() {
#endif #endif
} }
void Joystick::update() { void Joystick::update(float deltaTime) {
for (auto axisState : _axisStateMap) { for (auto axisState : _axisStateMap) {
if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
_axisStateMap[axisState.first] = 0.0f; _axisStateMap[axisState.first] = 0.0f;
@ -212,26 +213,6 @@ void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
#endif #endif
} }
float Joystick::getButton(int channel) const {
if (!_buttonPressedMap.empty()) {
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
return 1.0f;
} else {
return 0.0f;
}
}
return 0.0f;
}
float Joystick::getAxis(int channel) const {
auto axis = _axisStateMap.find(channel);
if (axis != _axisStateMap.end()) {
return (*axis).second;
} else {
return 0.0f;
}
}
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
UserInputMapper::Input Joystick::makeInput(SDL_GameControllerButton button) { UserInputMapper::Input Joystick::makeInput(SDL_GameControllerButton button) {
return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);

View file

@ -20,11 +20,10 @@
#undef main #undef main
#endif #endif
#include "UserInputMapper.h" #include "InputDevice.h"
class Joystick : public QObject { class Joystick : public QObject, InputDevice {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString name READ getName) Q_PROPERTY(QString name READ getName)
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
@ -44,27 +43,23 @@ public:
RIGHT_SHOULDER, RIGHT_SHOULDER,
LEFT_SHOULDER, LEFT_SHOULDER,
}; };
const QString& getName() const { return _name; }
// Device functions
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
virtual void update(float deltaTime) override;
virtual void focusOutEvent() override;
Joystick(); Joystick() : InputDevice("Joystick") {}
~Joystick(); ~Joystick();
typedef std::unordered_set<int> ButtonPressedMap;
typedef std::map<int, float> AxisStateMap;
float getButton(int channel) const;
float getAxis(int channel) const;
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
UserInputMapper::Input makeInput(SDL_GameControllerButton button); UserInputMapper::Input makeInput(SDL_GameControllerButton button);
#endif #endif
UserInputMapper::Input makeInput(Joystick::JoystickAxisChannel axis); UserInputMapper::Input makeInput(Joystick::JoystickAxisChannel axis);
void registerToUserInputMapper(UserInputMapper& mapper);
void assignDefaultInputMapping(UserInputMapper& mapper);
void update();
void focusOutEvent();
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController); Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController);
#endif #endif
@ -76,27 +71,16 @@ public:
void handleButtonEvent(const SDL_ControllerButtonEvent& event); void handleButtonEvent(const SDL_ControllerButtonEvent& event);
#endif #endif
const QString& getName() const { return _name; }
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
int getInstanceId() const { return _instanceId; } int getInstanceId() const { return _instanceId; }
#endif #endif
int getDeviceID() { return _deviceID; }
private: private:
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
SDL_GameController* _sdlGameController; SDL_GameController* _sdlGameController;
SDL_Joystick* _sdlJoystick; SDL_Joystick* _sdlJoystick;
SDL_JoystickID _instanceId; SDL_JoystickID _instanceId;
#endif #endif
QString _name;
protected:
int _deviceID = 0;
ButtonPressedMap _buttonPressedMap;
AxisStateMap _axisStateMap;
}; };
#endif // hifi_Joystick_h #endif // hifi_Joystick_h

View file

@ -17,6 +17,8 @@
#include "SDL2Manager.h" #include "SDL2Manager.h"
const QString SDL2Manager::NAME = "SDL2";
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) { SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) {
SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller); SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller);
@ -72,7 +74,15 @@ SDL2Manager* SDL2Manager::getInstance() {
return &sharedInstance; return &sharedInstance;
} }
void SDL2Manager::focusOutEvent() { bool SDL2Manager::isSupported() const {
#ifdef HAVE_SDL2
return true;
#else
return false;
#endif
}
void SDL2Manager::pluginFocusOutEvent() {
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
for (auto joystick : _openJoysticks) { for (auto joystick : _openJoysticks) {
joystick->focusOutEvent(); joystick->focusOutEvent();
@ -80,12 +90,12 @@ void SDL2Manager::focusOutEvent() {
#endif #endif
} }
void SDL2Manager::update() { void SDL2Manager::pluginUpdate(float deltaTime) {
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
if (_isInitialized) { if (_isInitialized) {
auto userInputMapper = DependencyManager::get<UserInputMapper>(); auto userInputMapper = DependencyManager::get<UserInputMapper>();
for (auto joystick : _openJoysticks) { for (auto joystick : _openJoysticks) {
joystick->update(); joystick->update(deltaTime);
} }
PerformanceTimer perfTimer("SDL2Manager::update"); PerformanceTimer perfTimer("SDL2Manager::update");

View file

@ -16,22 +16,33 @@
#include <SDL.h> #include <SDL.h>
#endif #endif
#include "InputPlugin.h"
#include "UserInputMapper.h" #include "UserInputMapper.h"
#include "Joystick.h" #include "Joystick.h"
class SDL2Manager : public QObject { class SDL2Manager : public InputPlugin {
Q_OBJECT Q_OBJECT
public: public:
SDL2Manager(); SDL2Manager();
~SDL2Manager(); ~SDL2Manager();
void focusOutEvent();
void update();
static SDL2Manager* getInstance(); static SDL2Manager* getInstance();
// Plugin functions
virtual bool isSupported() const override;
virtual bool isHandController() const override { return false; }
const QString& getName() const { return NAME; }
virtual void init() override {};
virtual void deinit() override {};
virtual void activate(PluginContainer * container) override {};
virtual void deactivate() override {};
virtual void idle() override {};
virtual void pluginFocusOutEvent() override;
virtual void pluginUpdate(float deltaTime) override;
signals: signals:
void joystickAdded(Joystick* joystick); void joystickAdded(Joystick* joystick);
@ -70,12 +81,11 @@ private:
int buttonPressed() const { return SDL_PRESSED; } int buttonPressed() const { return SDL_PRESSED; }
int buttonRelease() const { return SDL_RELEASED; } int buttonRelease() const { return SDL_RELEASED; }
#endif
#ifdef HAVE_SDL2
QMap<SDL_JoystickID, Joystick*> _openJoysticks; QMap<SDL_JoystickID, Joystick*> _openJoysticks;
#endif #endif
bool _isInitialized; bool _isInitialized;
static const QString NAME;
}; };
#endif // hifi__SDL2Manager_h #endif // hifi__SDL2Manager_h

View file

@ -11,13 +11,16 @@
#include <vector> #include <vector>
#include <avatar/AvatarManager.h>
#include <PerfStat.h> #include <PerfStat.h>
#include "Application.h" #include "NumericalConstants.h"
#include "SixenseManager.h" #include "SixenseManager.h"
#include "UserActivityLogger.h" #include "UserActivityLogger.h"
#include "InterfaceLogging.h"
// TODO: This should not be here
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(inputplugins)
Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins")
// These bits aren't used for buttons, so they can be used as masks: // These bits aren't used for buttons, so they can be used as masks:
const unsigned int LEFT_MASK = 0; const unsigned int LEFT_MASK = 0;
@ -46,12 +49,15 @@ typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData
#endif #endif
const QString SixenseManager::NAME = "Sixense";
SixenseManager& SixenseManager::getInstance() { SixenseManager& SixenseManager::getInstance() {
static SixenseManager sharedInstance; static SixenseManager sharedInstance;
return sharedInstance; return sharedInstance;
} }
SixenseManager::SixenseManager() : SixenseManager::SixenseManager() :
InputDevice("Hydra"),
#if defined(HAVE_SIXENSE) && defined(__APPLE__) #if defined(HAVE_SIXENSE) && defined(__APPLE__)
_sixenseLibrary(NULL), _sixenseLibrary(NULL),
#endif #endif
@ -80,7 +86,15 @@ SixenseManager::~SixenseManager() {
#endif #endif
} }
void SixenseManager::initialize() { bool SixenseManager::isSupported() const {
#ifdef HAVE_SIXENSE
return true;
#else
return false;
#endif
}
void SixenseManager::init() {
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
if (!_isInitialized) { if (!_isInitialized) {
@ -144,18 +158,21 @@ void SixenseManager::setFilter(bool filter) {
void SixenseManager::update(float deltaTime) { void SixenseManager::update(float deltaTime) {
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand(); //Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
if (_isInitialized && _isEnabled) { if (_isInitialized && _isEnabled) {
_buttonPressedMap.clear(); _buttonPressedMap.clear();
#ifdef __APPLE__ #ifdef __APPLE__
SixenseBaseFunction sixenseGetNumActiveControllers = SixenseBaseFunction sixenseGetNumActiveControllers =
(SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers"); (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");
#endif #endif
auto userInputMapper = DependencyManager::get<UserInputMapper>();
if (sixenseGetNumActiveControllers() == 0) { if (sixenseGetNumActiveControllers() == 0) {
_hydrasConnected = false; _hydrasConnected = false;
if (_deviceID != 0) { if (_deviceID != 0) {
Application::getUserInputMapper()->removeDevice(_deviceID); userInputMapper->removeDevice(_deviceID);
_deviceID = 0; _deviceID = 0;
_poseStateMap.clear(); _poseStateMap.clear();
// if (_prevPalms[0]) { // if (_prevPalms[0]) {
@ -171,8 +188,8 @@ void SixenseManager::update(float deltaTime) {
PerformanceTimer perfTimer("sixense"); PerformanceTimer perfTimer("sixense");
if (!_hydrasConnected) { if (!_hydrasConnected) {
_hydrasConnected = true; _hydrasConnected = true;
registerToUserInputMapper(*Application::getUserInputMapper()); registerToUserInputMapper(*userInputMapper);
getInstance().assignDefaultInputMapping(*Application::getUserInputMapper()); getInstance().assignDefaultInputMapping(*userInputMapper);
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra"); UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
} }
@ -240,7 +257,7 @@ void SixenseManager::update(float deltaTime) {
glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]);
rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation; rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation;
handlePoseEvent(position, rotation, numActiveControlers - 1); handlePoseEvent(position, rotation, numActiveControllers - 1);
} else { } else {
_poseStateMap.clear(); _poseStateMap.clear();
} }
@ -292,9 +309,9 @@ float SixenseManager::getCursorPixelRangeMult() const {
void SixenseManager::toggleSixense(bool shouldEnable) { void SixenseManager::toggleSixense(bool shouldEnable) {
if (shouldEnable && !isInitialized()) { if (shouldEnable && !isInitialized()) {
initialize(); init();
setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense)); //setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense));
setLowVelocityFilter(Menu::getInstance()->isOptionChecked(MenuOption::LowVelocityFilter)); //setLowVelocityFilter(Menu::getInstance()->isOptionChecked(MenuOption::LowVelocityFilter));
} }
setIsEnabled(shouldEnable); setIsEnabled(shouldEnable);
} }
@ -337,11 +354,11 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers)
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis)); glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis));
xAxis = glm::normalize(glm::cross(yAxis, zAxis)); xAxis = glm::normalize(glm::cross(yAxis, zAxis));
_orbRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis))); _orbRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis)));
qCDebug(interfaceapp, "succeess: sixense calibration"); qCDebug(inputplugins, "succeess: sixense calibration");
} }
break; break;
default: default:
qCDebug(interfaceapp, "failed: sixense calibration"); qCDebug(inputplugins, "failed: sixense calibration");
break; break;
} }
@ -360,7 +377,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers)
if (_calibrationState == CALIBRATION_STATE_IDLE) { if (_calibrationState == CALIBRATION_STATE_IDLE) {
float reach = glm::distance(positionLeft, positionRight); float reach = glm::distance(positionLeft, positionRight);
if (reach > 2.0f * MINIMUM_ARM_REACH) { if (reach > 2.0f * MINIMUM_ARM_REACH) {
qCDebug(interfaceapp, "started: sixense calibration"); qCDebug(inputplugins, "started: sixense calibration");
_averageLeft = positionLeft; _averageLeft = positionLeft;
_averageRight = positionRight; _averageRight = positionRight;
_reachLeft = _averageLeft; _reachLeft = _averageLeft;
@ -393,7 +410,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers)
_lastDistance = 0.0f; _lastDistance = 0.0f;
_reachUp = 0.5f * (_reachLeft + _reachRight); _reachUp = 0.5f * (_reachLeft + _reachRight);
_calibrationState = CALIBRATION_STATE_Y; _calibrationState = CALIBRATION_STATE_Y;
qCDebug(interfaceapp, "success: sixense calibration: left"); qCDebug(inputplugins, "success: sixense calibration: left");
} }
} }
else if (_calibrationState == CALIBRATION_STATE_Y) { else if (_calibrationState == CALIBRATION_STATE_Y) {
@ -412,7 +429,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers)
_lastDistance = 0.0f; _lastDistance = 0.0f;
_lockExpiry = now + LOCK_DURATION; _lockExpiry = now + LOCK_DURATION;
_calibrationState = CALIBRATION_STATE_Z; _calibrationState = CALIBRATION_STATE_Z;
qCDebug(interfaceapp, "success: sixense calibration: up"); qCDebug(inputplugins, "success: sixense calibration: up");
} }
} }
} }
@ -434,7 +451,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers)
if (fabsf(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) { if (fabsf(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) {
// lock has expired so clamp the data and move on // lock has expired so clamp the data and move on
_calibrationState = CALIBRATION_STATE_COMPLETE; _calibrationState = CALIBRATION_STATE_COMPLETE;
qCDebug(interfaceapp, "success: sixense calibration: forward"); qCDebug(inputplugins, "success: sixense calibration: forward");
// TODO: it is theoretically possible to detect that the controllers have been // TODO: it is theoretically possible to detect that the controllers have been
// accidentally switched (left hand is holding right controller) and to swap the order. // accidentally switched (left hand is holding right controller) and to swap the order.
} }
@ -547,7 +564,7 @@ void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) {
// Grab the current free device ID // Grab the current free device ID
_deviceID = mapper.getFreeDeviceID(); _deviceID = mapper.getFreeDeviceID();
auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("Hydra")); 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->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->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->getPose = [this](const UserInputMapper::Input& input, int timestamp) -> UserInputMapper::PoseValue { return this->getPose(input.getChannel()); };
@ -633,35 +650,6 @@ void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
} }
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::PoseValue SixenseManager::getPose(int channel) const {
auto pose = _poseStateMap.find(channel);
if (pose != _poseStateMap.end()) {
return (*pose).second;
} else {
return UserInputMapper::PoseValue();
}
}
UserInputMapper::Input SixenseManager::makeInput(unsigned int button, int index) { UserInputMapper::Input SixenseManager::makeInput(unsigned int button, int index) {
return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON); return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON);
} }

View file

@ -12,9 +12,6 @@
#ifndef hifi_SixenseManager_h #ifndef hifi_SixenseManager_h
#define hifi_SixenseManager_h #define hifi_SixenseManager_h
#include <QObject>
#include <unordered_set>
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
@ -26,7 +23,8 @@
#endif #endif
#include <input-plugins/UserInputMapper.h> #include "InputPlugin.h"
#include "InputDevice.h"
const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2 const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2
const unsigned int BUTTON_1 = 1U << 5; const unsigned int BUTTON_1 = 1U << 5;
@ -36,15 +34,10 @@ const unsigned int BUTTON_4 = 1U << 4;
const unsigned int BUTTON_FWD = 1U << 7; const unsigned int BUTTON_FWD = 1U << 7;
const unsigned int BUTTON_TRIGGER = 1U << 8; const unsigned int BUTTON_TRIGGER = 1U << 8;
// Event type that represents using the controller
const unsigned int CONTROLLER_0_EVENT = 1500U;
const unsigned int CONTROLLER_1_EVENT = 1501U;
const float DEFAULT_SIXENSE_RETICLE_MOVE_SPEED = 37.5f;
const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false; const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
/// Handles interaction with the Sixense SDK (e.g., Razer Hydra). // Handles interaction with the Sixense SDK (e.g., Razer Hydra).
class SixenseManager : public QObject { class SixenseManager : public InputPlugin, public InputDevice {
Q_OBJECT Q_OBJECT
public: public:
enum JoystickAxisChannel { enum JoystickAxisChannel {
@ -61,13 +54,31 @@ public:
}; };
static SixenseManager& getInstance(); static SixenseManager& getInstance();
void initialize(); // Plugin functions
virtual bool isSupported() const override;
virtual bool isHandController() const override { return false; }
const QString& getName() const { return NAME; }
virtual void init() override;
virtual void deinit() override {};
virtual void activate(PluginContainer * container) override {};
virtual void deactivate() override {};
virtual void idle() override {};
virtual void pluginFocusOutEvent() override { focusOutEvent(); }
virtual void pluginUpdate(float deltaTime) override { update(deltaTime); }
// Device functions
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
virtual void update(float deltaTime) override;
virtual void focusOutEvent() override;
bool isInitialized() const { return _isInitialized; } bool isInitialized() const { return _isInitialized; }
void setIsEnabled(bool isEnabled) { _isEnabled = isEnabled; } void setIsEnabled(bool isEnabled) { _isEnabled = isEnabled; }
void update(float deltaTime);
float getCursorPixelRangeMult() const; float getCursorPixelRangeMult() const;
float getReticleMoveSpeed() const { return _reticleMoveSpeed; } float getReticleMoveSpeed() const { return _reticleMoveSpeed; }
@ -75,23 +86,10 @@ public:
bool getInvertButtons() const { return _invertButtons; } bool getInvertButtons() const { return _invertButtons; }
void setInvertButtons(bool invertSixenseButtons) { _invertButtons = invertSixenseButtons; } void setInvertButtons(bool invertSixenseButtons) { _invertButtons = invertSixenseButtons; }
typedef std::unordered_set<int> ButtonPressedMap;
typedef std::map<int, float> AxisStateMap;
typedef std::map<int, UserInputMapper::PoseValue> PoseStateMap;
float getButton(int channel) const;
float getAxis(int channel) const;
UserInputMapper::PoseValue getPose(int channel) const;
UserInputMapper::Input makeInput(unsigned int button, int index); UserInputMapper::Input makeInput(unsigned int button, int index);
UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index); UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index);
UserInputMapper::Input makeInput(JointChannel joint); UserInputMapper::Input makeInput(JointChannel joint);
void registerToUserInputMapper(UserInputMapper& mapper);
void assignDefaultInputMapping(UserInputMapper& mapper);
void focusOutEvent();
public slots: public slots:
void toggleSixense(bool shouldEnable); void toggleSixense(bool shouldEnable);
void setFilter(bool filter); void setFilter(bool filter);
@ -137,15 +135,10 @@ private:
bool _lowVelocityFilter; bool _lowVelocityFilter;
bool _controllersAtBase; bool _controllersAtBase;
float _reticleMoveSpeed = DEFAULT_SIXENSE_RETICLE_MOVE_SPEED; float _reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
bool _invertButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS; bool _invertButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS;
protected: static const QString NAME;
int _deviceID = 0;
ButtonPressedMap _buttonPressedMap;
AxisStateMap _axisStateMap;
PoseStateMap _poseStateMap;
}; };
#endif // hifi_SixenseManager_h #endif // hifi_SixenseManager_h

View file

@ -21,12 +21,6 @@
#include "NumericalConstants.h" #include "NumericalConstants.h"
#include "UserActivityLogger.h" #include "UserActivityLogger.h"
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(inputplugins)
Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins")
const QString ViveControllerManager::NAME("OpenVR (Vive) Hand Controllers");
extern vr::IVRSystem *_hmd; extern vr::IVRSystem *_hmd;
extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]; extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
@ -47,12 +41,15 @@ const unsigned int TRIGGER_BUTTON = 1U << 4;
const float CONTROLLER_LENGTH_OFFSET = 0.175f; const float CONTROLLER_LENGTH_OFFSET = 0.175f;
const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
const QString ViveControllerManager::NAME = "OpenVR";
ViveControllerManager& ViveControllerManager::getInstance() { ViveControllerManager& ViveControllerManager::getInstance() {
static ViveControllerManager sharedInstance; static ViveControllerManager sharedInstance;
return sharedInstance; return sharedInstance;
} }
ViveControllerManager::ViveControllerManager() : ViveControllerManager::ViveControllerManager() :
InputDevice("SteamVR Controller"),
_isInitialized(false), _isInitialized(false),
_isEnabled(true), _isEnabled(true),
_trackedControllers(0), _trackedControllers(0),
@ -67,41 +64,15 @@ ViveControllerManager::~ViveControllerManager() {
} }
const QString& ViveControllerManager::getName() const {
return NAME;
}
bool ViveControllerManager::isSupported() const { bool ViveControllerManager::isSupported() const {
return vr::VR_IsHmdPresent(); return vr::VR_IsHmdPresent();
} }
void ViveControllerManager::init() {
;
}
void ViveControllerManager::deinit() { void ViveControllerManager::deinit() {
; // TODO: deinit openvr? avoid conflicts with display plugin
} }
void ViveControllerManager::activate(PluginContainer * container) { void ViveControllerManager::init() {
activate();
}
/// Called when a plugin is no longer being used. May be called multiple times.
void ViveControllerManager::deactivate() {
;
}
/**
* Called by the application during it's idle phase. If the plugin needs to do
* CPU intensive work, it should launch a thread for that, rather than trying to
* do long operations in the idle call
*/
void ViveControllerManager::idle() {
update();
}
void ViveControllerManager::activate() {
if (!_hmd) { if (!_hmd) {
vr::HmdError eError = vr::HmdError_None; vr::HmdError eError = vr::HmdError_None;
_hmd = vr::VR_Init(&eError); _hmd = vr::VR_Init(&eError);
@ -220,7 +191,7 @@ void ViveControllerManager::renderHand(UserInputMapper::PoseValue pose, gpu::Bat
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
} }
void ViveControllerManager::update() { void ViveControllerManager::update(float deltaTime) {
if (!_hmd) { if (!_hmd) {
return; return;
} }
@ -333,7 +304,7 @@ void ViveControllerManager::registerToUserInputMapper(UserInputMapper& mapper) {
// Grab the current free device ID // Grab the current free device ID
_deviceID = mapper.getFreeDeviceID(); _deviceID = mapper.getFreeDeviceID();
auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("SteamVR Controller")); 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->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->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->getPose = [this](const UserInputMapper::Input& input, int timestamp) -> UserInputMapper::PoseValue { return this->getPose(input.getChannel()); };
@ -405,35 +376,6 @@ void ViveControllerManager::assignDefaultInputMapping(UserInputMapper& mapper) {
mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND)); mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
} }
float ViveControllerManager::getButton(int channel) const {
if (!_buttonPressedMap.empty()) {
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
return 1.0f;
} else {
return 0.0f;
}
}
return 0.0f;
}
float ViveControllerManager::getAxis(int channel) const {
auto axis = _axisStateMap.find(channel);
if (axis != _axisStateMap.end()) {
return (*axis).second;
} else {
return 0.0f;
}
}
UserInputMapper::PoseValue ViveControllerManager::getPose(int channel) const {
auto pose = _poseStateMap.find(channel);
if (pose != _poseStateMap.end()) {
return (*pose).second;
} else {
return UserInputMapper::PoseValue();
}
}
UserInputMapper::Input ViveControllerManager::makeInput(unsigned int button, int index) { UserInputMapper::Input ViveControllerManager::makeInput(unsigned int button, int index) {
return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON); return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON);
} }

View file

@ -19,34 +19,14 @@
#include <model/Geometry.h> #include <model/Geometry.h>
#include <gpu/Texture.h> #include <gpu/Texture.h>
#include "InputDevice.h"
#include "InputPlugin.h" #include "InputPlugin.h"
#include <RenderArgs.h> #include <RenderArgs.h>
#include <render/Scene.h> #include <render/Scene.h>
#include "UserInputMapper.h"
class ViveControllerManager : public InputPlugin { class ViveControllerManager : public InputPlugin, public InputDevice {
Q_OBJECT
public: public:
virtual const QString& getName() const override;
virtual bool isSupported() const override;
virtual bool isHandController() { return true; }
/// Called when plugin is initially loaded, typically at application start
virtual void init() override;
/// Called when application is shutting down
virtual void deinit() override ;
/// Called when a plugin is being activated for use. May be called multiple times.
virtual void activate(PluginContainer * container) override;
/// Called when a plugin is no longer being used. May be called multiple times.
virtual void deactivate() override;
/**
* Called by the application during it's idle phase. If the plugin needs to do
* CPU intensive work, it should launch a thread for that, rather than trying to
* do long operations in the idle call
*/
virtual void idle() override;
enum JoystickAxisChannel { enum JoystickAxisChannel {
AXIS_Y_POS = 1U << 1, AXIS_Y_POS = 1U << 1,
AXIS_Y_NEG = 1U << 2, AXIS_Y_NEG = 1U << 2,
@ -67,31 +47,35 @@ public:
LEFT_HAND = 0, LEFT_HAND = 0,
RIGHT_HAND, RIGHT_HAND,
}; };
void focusOutEvent(); static ViveControllerManager& getInstance();
// Plugin functions
virtual bool isSupported() const override;
virtual bool isHandController() const override { return true; }
const QString& getName() const { return NAME; }
virtual void init() override;
virtual void deinit() override;
virtual void activate(PluginContainer * container) override {};
virtual void deactivate() override {};
virtual void idle() override {};
virtual void pluginFocusOutEvent() override { focusOutEvent(); }
virtual void pluginUpdate(float deltaTime) override { update(deltaTime); }
// Device functions
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
virtual void update(float deltaTime) override;
virtual void focusOutEvent() override;
void updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges); void updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges);
void update();
static ViveControllerManager& getInstance();
typedef std::unordered_set<int> ButtonPressedMap;
typedef std::map<int, float> AxisStateMap;
typedef std::map<int, UserInputMapper::PoseValue> PoseStateMap;
float getButton(int channel) const;
float getAxis(int channel) const;
UserInputMapper::PoseValue getPose(int channel) const;
UserInputMapper::Input makeInput(unsigned int button, int index); UserInputMapper::Input makeInput(unsigned int button, int index);
UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index); UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index);
UserInputMapper::Input makeInput(JointChannel joint); UserInputMapper::Input makeInput(JointChannel joint);
void registerToUserInputMapper(UserInputMapper& mapper);
void assignDefaultInputMapping(UserInputMapper& mapper);
void activate();
private: private:
ViveControllerManager(); ViveControllerManager();
~ViveControllerManager(); ~ViveControllerManager();
@ -114,13 +98,6 @@ private:
int _rightHandRenderID; int _rightHandRenderID;
static const QString NAME; static const QString NAME;
protected:
int _deviceID = 0;
ButtonPressedMap _buttonPressedMap;
AxisStateMap _axisStateMap;
PoseStateMap _poseStateMap;
}; };