Merge pull request #6080 from jherico/controllers

Controllers Branch - Merging the old and new interfaces
This commit is contained in:
Brad Hefta-Gaub 2015-10-14 18:48:38 -07:00
commit dc0f1378b7
46 changed files with 1200 additions and 1165 deletions

View file

@ -1,12 +1,12 @@
set(TARGET_NAME assignment-client) set(TARGET_NAME assignment-client)
setup_hifi_project(Core Gui Network Script Widgets WebSockets) setup_hifi_project(Core Gui Network Script Quick Widgets WebSockets)
# link in the shared libraries # link in the shared libraries
link_hifi_libraries( link_hifi_libraries(
audio avatars octree environment gpu model fbx entities audio avatars octree environment gpu model fbx entities
networking animation shared script-engine embedded-webserver networking animation shared script-engine embedded-webserver
physics controllers physics
) )
include_application_version() include_application_version()

View file

@ -11,6 +11,16 @@
// Assumes you only have the default keyboard connected // Assumes you only have the default keyboard connected
function findAction(name) {
var actions = Controller.getAllActions();
for (var i = 0; i < actions.length; i++) {
if (actions[i].actionName == name) {
return i;
}
}
// If the action isn't found, it will default to the first available action
return 0;
}
var hydra = Controller.Hardware.Hydra2; var hydra = Controller.Hardware.Hydra2;
@ -46,44 +56,48 @@ Controller.resetAllDeviceBindings();
// Query all actions // Query all actions
print("All Actions: \n" + Controller.getAllActions()); print("All Actions: \n" + Controller.getAllActions());
var actionId = findAction("YAW_LEFT")
print("Yaw Left action ID: " + actionId)
// Each action stores: // Each action stores:
// action: int representation of enum // action: int representation of enum
print("Action 5 int: \n" + Controller.getAllActions()[5].action); print("Action int: \n" + Controller.getAllActions()[actionId].action);
// actionName: string representation of enum // actionName: string representation of enum
print("Action 5 name: \n" + Controller.getAllActions()[5].actionName); print("Action name: \n" + Controller.getAllActions()[actionId].actionName);
// inputChannels: list of all inputchannels that control that action // inputChannels: list of all inputchannels that control that action
print("Action 5 input channels: \n" + Controller.getAllActions()[5].inputChannels + "\n"); print("Action input channels: \n" + Controller.getAllActions()[actionId].inputChannels + "\n");
// Each input channel stores: // Each input channel stores:
// action: Action that this InputChannel maps to // action: Action that this InputChannel maps to
print("Input channel action: \n" + Controller.getAllActions()[5].inputChannels[0].action); print("Input channel action: \n" + Controller.getAllActions()[actionId].inputChannels[0].action);
// scale: sensitivity of input // scale: sensitivity of input
print("Input channel scale: \n" + Controller.getAllActions()[5].inputChannels[0].scale); print("Input channel scale: \n" + Controller.getAllActions()[actionId].inputChannels[0].scale);
// input and modifier: Inputs // input and modifier: Inputs
print("Input channel input and modifier: \n" + Controller.getAllActions()[5].inputChannels[0].input + "\n" + Controller.getAllActions()[5].inputChannels[0].modifier + "\n"); print("Input channel input and modifier: \n" + Controller.getAllActions()[actionId].inputChannels[0].input + "\n" + Controller.getAllActions()[actionId].inputChannels[0].modifier + "\n");
// Each Input stores: // Each Input stores:
// device: device of input // device: device of input
print("Input device: \n" + Controller.getAllActions()[5].inputChannels[0].input.device); print("Input device: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.device);
// channel: channel of input // channel: channel of input
print("Input channel: \n" + Controller.getAllActions()[5].inputChannels[0].input.channel); print("Input channel: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.channel);
// type: type of input (Unknown, Button, Axis, Joint) // type: type of input (Unknown, Button, Axis, Joint)
print("Input type: \n" + Controller.getAllActions()[5].inputChannels[0].input.type); print("Input type: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.type);
// id: id of input // id: id of input
print("Input id: \n" + Controller.getAllActions()[5].inputChannels[0].input.id + "\n"); print("Input id: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.id + "\n");
// You can get the name of a device from its id // You can get the name of a device from its id
print("Device 1 name: \n" + Controller.getDeviceName(Controller.getAllActions()[5].inputChannels[0].input.id)); print("Device 1 name: \n" + Controller.getDeviceName(Controller.getAllActions()[actionId].inputChannels[0].input.id));
// You can also get all of a devices input channels // You can also get all of a devices input channels
print("Device 1's input channels: \n" + Controller.getAllInputsForDevice(1) + "\n"); print("Device 1's input channels: \n" + Controller.getAllInputsForDevice(1) + "\n");
@ -119,7 +133,7 @@ for (i = 0; i < availableInputs.length; i++) {
// You can modify key bindings by using these avaiable inputs // You can modify key bindings by using these avaiable inputs
// This will replace e (up) with 6 // This will replace e (up) with 6
var e = Controller.getAllActions()[5].inputChannels[0]; var e = Controller.getAllActions()[actionId].inputChannels[0];
Controller.removeInputChannel(e); Controller.removeInputChannel(e);
e.input = availableInputs[6].input; e.input = availableInputs[6].input;
Controller.addInputChannel(e); Controller.addInputChannel(e);

View file

@ -38,7 +38,7 @@ var mouseLook = (function () {
keyboardID = 0; keyboardID = 0;
function onKeyPressEvent(event) { function onKeyPressEvent(event) {
if (event.text == 'M') { if (event.text == 'm') {
active = !active; active = !active;
updateMapping(); updateMapping();
} }

View file

@ -98,9 +98,8 @@ endif()
# link required hifi libraries # link required hifi libraries
link_hifi_libraries(shared octree environment gpu procedural model render fbx networking model-networking entities avatars link_hifi_libraries(shared octree environment gpu procedural model render fbx networking model-networking entities avatars
audio audio-client animation script-engine physics audio audio-client animation script-engine physics
render-utils entities-renderer ui auto-updater render-utils entities-renderer ui auto-updater
plugins display-plugins input-plugins controllers plugins display-plugins input-plugins )
controllers)
target_bullet() target_bullet()
target_glew() target_glew()

View file

@ -60,7 +60,7 @@
#include <InfoView.h> #include <InfoView.h>
#include <input-plugins/InputPlugin.h> #include <input-plugins/InputPlugin.h>
#include <input-plugins/Joystick.h> // this should probably be removed #include <input-plugins/Joystick.h> // this should probably be removed
#include <input-plugins/UserInputMapper.h> #include <controllers/UserInputMapper.h>
#include <LogHandler.h> #include <LogHandler.h>
#include <MainWindow.h> #include <MainWindow.h>
#include <MessageDialog.h> #include <MessageDialog.h>
@ -614,7 +614,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// Setup the userInputMapper with the actions // Setup the userInputMapper with the actions
auto userInputMapper = DependencyManager::get<UserInputMapper>(); auto userInputMapper = DependencyManager::get<UserInputMapper>();
connect(userInputMapper.data(), &UserInputMapper::actionEvent, &_controllerScriptingInterface, &AbstractControllerScriptingInterface::actionEvent); connect(userInputMapper.data(), &UserInputMapper::actionEvent, &_controllerScriptingInterface, &ControllerScriptingInterface::actionEvent);
connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) { connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
if (state) { if (state) {
switch (action) { switch (action) {
@ -2708,7 +2708,7 @@ void Application::update(float deltaTime) {
} }
// Dispatch input events // Dispatch input events
_controllerScriptingInterface.updateInputControllers(); _controllerScriptingInterface.update();
// Transfer the user inputs to the driveKeys // Transfer the user inputs to the driveKeys
myAvatar->clearDriveKeys(); myAvatar->clearDriveKeys();

View file

@ -161,7 +161,7 @@ public:
ToolWindow* getToolWindow() { return _toolWindow ; } ToolWindow* getToolWindow() { return _toolWindow ; }
virtual AbstractControllerScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; } virtual controller::ScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; }
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine); virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine);
QImage renderAvatarBillboard(RenderArgs* renderArgs); QImage renderAvatarBillboard(RenderArgs* renderArgs);

View file

@ -13,7 +13,7 @@
#include <QObject> #include <QObject>
#include <QLibrary> #include <QLibrary>
#include <input-plugins/UserInputMapper.h> #include <controllers/UserInputMapper.h>
#include "InterfaceLogging.h" #include "InterfaceLogging.h"

View file

@ -9,21 +9,20 @@
// 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 "ControllerScriptingInterface.h"
#include <avatar/AvatarManager.h> #include <avatar/AvatarManager.h>
#include <avatar/MyAvatar.h> #include <avatar/MyAvatar.h>
#include <HandData.h> #include <HandData.h>
#include <HFBackEvent.h> #include <HFBackEvent.h>
#include <plugins/PluginManager.h>
#include <controllers/NewControllerScriptingInterface.h>
#include "Application.h" #include "Application.h"
#include "devices/MotionTracker.h" #include "devices/MotionTracker.h"
#include "ControllerScriptingInterface.h"
// TODO: this needs to be removed, as well as any related controller-specific information // TODO: this needs to be removed, as well as any related controller-specific information
#include <input-plugins/SixenseManager.h> #include <input-plugins/SixenseManager.h>
ControllerScriptingInterface::ControllerScriptingInterface() : ControllerScriptingInterface::ControllerScriptingInterface() :
_mouseCaptured(false), _mouseCaptured(false),
_touchCaptured(false), _touchCaptured(false),
@ -34,7 +33,6 @@ ControllerScriptingInterface::ControllerScriptingInterface() :
} }
ControllerScriptingInterface::~ControllerScriptingInterface() { ControllerScriptingInterface::~ControllerScriptingInterface() {
delete _newControllerScriptingInterface;
} }
@ -118,7 +116,7 @@ void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::Input
inputPair.second = QString(object.property("inputName").toVariant().toString()); inputPair.second = QString(object.property("inputName").toVariant().toString());
} }
void ControllerScriptingInterface::registerControllerTypes(ScriptEngine* engine) { void ControllerScriptingInterface::registerControllerTypes(QScriptEngine* engine) {
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine); qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputChannel> >(engine); qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputChannel> >(engine);
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine); qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
@ -126,13 +124,6 @@ void ControllerScriptingInterface::registerControllerTypes(ScriptEngine* engine)
qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue); qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue);
qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
wireUpControllers(engine);
// hack in the new controller scripting interface...
_newControllerScriptingInterface = new controller::NewControllerScriptingInterface();
engine->registerGlobalObject("NewControllers", _newControllerScriptingInterface);
} }
void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
@ -192,6 +183,7 @@ const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const
return NULL; return NULL;
} }
/*
bool ControllerScriptingInterface::isPrimaryButtonPressed() const { bool ControllerScriptingInterface::isPrimaryButtonPressed() const {
const PalmData* primaryPalm = getPrimaryPalm(); const PalmData* primaryPalm = getPrimaryPalm();
if (primaryPalm) { if (primaryPalm) {
@ -345,6 +337,7 @@ glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex
} }
return glm::vec3(0); // bad index return glm::vec3(0); // bad index
} }
*/
bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const { bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const {
return isKeyCaptured(KeyEvent(*event)); return isKeyCaptured(KeyEvent(*event));
@ -395,97 +388,64 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
return qApp->getUiSize(); return qApp->getUiSize();
} }
QString ControllerScriptingInterface::sanatizeName(const QString& name) { controller::InputController::Pointer ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
QString cleanName { name };
cleanName.remove(QRegularExpression{"[\\(\\)\\.\\s]"});
return cleanName;
}
void ControllerScriptingInterface::wireUpControllers(ScriptEngine* engine) {
// Controller.Standard.*
auto standardDevice = DependencyManager::get<UserInputMapper>()->getStandardDevice();
if (standardDevice) {
auto deviceName = sanatizeName(standardDevice->getName());
auto deviceInputs = standardDevice->getAvailabeInputs();
for (const auto& inputMapping : deviceInputs) {
auto input = inputMapping.first;
auto inputName = sanatizeName(inputMapping.second);
QString deviceInputName{ "Controller." + deviceName + "." + inputName };
engine->registerValue(deviceInputName, input.getID());
}
}
// Controller.Hardware.*
auto devices = DependencyManager::get<UserInputMapper>()->getDevices();
for(const auto& deviceMapping : devices) {
auto device = deviceMapping.second.get();
auto deviceName = sanatizeName(device->getName());
auto deviceInputs = device->getAvailabeInputs();
for (const auto& inputMapping : deviceInputs) {
auto input = inputMapping.first;
auto inputName = sanatizeName(inputMapping.second);
QString deviceInputName { "Controller.Hardware." + deviceName + "." + inputName };
engine->registerValue(deviceInputName, input.getID());
}
}
// Controller.Actions.*
auto actionNames = DependencyManager::get<UserInputMapper>()->getActionNames();
int actionNumber = 0;
for (const auto& actionName : actionNames) {
QString safeActionName { "Controller.Actions." + sanatizeName(actionName) };
engine->registerValue(safeActionName, actionNumber);
actionNumber++;
}
}
AbstractInputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
// This is where we retreive the Device Tracker category and then the sub tracker within it // This is where we retreive the Device Tracker category and then the sub tracker within it
//TODO C++11 auto icIt = _inputControllers.find(0); auto icIt = _inputControllers.find(0);
InputControllerMap::iterator icIt = _inputControllers.find(0);
if (icIt != _inputControllers.end()) { if (icIt != _inputControllers.end()) {
return (*icIt).second; return (*icIt).second;
} else { }
// Look for device
DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString());
if (deviceID < 0) {
deviceID = 0;
}
// TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion)
// in the near future we need to change that to a real mapping between the devices and the deviceName
// ALso we need to expand the spec so we can fall back on the "default" controller per categories
if (deviceID >= 0) { // Look for device
// TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString());
MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID)); if (deviceID < 0) {
if (motionTracker) { deviceID = 0;
MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString()); }
if (trackerID >= 0) { // TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion)
AbstractInputController* inputController = new InputController(deviceID, trackerID, this); // in the near future we need to change that to a real mapping between the devices and the deviceName
// ALso we need to expand the spec so we can fall back on the "default" controller per categories
_inputControllers.insert(InputControllerMap::value_type(inputController->getKey(), inputController)); if (deviceID >= 0) {
// TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices
return inputController; MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID));
} if (motionTracker) {
MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString());
if (trackerID >= 0) {
controller::InputController::Pointer inputController = std::make_shared<InputController>(deviceID, trackerID, this);
controller::InputController::Key key = inputController->getKey();
_inputControllers.insert(InputControllerMap::value_type(inputController->getKey(), inputController));
return inputController;
} }
} }
return 0;
} }
return controller::InputController::Pointer();
} }
void ControllerScriptingInterface::releaseInputController(AbstractInputController* input) { void ControllerScriptingInterface::releaseInputController(controller::InputController::Pointer input) {
_inputControllers.erase(input->getKey()); _inputControllers.erase(input->getKey());
} }
void ControllerScriptingInterface::updateInputControllers() { void ControllerScriptingInterface::update() {
//TODO C++11 for (auto it = _inputControllers.begin(); it != _inputControllers.end(); it++) { static float last = secTimestampNow();
for (InputControllerMap::iterator it = _inputControllers.begin(); it != _inputControllers.end(); it++) { float now = secTimestampNow();
(*it).second->update(); float delta = now - last;
last = now;
for(auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
if (inputPlugin->isActive()) {
inputPlugin->pluginUpdate(delta, false);
}
} }
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->update(delta);
for (auto entry : _inputControllers) {
entry.second->update();
}
controller::ScriptingInterface::update();
} }
QVector<UserInputMapper::Action> ControllerScriptingInterface::getAllActions() { QVector<UserInputMapper::Action> ControllerScriptingInterface::getAllActions() {
@ -545,7 +505,6 @@ QVector<QString> ControllerScriptingInterface::getActionNames() const {
} }
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
AbstractInputController(),
_deviceTrackerId(deviceTrackerId), _deviceTrackerId(deviceTrackerId),
_subTrackerId(subTrackerId), _subTrackerId(subTrackerId),
_isActive(false) _isActive(false)
@ -568,7 +527,7 @@ void InputController::update() {
joint->getLocFrame().getRotation(_eventCache.locRotation); joint->getLocFrame().getRotation(_eventCache.locRotation);
_isActive = true; _isActive = true;
emit spatialEvent(_eventCache); //emit spatialEvent(_eventCache);
} }
} }
} }
@ -580,3 +539,19 @@ const unsigned int INPUTCONTROLLER_KEY_DEVICE_MASK = 16;
InputController::Key InputController::getKey() const { InputController::Key InputController::getKey() const {
return (((_deviceTrackerId & INPUTCONTROLLER_KEY_DEVICE_MASK) << INPUTCONTROLLER_KEY_DEVICE_OFFSET) | _subTrackerId); return (((_deviceTrackerId & INPUTCONTROLLER_KEY_DEVICE_MASK) << INPUTCONTROLLER_KEY_DEVICE_OFFSET) | _subTrackerId);
} }
void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }
void ControllerScriptingInterface::emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); }
void ControllerScriptingInterface::emitMousePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mousePressEvent(MouseEvent(*event, deviceID)); }
void ControllerScriptingInterface::emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); }
void ControllerScriptingInterface::emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); }
void ControllerScriptingInterface::emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }
void ControllerScriptingInterface::emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); }
void ControllerScriptingInterface::emitTouchUpdateEvent(const TouchEvent& event) { emit touchUpdateEvent(event); }
void ControllerScriptingInterface::emitWheelEvent(QWheelEvent* event) { emit wheelEvent(*event); }

View file

@ -14,15 +14,20 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <input-plugins/UserInputMapper.h> #include <controllers/UserInputMapper.h>
#include <controllers/ScriptingInterface.h>
#include <HFActionEvent.h>
#include <KeyEvent.h>
#include <MouseEvent.h>
#include <SpatialEvent.h>
#include <TouchEvent.h>
#include <WheelEvent.h>
class ScriptEngine;
#include <AbstractControllerScriptingInterface.h>
class PalmData; class PalmData;
namespace controller {
class NewControllerScriptingInterface;
}
class InputController : public AbstractInputController { class InputController : public controller::InputController {
Q_OBJECT Q_OBJECT
public: public:
@ -53,30 +58,53 @@ signals:
/// handles scripting of input controller commands from JS /// handles scripting of input controller commands from JS
class ControllerScriptingInterface : public AbstractControllerScriptingInterface { class ControllerScriptingInterface : public controller::ScriptingInterface {
Q_OBJECT Q_OBJECT
public: public:
ControllerScriptingInterface(); ControllerScriptingInterface();
~ControllerScriptingInterface(); ~ControllerScriptingInterface();
virtual void registerControllerTypes(ScriptEngine* engine); Q_INVOKABLE QVector<UserInputMapper::Action> getAllActions();
Q_INVOKABLE bool addInputChannel(UserInputMapper::InputChannel inputChannel);
Q_INVOKABLE bool removeInputChannel(UserInputMapper::InputChannel inputChannel);
Q_INVOKABLE QVector<UserInputMapper::InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
Q_INVOKABLE QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
Q_INVOKABLE QVector<UserInputMapper::InputChannel> getAllInputsForDevice(unsigned int device);
Q_INVOKABLE QString getDeviceName(unsigned int device);
Q_INVOKABLE float getActionValue(int action);
Q_INVOKABLE void resetDevice(unsigned int device);
Q_INVOKABLE void resetAllDeviceBindings();
Q_INVOKABLE int findDevice(QString name);
Q_INVOKABLE QVector<QString> getDeviceNames();
Q_INVOKABLE int findAction(QString actionName);
Q_INVOKABLE QVector<QString> getActionNames() const;
virtual void registerControllerTypes(QScriptEngine* engine);
void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } void emitKeyPressEvent(QKeyEvent* event);
void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } void emitKeyReleaseEvent(QKeyEvent* event);
void handleMetaEvent(HFMetaEvent* event); void handleMetaEvent(HFMetaEvent* event);
void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0);
void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); } void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0);
void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); } void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0);
void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); } void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0);
void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); } void emitTouchBeginEvent(const TouchEvent& event);
void emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); } void emitTouchEndEvent(const TouchEvent& event);
void emitTouchUpdateEvent(const TouchEvent& event) { emit touchUpdateEvent(event); } void emitTouchUpdateEvent(const TouchEvent& event);
void emitWheelEvent(QWheelEvent* event) { emit wheelEvent(*event); } void emitWheelEvent(QWheelEvent* event);
bool isKeyCaptured(QKeyEvent* event) const; bool isKeyCaptured(QKeyEvent* event) const;
bool isKeyCaptured(const KeyEvent& event) const; bool isKeyCaptured(const KeyEvent& event) const;
@ -86,48 +114,10 @@ public:
bool areActionsCaptured() const { return _actionsCaptured; } bool areActionsCaptured() const { return _actionsCaptured; }
bool isJoystickCaptured(int joystickIndex) const; bool isJoystickCaptured(int joystickIndex) const;
void updateInputControllers(); virtual void update() override;
public slots: public slots:
Q_INVOKABLE virtual QVector<UserInputMapper::Action> getAllActions();
Q_INVOKABLE virtual bool addInputChannel(UserInputMapper::InputChannel inputChannel);
Q_INVOKABLE virtual bool removeInputChannel(UserInputMapper::InputChannel inputChannel);
Q_INVOKABLE virtual QVector<UserInputMapper::InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
Q_INVOKABLE virtual QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
Q_INVOKABLE virtual QVector<UserInputMapper::InputChannel> getAllInputsForDevice(unsigned int device);
Q_INVOKABLE virtual QString getDeviceName(unsigned int device);
Q_INVOKABLE virtual float getActionValue(int action);
Q_INVOKABLE virtual void resetDevice(unsigned int device);
Q_INVOKABLE virtual void resetAllDeviceBindings();
Q_INVOKABLE virtual int findDevice(QString name);
Q_INVOKABLE virtual QVector<QString> getDeviceNames();
Q_INVOKABLE virtual int findAction(QString actionName);
Q_INVOKABLE virtual QVector<QString> getActionNames() const;
virtual bool isPrimaryButtonPressed() const;
virtual glm::vec2 getPrimaryJoystickPosition() const;
virtual int getNumberOfButtons() const;
virtual bool isButtonPressed(int buttonIndex) const;
virtual int getNumberOfTriggers() const;
virtual float getTriggerValue(int triggerIndex) const;
virtual int getNumberOfJoysticks() const;
virtual glm::vec2 getJoystickPosition(int joystickIndex) const;
virtual int getNumberOfSpatialControls() const;
virtual glm::vec3 getSpatialControlPosition(int controlIndex) const;
virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const;
virtual glm::vec3 getSpatialControlNormal(int controlIndex) const;
virtual glm::quat getSpatialControlRawRotation(int controlIndex) const;
virtual glm::vec3 getSpatialControlRawAngularVelocity(int controlIndex) const;
virtual void captureKeyEvents(const KeyEvent& event); virtual void captureKeyEvents(const KeyEvent& event);
virtual void releaseKeyEvents(const KeyEvent& event); virtual void releaseKeyEvents(const KeyEvent& event);
@ -149,9 +139,31 @@ public slots:
virtual glm::vec2 getViewportDimensions() const; virtual glm::vec2 getViewportDimensions() const;
/// Factory to create an InputController /// Factory to create an InputController
virtual AbstractInputController* createInputController(const QString& deviceName, const QString& tracker); virtual controller::InputController::Pointer createInputController(const QString& deviceName, const QString& tracker);
virtual void releaseInputController(controller::InputController::Pointer input);
virtual void releaseInputController(AbstractInputController* input); signals:
void keyPressEvent(const KeyEvent& event);
void keyReleaseEvent(const KeyEvent& event);
void actionStartEvent(const HFActionEvent& event);
void actionEndEvent(const HFActionEvent& event);
void backStartEvent();
void backEndEvent();
void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0);
void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0);
void touchBeginEvent(const TouchEvent& event);
void touchEndEvent(const TouchEvent& event);
void touchUpdateEvent(const TouchEvent& event);
void wheelEvent(const WheelEvent& event);
void actionEvent(int action, float state);
private: private:
QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript
@ -168,12 +180,9 @@ private:
QMultiMap<int,KeyEvent> _capturedKeys; QMultiMap<int,KeyEvent> _capturedKeys;
QSet<int> _capturedJoysticks; QSet<int> _capturedJoysticks;
typedef std::map< AbstractInputController::Key, AbstractInputController* > InputControllerMap; using InputKey = controller::InputController::Key;
using InputControllerMap = std::map<InputKey, controller::InputController::Pointer>;
InputControllerMap _inputControllers; InputControllerMap _inputControllers;
void wireUpControllers(ScriptEngine* engine);
controller::NewControllerScriptingInterface* _newControllerScriptingInterface = nullptr;
}; };
const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip

View file

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

View file

@ -4,7 +4,7 @@ set(TARGET_NAME controllers)
setup_hifi_library(Script) setup_hifi_library(Script)
# 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
link_hifi_libraries(shared plugins input-plugins) link_hifi_libraries(shared)
GroupSources("src/controllers") GroupSources("src/controllers")

View file

@ -14,7 +14,7 @@
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <input-plugins/UserInputMapper.h> #include "UserInputMapper.h"
class QScriptValue; class QScriptValue;

View file

@ -1,89 +0,0 @@
//
// Created by Bradley Austin Davis 2015/10/09
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_Controllers_NewControllerScriptingInterface_h
#define hifi_Controllers_NewControllerScriptingInterface_h
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <set>
#include <QtCore/QObject>
#include <QtCore/QVariant>
#include <QtQml/QJSValue>
#include <QtScript/QScriptValue>
#include <input-plugins/UserInputMapper.h>
#include "Mapping.h"
class QScriptValue;
namespace controller {
class NewControllerScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(QVariantMap Hardware READ getHardware CONSTANT FINAL)
Q_PROPERTY(QVariantMap Actions READ getActions CONSTANT FINAL)
Q_PROPERTY(QVariantMap Standard READ getStandard CONSTANT FINAL)
public:
NewControllerScriptingInterface();
Q_INVOKABLE float getValue(const int& source);
Q_INVOKABLE void update();
Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
Q_INVOKABLE void disableMapping(const QString& mappingName) {
enableMapping(mappingName, false);
}
const QVariantMap& getHardware() { return _hardware; }
const QVariantMap& getActions() { return _actions; }
const QVariantMap& getStandard() { return _standard; }
private:
// FIXME move to unordered set / map
using MappingMap = std::map<QString, Mapping::Pointer>;
using MappingStack = std::list<Mapping::Pointer>;
using InputToEndpointMap = std::map<UserInputMapper::Input, Endpoint::Pointer>;
using EndpointSet = std::unordered_set<Endpoint::Pointer>;
using ValueMap = std::map<Endpoint::Pointer, float>;
using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
void update(Mapping::Pointer& mapping, EndpointSet& consumed);
float getValue(const Endpoint::Pointer& endpoint);
Endpoint::Pointer endpointFor(const QJSValue& endpoint);
Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint);
Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
friend class MappingBuilderProxy;
friend class RouteBuilderProxy;
private:
uint16_t _nextFunctionId;
InputToEndpointMap _endpoints;
EndpointPairMap _compositeEndpoints;
ValueMap _overrideValues;
MappingMap _mappingsByName;
MappingStack _activeMappings;
QVariantMap _hardware;
QVariantMap _actions;
QVariantMap _standard;
};
}
#endif

View file

@ -5,7 +5,7 @@
// 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 "NewControllerScriptingInterface.h" #include "ScriptingInterface.h"
#include <mutex> #include <mutex>
#include <set> #include <set>
@ -14,19 +14,15 @@
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <input-plugins/UserInputMapper.h>
#include <input-plugins/InputPlugin.h>
#include <input-plugins/KeyboardMouseDevice.h>
#include <plugins/PluginManager.h>
#include "impl/MappingBuilderProxy.h" #include "impl/MappingBuilderProxy.h"
#include "Logging.h" #include "Logging.h"
#include "InputDevice.h"
static const uint16_t ACTIONS_DEVICE = UserInputMapper::Input::INVALID_DEVICE - (uint16_t)1; static const uint16_t ACTIONS_DEVICE = UserInputMapper::Input::INVALID_DEVICE - (uint16_t)1;
namespace controller { namespace controller {
class VirtualEndpoint : public Endpoint { class VirtualEndpoint : public Endpoint {
public: public:
VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input(-1)) VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input(-1))
@ -97,18 +93,15 @@ namespace controller {
Endpoint::Pointer _second; Endpoint::Pointer _second;
}; };
QString sanatizeName(const QString& name) {
QString cleanName{ name }; QRegularExpression ScriptingInterface::SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" };
cleanName.remove(QRegularExpression{ "[\\(\\)\\.\\s]" });
return cleanName;
}
QVariantMap createDeviceMap(const UserInputMapper::DeviceProxy* device) { QVariantMap createDeviceMap(const UserInputMapper::DeviceProxy* device) {
auto userInputMapper = DependencyManager::get<UserInputMapper>(); auto userInputMapper = DependencyManager::get<UserInputMapper>();
QVariantMap deviceMap; QVariantMap deviceMap;
for (const auto& inputMapping : device->getAvailabeInputs()) { for (const auto& inputMapping : device->getAvailabeInputs()) {
const auto& input = inputMapping.first; const auto& input = inputMapping.first;
const auto inputName = sanatizeName(inputMapping.second); const auto inputName = QString(inputMapping.second).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType() qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType()
<< QString::number(input.getID(), 16) << ": " << inputName; << QString::number(input.getID(), 16) << ": " << inputName;
deviceMap.insert(inputName, input.getID()); deviceMap.insert(inputName, input.getID());
@ -116,12 +109,12 @@ namespace controller {
return deviceMap; return deviceMap;
} }
NewControllerScriptingInterface::NewControllerScriptingInterface() { ScriptingInterface::ScriptingInterface() {
auto userInputMapper = DependencyManager::get<UserInputMapper>(); auto userInputMapper = DependencyManager::get<UserInputMapper>();
auto devices = userInputMapper->getDevices(); auto devices = userInputMapper->getDevices();
for (const auto& deviceMapping : devices) { for (const auto& deviceMapping : devices) {
auto device = deviceMapping.second.get(); auto device = deviceMapping.second.get();
auto deviceName = sanatizeName(device->getName()); auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName; qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName;
// Expose the IDs to JS // Expose the IDs to JS
_hardware.insert(deviceName, createDeviceMap(device)); _hardware.insert(deviceName, createDeviceMap(device));
@ -164,7 +157,8 @@ namespace controller {
UserInputMapper::Input actionInput(ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS); UserInputMapper::Input actionInput(ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS);
qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16); qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16);
// Expose the IDs to JS // Expose the IDs to JS
_actions.insert(sanatizeName(actionName), actionInput.getID()); QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION);
_actions.insert(cleanActionName, actionInput.getID());
// Create the endpoints // Create the endpoints
// FIXME action endpoints need to accumulate values, and have them cleared at each frame // FIXME action endpoints need to accumulate values, and have them cleared at each frame
@ -172,7 +166,7 @@ namespace controller {
} }
} }
QObject* NewControllerScriptingInterface::newMapping(const QString& mappingName) { QObject* ScriptingInterface::newMapping(const QString& mappingName) {
if (_mappingsByName.count(mappingName)) { if (_mappingsByName.count(mappingName)) {
qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName; qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName;
} }
@ -182,7 +176,7 @@ namespace controller {
return new MappingBuilderProxy(*this, mapping); return new MappingBuilderProxy(*this, mapping);
} }
void NewControllerScriptingInterface::enableMapping(const QString& mappingName, bool enable) { void ScriptingInterface::enableMapping(const QString& mappingName, bool enable) {
auto iterator = _mappingsByName.find(mappingName); auto iterator = _mappingsByName.find(mappingName);
if (_mappingsByName.end() == iterator) { if (_mappingsByName.end() == iterator) {
qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName; qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName;
@ -202,7 +196,7 @@ namespace controller {
} }
} }
float NewControllerScriptingInterface::getValue(const int& source) { float ScriptingInterface::getValue(const int& source) const {
// return (sin(secTimestampNow()) + 1.0f) / 2.0f; // return (sin(secTimestampNow()) + 1.0f) / 2.0f;
UserInputMapper::Input input(source); UserInputMapper::Input input(source);
auto iterator = _endpoints.find(input); auto iterator = _endpoints.find(input);
@ -214,7 +208,7 @@ namespace controller {
return getValue(endpoint); return getValue(endpoint);
} }
float NewControllerScriptingInterface::getValue(const Endpoint::Pointer& endpoint) { float ScriptingInterface::getValue(const Endpoint::Pointer& endpoint) const {
auto valuesIterator = _overrideValues.find(endpoint); auto valuesIterator = _overrideValues.find(endpoint);
if (_overrideValues.end() != valuesIterator) { if (_overrideValues.end() != valuesIterator) {
return valuesIterator->second; return valuesIterator->second;
@ -223,19 +217,20 @@ namespace controller {
return endpoint->value(); return endpoint->value();
} }
float ScriptingInterface::getButtonValue(StandardButtonChannel source, uint16_t device) const {
void NewControllerScriptingInterface::update() { return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::BUTTON).getID());
static float last = secTimestampNow(); }
float now = secTimestampNow();
float delta = now - last;
last = now;
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { float ScriptingInterface::getAxisValue(StandardAxisChannel source, uint16_t device) const {
inputPlugin->pluginUpdate(delta, false); return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID());
} }
glm::mat4 ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
return glm::mat4();
}
void ScriptingInterface::update() {
auto userInputMapper = DependencyManager::get<UserInputMapper>(); auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->update(delta);
_overrideValues.clear(); _overrideValues.clear();
EndpointSet readEndpoints; EndpointSet readEndpoints;
@ -295,9 +290,7 @@ namespace controller {
} }
} }
Endpoint::Pointer ScriptingInterface::endpointFor(const QJSValue& endpoint) {
Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const QJSValue& endpoint) {
if (endpoint.isNumber()) { if (endpoint.isNumber()) {
return endpointFor(UserInputMapper::Input(endpoint.toInt())); return endpointFor(UserInputMapper::Input(endpoint.toInt()));
} }
@ -311,7 +304,7 @@ namespace controller {
return Endpoint::Pointer(); return Endpoint::Pointer();
} }
Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const QScriptValue& endpoint) { Endpoint::Pointer ScriptingInterface::endpointFor(const QScriptValue& endpoint) {
if (endpoint.isNumber()) { if (endpoint.isNumber()) {
return endpointFor(UserInputMapper::Input(endpoint.toInt32())); return endpointFor(UserInputMapper::Input(endpoint.toInt32()));
} }
@ -325,7 +318,7 @@ namespace controller {
return Endpoint::Pointer(); return Endpoint::Pointer();
} }
Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) { Endpoint::Pointer ScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) {
auto iterator = _endpoints.find(inputId); auto iterator = _endpoints.find(inputId);
if (_endpoints.end() == iterator) { if (_endpoints.end() == iterator) {
qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16); qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
@ -334,7 +327,7 @@ namespace controller {
return iterator->second; return iterator->second;
} }
Endpoint::Pointer NewControllerScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) { Endpoint::Pointer ScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) {
EndpointPair pair(first, second); EndpointPair pair(first, second);
Endpoint::Pointer result; Endpoint::Pointer result;
auto iterator = _compositeEndpoints.find(pair); auto iterator = _compositeEndpoints.find(pair);
@ -347,6 +340,70 @@ namespace controller {
return result; return result;
} }
bool ScriptingInterface::isPrimaryButtonPressed() const {
return isButtonPressed(StandardButtonChannel::A);
}
glm::vec2 ScriptingInterface::getPrimaryJoystickPosition() const {
return getJoystickPosition(0);
}
int ScriptingInterface::getNumberOfButtons() const {
return StandardButtonChannel::NUM_STANDARD_BUTTONS;
}
bool ScriptingInterface::isButtonPressed(int buttonIndex) const {
return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0 ? false : true;
}
int ScriptingInterface::getNumberOfTriggers() const {
return StandardCounts::TRIGGERS;
}
float ScriptingInterface::getTriggerValue(int triggerIndex) const {
return getAxisValue(triggerIndex == 0 ? StandardAxisChannel::LT : StandardAxisChannel::RT);
}
int ScriptingInterface::getNumberOfJoysticks() const {
return StandardCounts::ANALOG_STICKS;
}
glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const {
StandardAxisChannel xid = StandardAxisChannel::LX;
StandardAxisChannel yid = StandardAxisChannel::LY;
if (joystickIndex != 0) {
xid = StandardAxisChannel::RX;
yid = StandardAxisChannel::RY;
}
vec2 result;
result.x = getAxisValue(xid);
result.y = getAxisValue(yid);
return result;
}
int ScriptingInterface::getNumberOfSpatialControls() const {
return StandardCounts::POSES;
}
glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const {
// FIXME extract the position from the standard pose
return vec3();
}
glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
// FIXME extract the velocity from the standard pose
return vec3();
}
glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const {
// FIXME extract the normal from the standard pose
return vec3();
}
glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
// FIXME extract the rotation from the standard pose
return quat();
}
} // namespace controllers } // namespace controllers
//var mapping = Controller.newMapping(); //var mapping = Controller.newMapping();

View file

@ -0,0 +1,138 @@
//
// AbstractControllerScriptingInterface.h
// libraries/script-engine/src
//
// Created by Brad Hefta-Gaub on 12/17/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_AbstractControllerScriptingInterface_h
#define hifi_AbstractControllerScriptingInterface_h
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <set>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <QtCore/QObject>
#include <QtCore/QVariant>
#include <QtQml/QJSValue>
#include <QtScript/QScriptValue>
#include "UserInputMapper.h"
#include "StandardControls.h"
#include "Mapping.h"
namespace controller {
class InputController : public QObject {
Q_OBJECT
public:
using Key = unsigned int;
using Pointer = std::shared_ptr<InputController>;
virtual void update() = 0;
virtual Key getKey() const = 0;
public slots:
virtual bool isActive() const = 0;
virtual glm::vec3 getAbsTranslation() const = 0;
virtual glm::quat getAbsRotation() const = 0;
virtual glm::vec3 getLocTranslation() const = 0;
virtual glm::quat getLocRotation() const = 0;
signals:
//void spatialEvent(const SpatialEvent& event);
};
/// handles scripting of input controller commands from JS
class ScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(QVariantMap Hardware READ getHardware CONSTANT FINAL)
Q_PROPERTY(QVariantMap Actions READ getActions CONSTANT FINAL)
Q_PROPERTY(QVariantMap Standard READ getStandard CONSTANT FINAL)
public:
ScriptingInterface();
Q_INVOKABLE float getValue(const int& source) const;
Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const;
Q_INVOKABLE glm::mat4 getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
Q_INVOKABLE void disableMapping(const QString& mappingName) {
enableMapping(mappingName, false);
}
Q_INVOKABLE bool isPrimaryButtonPressed() const;
Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const;
Q_INVOKABLE int getNumberOfButtons() const;
Q_INVOKABLE bool isButtonPressed(int buttonIndex) const;
Q_INVOKABLE int getNumberOfTriggers() const;
Q_INVOKABLE float getTriggerValue(int triggerIndex) const;
Q_INVOKABLE int getNumberOfJoysticks() const;
Q_INVOKABLE glm::vec2 getJoystickPosition(int joystickIndex) const;
Q_INVOKABLE int getNumberOfSpatialControls() const;
Q_INVOKABLE glm::vec3 getSpatialControlPosition(int controlIndex) const;
Q_INVOKABLE glm::vec3 getSpatialControlVelocity(int controlIndex) const;
Q_INVOKABLE glm::vec3 getSpatialControlNormal(int controlIndex) const;
Q_INVOKABLE glm::quat getSpatialControlRawRotation(int controlIndex) const;
Q_INVOKABLE const QVariantMap& getHardware() { return _hardware; }
Q_INVOKABLE const QVariantMap& getActions() { return _actions; }
Q_INVOKABLE const QVariantMap& getStandard() { return _standard; }
static QRegularExpression SANITIZE_NAME_EXPRESSION;
public slots:
virtual void update();
virtual void registerControllerTypes(QScriptEngine* engine) = 0;
private:
friend class MappingBuilderProxy;
friend class RouteBuilderProxy;
// FIXME move to unordered set / map
using MappingMap = std::map<QString, Mapping::Pointer>;
using MappingStack = std::list<Mapping::Pointer>;
using InputToEndpointMap = std::map<UserInputMapper::Input, Endpoint::Pointer>;
using EndpointSet = std::unordered_set<Endpoint::Pointer>;
using ValueMap = std::map<Endpoint::Pointer, float>;
using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
void update(Mapping::Pointer& mapping, EndpointSet& consumed);
float getValue(const Endpoint::Pointer& endpoint) const;
Endpoint::Pointer endpointFor(const QJSValue& endpoint);
Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint);
Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
QVariantMap _hardware;
QVariantMap _actions;
QVariantMap _standard;
InputToEndpointMap _endpoints;
EndpointPairMap _compositeEndpoints;
ValueMap _overrideValues;
MappingMap _mappingsByName;
MappingStack _activeMappings;
};
}
#endif // hifi_AbstractControllerScriptingInterface_h

View file

@ -38,59 +38,59 @@ void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> { proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
QVector<UserInputMapper::InputPair> availableInputs; QVector<UserInputMapper::InputPair> availableInputs;
// Buttons // Buttons
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "A")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "B")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "X")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Y")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
// DPad // DPad
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "DU")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "DD")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "DL")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "DR")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
// Bumpers // Bumpers
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "LB")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "RB")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
// Stick press // Stick press
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "LS")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "RS")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
// Center buttons // Center buttons
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::START), "Start")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Back")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
// Analog sticks // Analog sticks
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LY), "LY")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LX), "LX")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RY), "RY")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RX), "RX")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
// Triggers // Triggers
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "LT")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "RT")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
// Poses // Poses
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LeftPose), "LeftPose")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT), "LeftPose"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RightPose), "RightPose")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT), "RightPose"));
// Aliases, PlayStation style names // Aliases, PlayStation style names
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "L1")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "R1")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "L2")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "R2")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "L3")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "R3")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Select")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "Cross")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "Circle")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "Square")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Triangle")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "Up")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "Down")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "Left")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "Right")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
return availableInputs; return availableInputs;
@ -108,14 +108,14 @@ void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) { void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
} }
UserInputMapper::Input StandardController::makeInput(Controllers::StandardButtonChannel button) { UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) {
return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
} }
UserInputMapper::Input StandardController::makeInput(Controllers::StandardAxisChannel axis) { UserInputMapper::Input StandardController::makeInput(controller::StandardAxisChannel axis) {
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
} }
UserInputMapper::Input StandardController::makeInput(Controllers::StandardPoseChannel pose) { UserInputMapper::Input StandardController::makeInput(controller::StandardPoseChannel pose) {
return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE); return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
} }

View file

@ -38,9 +38,9 @@ public:
StandardController() : InputDevice("Standard") {} StandardController() : InputDevice("Standard") {}
~StandardController(); ~StandardController();
UserInputMapper::Input makeInput(Controllers::StandardButtonChannel button); UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
UserInputMapper::Input makeInput(Controllers::StandardAxisChannel axis); UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
UserInputMapper::Input makeInput(Controllers::StandardPoseChannel pose); UserInputMapper::Input makeInput(controller::StandardPoseChannel pose);
private: private:
}; };

View file

@ -7,7 +7,7 @@
// //
#pragma once #pragma once
namespace Controllers { namespace controller {
// Needs to match order and values of SDL_GameControllerButton // Needs to match order and values of SDL_GameControllerButton
enum StandardButtonChannel { enum StandardButtonChannel {
@ -30,7 +30,8 @@ namespace Controllers {
DU, DU,
DD, DD,
DL, DL,
DR DR,
NUM_STANDARD_BUTTONS
}; };
// Needs to match order and values of SDL_GameControllerAxis // Needs to match order and values of SDL_GameControllerAxis
@ -43,13 +44,21 @@ namespace Controllers {
RY, RY,
// Triggers // Triggers
LT, LT,
RT RT,
NUM_STANDARD_AXES
}; };
// No correlation to SDL // No correlation to SDL
enum StandardPoseChannel { enum StandardPoseChannel {
LeftPose = 0, LEFT = 0,
RightPose RIGHT,
HEAD,
NUM_STANDARD_POSES
}; };
enum StandardCounts {
TRIGGERS = 2,
ANALOG_STICKS = 2,
POSES = 2, // FIXME 3? if we want to expose the head?
};
} }

View file

@ -1,368 +1,368 @@
// //
// UserInputMapper.cpp // UserInputMapper.cpp
// input-plugins/src/input-plugins // input-plugins/src/input-plugins
// //
// Created by Sam Gateau on 4/27/15. // Created by Sam Gateau on 4/27/15.
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
// 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 "UserInputMapper.h" #include "UserInputMapper.h"
#include "StandardController.h" #include "StandardController.h"
const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX); const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX);
const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice(); const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice();
const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel(); const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel();
const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType(); const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType();
// Default contruct allocate the poutput size with the current hardcoded action channels // Default contruct allocate the poutput size with the current hardcoded action channels
UserInputMapper::UserInputMapper() { UserInputMapper::UserInputMapper() {
registerStandardDevice(); registerStandardDevice();
assignDefaulActionScales(); assignDefaulActionScales();
createActionNames(); createActionNames();
} }
UserInputMapper::~UserInputMapper() { UserInputMapper::~UserInputMapper() {
} }
bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){ bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
proxy->_name += " (" + QString::number(deviceID) + ")"; proxy->_name += " (" + QString::number(deviceID) + ")";
_registeredDevices[deviceID] = proxy; _registeredDevices[deviceID] = proxy;
return true; return true;
} }
UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) { UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) {
auto device = _registeredDevices.find(input.getDevice()); auto device = _registeredDevices.find(input.getDevice());
if (device != _registeredDevices.end()) { if (device != _registeredDevices.end()) {
return (device->second); return (device->second);
} else { } else {
return DeviceProxy::Pointer(); return DeviceProxy::Pointer();
} }
} }
QString UserInputMapper::getDeviceName(uint16 deviceID) { QString UserInputMapper::getDeviceName(uint16 deviceID) {
if (_registeredDevices.find(deviceID) != _registeredDevices.end()) { if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
return _registeredDevices[deviceID]->_name; return _registeredDevices[deviceID]->_name;
} }
return QString("unknown"); return QString("unknown");
} }
void UserInputMapper::resetAllDeviceBindings() { void UserInputMapper::resetAllDeviceBindings() {
for (auto device : _registeredDevices) { for (auto device : _registeredDevices) {
device.second->resetDeviceBindings(); device.second->resetDeviceBindings();
} }
} }
void UserInputMapper::resetDevice(uint16 deviceID) { void UserInputMapper::resetDevice(uint16 deviceID) {
auto device = _registeredDevices.find(deviceID); auto device = _registeredDevices.find(deviceID);
if (device != _registeredDevices.end()) { if (device != _registeredDevices.end()) {
device->second->resetDeviceBindings(); device->second->resetDeviceBindings();
} }
} }
int UserInputMapper::findDevice(QString name) { int UserInputMapper::findDevice(QString name) {
for (auto device : _registeredDevices) { for (auto device : _registeredDevices) {
if (device.second->_name.split(" (")[0] == name) { if (device.second->_name.split(" (")[0] == name) {
return device.first; return device.first;
} }
} }
return 0; return 0;
} }
QVector<QString> UserInputMapper::getDeviceNames() { QVector<QString> UserInputMapper::getDeviceNames() {
QVector<QString> result; QVector<QString> result;
for (auto device : _registeredDevices) { for (auto device : _registeredDevices) {
QString deviceName = device.second->_name.split(" (")[0]; QString deviceName = device.second->_name.split(" (")[0];
result << deviceName; result << deviceName;
} }
return result; return result;
} }
bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) { bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
return addInputChannel(action, input, Input(), scale); return addInputChannel(action, input, Input(), scale);
} }
bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) { bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) {
// Check that the device is registered // Check that the device is registered
if (!getDeviceProxy(input)) { if (!getDeviceProxy(input)) {
qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped."; qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped.";
return false; return false;
} }
auto inputChannel = InputChannel(input, modifier, action, scale); auto inputChannel = InputChannel(input, modifier, action, scale);
// Insert or replace the input to modifiers // Insert or replace the input to modifiers
if (inputChannel.hasModifier()) { if (inputChannel.hasModifier()) {
auto& modifiers = _inputToModifiersMap[input.getID()]; auto& modifiers = _inputToModifiersMap[input.getID()];
modifiers.push_back(inputChannel._modifier); modifiers.push_back(inputChannel._modifier);
std::sort(modifiers.begin(), modifiers.end()); std::sort(modifiers.begin(), modifiers.end());
} }
// Now update the action To Inputs side of things // Now update the action To Inputs side of things
_actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel)); _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel));
return true; return true;
} }
int UserInputMapper::addInputChannels(const InputChannels& channels) { int UserInputMapper::addInputChannels(const InputChannels& channels) {
int nbAdded = 0; int nbAdded = 0;
for (auto& channel : channels) { for (auto& channel : channels) {
nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale); nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale);
} }
return nbAdded; return nbAdded;
} }
bool UserInputMapper::removeInputChannel(InputChannel inputChannel) { bool UserInputMapper::removeInputChannel(InputChannel inputChannel) {
// Remove from Input to Modifiers map // Remove from Input to Modifiers map
if (inputChannel.hasModifier()) { if (inputChannel.hasModifier()) {
_inputToModifiersMap.erase(inputChannel._input.getID()); _inputToModifiersMap.erase(inputChannel._input.getID());
} }
// Remove from Action to Inputs map // Remove from Action to Inputs map
std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret; std::pair<ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
ret = _actionToInputsMap.equal_range(inputChannel._action); ret = _actionToInputsMap.equal_range(inputChannel._action);
for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) { for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
if (it->second == inputChannel) { if (it->second == inputChannel) {
_actionToInputsMap.erase(it); _actionToInputsMap.erase(it);
return true; return true;
} }
} }
return false; return false;
} }
void UserInputMapper::removeAllInputChannels() { void UserInputMapper::removeAllInputChannels() {
_inputToModifiersMap.clear(); _inputToModifiersMap.clear();
_actionToInputsMap.clear(); _actionToInputsMap.clear();
} }
void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) { void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) {
QVector<InputChannel> channels = getAllInputsForDevice(device); QVector<InputChannel> channels = getAllInputsForDevice(device);
for (auto& channel : channels) { for (auto& channel : channels) {
removeInputChannel(channel); removeInputChannel(channel);
} }
} }
void UserInputMapper::removeDevice(int device) { void UserInputMapper::removeDevice(int device) {
removeAllInputChannelsForDevice((uint16) device); removeAllInputChannelsForDevice((uint16) device);
_registeredDevices.erase(device); _registeredDevices.erase(device);
} }
int UserInputMapper::getInputChannels(InputChannels& channels) const { int UserInputMapper::getInputChannels(InputChannels& channels) const {
for (auto& channel : _actionToInputsMap) { for (auto& channel : _actionToInputsMap) {
channels.push_back(channel.second); channels.push_back(channel.second);
} }
return _actionToInputsMap.size(); return _actionToInputsMap.size();
} }
QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) { QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
InputChannels allChannels; InputChannels allChannels;
getInputChannels(allChannels); getInputChannels(allChannels);
QVector<InputChannel> channels; QVector<InputChannel> channels;
for (InputChannel inputChannel : allChannels) { for (InputChannel inputChannel : allChannels) {
if (inputChannel._input._device == device) { if (inputChannel._input._device == device) {
channels.push_back(inputChannel); channels.push_back(inputChannel);
} }
} }
return channels; return channels;
} }
void UserInputMapper::update(float deltaTime) { void UserInputMapper::update(float deltaTime) {
// Reset the axis state for next loop // Reset the axis state for next loop
for (auto& channel : _actionStates) { for (auto& channel : _actionStates) {
channel = 0.0f; channel = 0.0f;
} }
for (auto& channel : _poseStates) { for (auto& channel : _poseStates) {
channel = PoseValue(); channel = PoseValue();
} }
int currentTimestamp = 0; int currentTimestamp = 0;
for (auto& channelInput : _actionToInputsMap) { for (auto& channelInput : _actionToInputsMap) {
auto& inputMapping = channelInput.second; auto& inputMapping = channelInput.second;
auto& inputID = inputMapping._input; auto& inputID = inputMapping._input;
bool enabled = true; bool enabled = true;
// Check if this input channel has modifiers and collect the possibilities // Check if this input channel has modifiers and collect the possibilities
auto modifiersIt = _inputToModifiersMap.find(inputID.getID()); auto modifiersIt = _inputToModifiersMap.find(inputID.getID());
if (modifiersIt != _inputToModifiersMap.end()) { if (modifiersIt != _inputToModifiersMap.end()) {
Modifiers validModifiers; Modifiers validModifiers;
bool isActiveModifier = false; bool isActiveModifier = false;
for (auto& modifier : modifiersIt->second) { for (auto& modifier : modifiersIt->second) {
auto deviceProxy = getDeviceProxy(modifier); auto deviceProxy = getDeviceProxy(modifier);
if (deviceProxy->getButton(modifier, currentTimestamp)) { if (deviceProxy->getButton(modifier, currentTimestamp)) {
validModifiers.push_back(modifier); validModifiers.push_back(modifier);
isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID()); isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID());
} }
} }
enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier; enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier;
} }
// if enabled: default input or all modifiers on // if enabled: default input or all modifiers on
if (enabled) { if (enabled) {
auto deviceProxy = getDeviceProxy(inputID); auto deviceProxy = getDeviceProxy(inputID);
switch (inputMapping._input.getType()) { switch (inputMapping._input.getType()) {
case ChannelType::BUTTON: { case ChannelType::BUTTON: {
_actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime
break; break;
} }
case ChannelType::AXIS: { case ChannelType::AXIS: {
_actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp); _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp);
break; break;
} }
case ChannelType::POSE: { case ChannelType::POSE: {
if (!_poseStates[channelInput.first].isValid()) { if (!_poseStates[channelInput.first].isValid()) {
_poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp); _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp);
} }
break; break;
} }
default: { default: {
break; //silence please break; //silence please
} }
} }
} else{ } else{
// Channel input not enabled // Channel input not enabled
enabled = false; enabled = false;
} }
} }
// Scale all the channel step with the scale // Scale all the channel step with the scale
static const float EPSILON = 0.01f; static const float EPSILON = 0.01f;
for (auto i = 0; i < NUM_ACTIONS; i++) { for (auto i = 0; i < NUM_ACTIONS; i++) {
_actionStates[i] *= _actionScales[i]; _actionStates[i] *= _actionScales[i];
// Emit only on change, and emit when moving back to 0 // Emit only on change, and emit when moving back to 0
if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) { if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) {
_lastActionStates[i] = _actionStates[i]; _lastActionStates[i] = _actionStates[i];
emit actionEvent(i, _actionStates[i]); emit actionEvent(i, _actionStates[i]);
} }
// TODO: emit signal for pose changes // TODO: emit signal for pose changes
} }
} }
QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const { QVector<UserInputMapper::Action> UserInputMapper::getAllActions() const {
QVector<Action> actions; QVector<Action> actions;
for (auto i = 0; i < NUM_ACTIONS; i++) { for (auto i = 0; i < NUM_ACTIONS; i++) {
actions.append(Action(i)); actions.append(Action(i));
} }
return actions; return actions;
} }
QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) { QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
QVector<InputChannel> inputChannels; QVector<InputChannel> inputChannels;
std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret; std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> ret;
ret = _actionToInputsMap.equal_range(action); ret = _actionToInputsMap.equal_range(action);
for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) { for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) {
inputChannels.append(it->second); inputChannels.append(it->second);
} }
return inputChannels; return inputChannels;
} }
int UserInputMapper::findAction(const QString& actionName) const { int UserInputMapper::findAction(const QString& actionName) const {
auto actions = getAllActions(); auto actions = getAllActions();
for (auto action : actions) { for (auto action : actions) {
if (getActionName(action) == actionName) { if (getActionName(action) == actionName) {
return action; return action;
} }
} }
// If the action isn't found, return -1 // If the action isn't found, return -1
return -1; return -1;
} }
QVector<QString> UserInputMapper::getActionNames() const { QVector<QString> UserInputMapper::getActionNames() const {
QVector<QString> result; QVector<QString> result;
for (auto i = 0; i < NUM_ACTIONS; i++) { for (auto i = 0; i < NUM_ACTIONS; i++) {
result << _actionNames[i]; result << _actionNames[i];
} }
return result; return result;
} }
void UserInputMapper::assignDefaulActionScales() { void UserInputMapper::assignDefaulActionScales() {
_actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit
_actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit
_actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit
_actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit
_actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit
_actionScales[VERTICAL_UP] = 1.0f; // 1m per unit _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit
_actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit
_actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit
_actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit
_actionScales[PITCH_UP] = 1.0f; // 1 degree per unit _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
_actionScales[BOOM_IN] = 0.5f; // .5m per unit _actionScales[BOOM_IN] = 0.5f; // .5m per unit
_actionScales[BOOM_OUT] = 0.5f; // .5m per unit _actionScales[BOOM_OUT] = 0.5f; // .5m per unit
_actionScales[LEFT_HAND] = 1.0f; // default _actionScales[LEFT_HAND] = 1.0f; // default
_actionScales[RIGHT_HAND] = 1.0f; // default _actionScales[RIGHT_HAND] = 1.0f; // default
_actionScales[LEFT_HAND_CLICK] = 1.0f; // on _actionScales[LEFT_HAND_CLICK] = 1.0f; // on
_actionScales[RIGHT_HAND_CLICK] = 1.0f; // on _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on
_actionStates[SHIFT] = 1.0f; // on _actionStates[SHIFT] = 1.0f; // on
_actionStates[ACTION1] = 1.0f; // default _actionStates[ACTION1] = 1.0f; // default
_actionStates[ACTION2] = 1.0f; // default _actionStates[ACTION2] = 1.0f; // default
_actionStates[TranslateX] = 1.0f; // default _actionStates[TRANSLATE_X] = 1.0f; // default
_actionStates[TranslateY] = 1.0f; // default _actionStates[TRANSLATE_Y] = 1.0f; // default
_actionStates[TranslateZ] = 1.0f; // default _actionStates[TRANSLATE_Z] = 1.0f; // default
_actionStates[Roll] = 1.0f; // default _actionStates[ROLL] = 1.0f; // default
_actionStates[Pitch] = 1.0f; // default _actionStates[PITCH] = 1.0f; // default
_actionStates[Yaw] = 1.0f; // default _actionStates[YAW] = 1.0f; // default
} }
// This is only necessary as long as the actions are hardcoded // This is only necessary as long as the actions are hardcoded
// Eventually you can just add the string when you add the action // Eventually you can just add the string when you add the action
void UserInputMapper::createActionNames() { void UserInputMapper::createActionNames() {
_actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD"; _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD";
_actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD"; _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD";
_actionNames[LATERAL_LEFT] = "LATERAL_LEFT"; _actionNames[LATERAL_LEFT] = "LATERAL_LEFT";
_actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT"; _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT";
_actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN"; _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN";
_actionNames[VERTICAL_UP] = "VERTICAL_UP"; _actionNames[VERTICAL_UP] = "VERTICAL_UP";
_actionNames[YAW_LEFT] = "YAW_LEFT"; _actionNames[YAW_LEFT] = "YAW_LEFT";
_actionNames[YAW_RIGHT] = "YAW_RIGHT"; _actionNames[YAW_RIGHT] = "YAW_RIGHT";
_actionNames[PITCH_DOWN] = "PITCH_DOWN"; _actionNames[PITCH_DOWN] = "PITCH_DOWN";
_actionNames[PITCH_UP] = "PITCH_UP"; _actionNames[PITCH_UP] = "PITCH_UP";
_actionNames[BOOM_IN] = "BOOM_IN"; _actionNames[BOOM_IN] = "BOOM_IN";
_actionNames[BOOM_OUT] = "BOOM_OUT"; _actionNames[BOOM_OUT] = "BOOM_OUT";
_actionNames[LEFT_HAND] = "LEFT_HAND"; _actionNames[LEFT_HAND] = "LEFT_HAND";
_actionNames[RIGHT_HAND] = "RIGHT_HAND"; _actionNames[RIGHT_HAND] = "RIGHT_HAND";
_actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK"; _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK";
_actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK"; _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK";
_actionNames[SHIFT] = "SHIFT"; _actionNames[SHIFT] = "SHIFT";
_actionNames[ACTION1] = "ACTION1"; _actionNames[ACTION1] = "ACTION1";
_actionNames[ACTION2] = "ACTION2"; _actionNames[ACTION2] = "ACTION2";
_actionNames[CONTEXT_MENU] = "CONTEXT_MENU"; _actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
_actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE"; _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
_actionNames[TranslateX] = "TranslateX"; _actionNames[TRANSLATE_X] = "TranslateX";
_actionNames[TranslateY] = "TranslateY"; _actionNames[TRANSLATE_Y] = "TranslateY";
_actionNames[TranslateZ] = "TranslateZ"; _actionNames[TRANSLATE_Z] = "TranslateZ";
_actionNames[Roll] = "Roll"; _actionNames[ROLL] = "Roll";
_actionNames[Pitch] = "Pitch"; _actionNames[PITCH] = "Pitch";
_actionNames[Yaw] = "Yaw"; _actionNames[YAW] = "Yaw";
} }
void UserInputMapper::registerStandardDevice() { void UserInputMapper::registerStandardDevice() {
_standardController = std::make_shared<StandardController>(); _standardController = std::make_shared<StandardController>();
_standardController->registerToUserInputMapper(*this); _standardController->registerToUserInputMapper(*this);
} }
float UserInputMapper::DeviceProxy::getValue(const Input& input, int timestamp) const { float UserInputMapper::DeviceProxy::getValue(const Input& input, int timestamp) const {
switch (input.getType()) { switch (input.getType()) {
case UserInputMapper::ChannelType::BUTTON: case UserInputMapper::ChannelType::BUTTON:
return getButton(input, timestamp) ? 1.0f : 0.0f; return getButton(input, timestamp) ? 1.0f : 0.0f;
case UserInputMapper::ChannelType::AXIS: case UserInputMapper::ChannelType::AXIS:
return getAxis(input, timestamp); return getAxis(input, timestamp);
case UserInputMapper::ChannelType::POSE: case UserInputMapper::ChannelType::POSE:
return getPose(input, timestamp)._valid ? 1.0f : 0.0f; return getPose(input, timestamp)._valid ? 1.0f : 0.0f;
default: default:
return 0.0f; return 0.0f;
} }
} }

View file

@ -146,44 +146,52 @@ public:
// Actions are the output channels of the Mapper, that's what the InputChannel map to // Actions are the output channels of the Mapper, that's what the InputChannel map to
// For now the Actions are hardcoded, this is bad, but we will fix that in the near future // For now the Actions are hardcoded, this is bad, but we will fix that in the near future
enum Action { enum Action {
LONGITUDINAL_BACKWARD = 0, TRANSLATE_X = 0,
LONGITUDINAL_FORWARD, TRANSLATE_Y,
TRANSLATE_Z,
ROTATE_X, PITCH = ROTATE_X,
ROTATE_Y, YAW = ROTATE_Y,
ROTATE_Z, ROLL = ROTATE_Z,
LATERAL_LEFT, TRANSLATE_CAMERA_Z,
LATERAL_RIGHT,
VERTICAL_DOWN,
VERTICAL_UP,
YAW_LEFT,
YAW_RIGHT,
PITCH_DOWN,
PITCH_UP,
BOOM_IN,
BOOM_OUT,
LEFT_HAND, LEFT_HAND,
RIGHT_HAND, RIGHT_HAND,
LEFT_HAND_CLICK, LEFT_HAND_CLICK,
RIGHT_HAND_CLICK, RIGHT_HAND_CLICK,
SHIFT,
ACTION1, ACTION1,
ACTION2, ACTION2,
CONTEXT_MENU, CONTEXT_MENU,
TOGGLE_MUTE, TOGGLE_MUTE,
TranslateX, SHIFT,
TranslateY,
TranslateZ, // Biseced aliases for TRANSLATE_Z
Roll, LONGITUDINAL_BACKWARD,
Pitch, LONGITUDINAL_FORWARD,
Yaw,
// Biseced aliases for TRANSLATE_X
LATERAL_LEFT,
LATERAL_RIGHT,
// Biseced aliases for TRANSLATE_Y
VERTICAL_DOWN,
VERTICAL_UP,
// Biseced aliases for ROTATE_Y
YAW_LEFT,
YAW_RIGHT,
// Biseced aliases for ROTATE_X
PITCH_DOWN,
PITCH_UP,
// Biseced aliases for TRANSLATE_CAMERA_Z
BOOM_IN,
BOOM_OUT,
NUM_ACTIONS, NUM_ACTIONS,
}; };

View file

@ -12,7 +12,7 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include "RouteBuilderProxy.h" #include "RouteBuilderProxy.h"
#include "../NewControllerScriptingInterface.h" #include "../ScriptingInterface.h"
#include "../Logging.h" #include "../Logging.h"
namespace controller { namespace controller {

View file

@ -20,12 +20,14 @@ class QScriptValue;
namespace controller { namespace controller {
class NewControllerScriptingInterface; class ScriptingInterface;
// TODO migrate functionality to a MappingBuilder class and make the proxy defer to that
// (for easier use in both C++ and JS)
class MappingBuilderProxy : public QObject { class MappingBuilderProxy : public QObject {
Q_OBJECT Q_OBJECT
public: public:
MappingBuilderProxy(NewControllerScriptingInterface& parent, Mapping::Pointer mapping) MappingBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping)
: _parent(parent), _mapping(mapping) { } : _parent(parent), _mapping(mapping) { }
Q_INVOKABLE QObject* from(const QJSValue& source); Q_INVOKABLE QObject* from(const QJSValue& source);
@ -38,7 +40,7 @@ protected:
QObject* from(const Endpoint::Pointer& source); QObject* from(const Endpoint::Pointer& source);
friend class RouteBuilderProxy; friend class RouteBuilderProxy;
NewControllerScriptingInterface& _parent; ScriptingInterface& _parent;
Mapping::Pointer _mapping; Mapping::Pointer _mapping;
}; };

View file

@ -12,7 +12,7 @@
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include "MappingBuilderProxy.h" #include "MappingBuilderProxy.h"
#include "../NewControllerScriptingInterface.h" #include "../ScriptingInterface.h"
#include "../Logging.h" #include "../Logging.h"
namespace controller { namespace controller {

View file

@ -19,12 +19,14 @@ class QScriptValue;
namespace controller { namespace controller {
class NewControllerScriptingInterface; class ScriptingInterface;
// TODO migrate functionality to a RouteBuilder class and make the proxy defer to that
// (for easier use in both C++ and JS)
class RouteBuilderProxy : public QObject { class RouteBuilderProxy : public QObject {
Q_OBJECT Q_OBJECT
public: public:
RouteBuilderProxy(NewControllerScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route) RouteBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route)
: _parent(parent), _mapping(mapping), _route(route) { } : _parent(parent), _mapping(mapping), _route(route) { }
Q_INVOKABLE void to(const QJSValue& destination); Q_INVOKABLE void to(const QJSValue& destination);
@ -47,7 +49,7 @@ class RouteBuilderProxy : public QObject {
Mapping::Pointer _mapping; Mapping::Pointer _mapping;
Route::Pointer _route; Route::Pointer _route;
NewControllerScriptingInterface& _parent; ScriptingInterface& _parent;
}; };
} }

View file

@ -1,7 +1,7 @@
set(TARGET_NAME entities-renderer) set(TARGET_NAME entities-renderer)
AUTOSCRIBE_SHADER_LIB(gpu model render render-utils) AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
setup_hifi_library(Widgets Network Script) setup_hifi_library(Widgets Network Script)
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils) link_hifi_libraries(shared gpu procedural model model-networking script-engine controllers render render-utils)
target_bullet() target_bullet()

View file

@ -1,6 +1,6 @@
set(TARGET_NAME input-plugins) set(TARGET_NAME input-plugins)
setup_hifi_library() setup_hifi_library()
link_hifi_libraries(shared plugins gpu render-utils) link_hifi_libraries(shared plugins controllers)
GroupSources("src/input-plugins") GroupSources("src/input-plugins")

View file

@ -23,7 +23,7 @@ InputPluginList getInputPlugins() {
new KeyboardMouseDevice(), new KeyboardMouseDevice(),
new SDL2Manager(), new SDL2Manager(),
new SixenseManager(), new SixenseManager(),
//new ViveControllerManager(), new ViveControllerManager(),
nullptr nullptr
}; };

View file

@ -1,167 +1,164 @@
// //
// Joystick.cpp // Joystick.cpp
// input-plugins/src/input-plugins // input-plugins/src/input-plugins
// //
// Created by Stephen Birarda on 2014-09-23. // Created by Stephen Birarda on 2014-09-23.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
// //
// 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 <limits> #include "Joystick.h"
#include <glm/glm.hpp> #include <limits>
#include <glm/glm.hpp>
#include "Joystick.h"
const float CONTROLLER_THRESHOLD = 0.3f;
#include "StandardControls.h"
#ifdef HAVE_SDL2
const float CONTROLLER_THRESHOLD = 0.3f; const float MAX_AXIS = 32768.0f;
#ifdef HAVE_SDL2 Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
const float MAX_AXIS = 32768.0f; InputDevice(name),
_sdlGameController(sdlGameController),
Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) : _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
InputDevice(name), _instanceId(instanceId)
_sdlGameController(sdlGameController), {
_sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
_instanceId(instanceId) }
{
#endif
}
Joystick::~Joystick() {
#endif closeJoystick();
}
Joystick::~Joystick() {
closeJoystick(); void Joystick::closeJoystick() {
} #ifdef HAVE_SDL2
SDL_GameControllerClose(_sdlGameController);
void Joystick::closeJoystick() { #endif
#ifdef HAVE_SDL2 }
SDL_GameControllerClose(_sdlGameController);
#endif void Joystick::update(float deltaTime, bool jointsCaptured) {
} for (auto axisState : _axisStateMap) {
if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
void Joystick::update(float deltaTime, bool jointsCaptured) { _axisStateMap[axisState.first] = 0.0f;
for (auto axisState : _axisStateMap) { }
if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { }
_axisStateMap[axisState.first] = 0.0f; }
}
} void Joystick::focusOutEvent() {
} _axisStateMap.clear();
_buttonPressedMap.clear();
void Joystick::focusOutEvent() { };
_axisStateMap.clear();
_buttonPressedMap.clear(); #ifdef HAVE_SDL2
};
void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
#ifdef HAVE_SDL2 SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
_axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) { }
SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
_axisStateMap[makeInput((Controllers::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS; void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
} auto input = makeInput((controller::StandardButtonChannel)event.button);
bool newValue = event.state == SDL_PRESSED;
void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) { if (newValue) {
auto input = makeInput((Controllers::StandardButtonChannel)event.button); _buttonPressedMap.insert(input.getChannel());
bool newValue = event.state == SDL_PRESSED; } else {
if (newValue) { _buttonPressedMap.erase(input.getChannel());
_buttonPressedMap.insert(input.getChannel()); }
} else { }
_buttonPressedMap.erase(input.getChannel());
} #endif
}
#endif void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
// Grab the current free device ID
_deviceID = mapper.getFreeDeviceID();
void Joystick::registerToUserInputMapper(UserInputMapper& mapper) {
// Grab the current free device ID auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
_deviceID = mapper.getFreeDeviceID(); 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()); };
auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name); proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; QVector<UserInputMapper::InputPair> availableInputs;
proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; // Buttons
proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> { availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A"));
QVector<UserInputMapper::InputPair> availableInputs; availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B"));
// Buttons availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "A")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "B"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "X")); // DPad
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Y")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU"));
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD"));
// DPad availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "DU")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "DD"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "DL")); // Bumpers
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "DR")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB"));
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB"));
// Bumpers
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "LB")); // Stick press
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "RB")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS"));
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS"));
// Stick press
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "LS")); // Center buttons
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "RS")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start"));
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back"));
// Center buttons
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::START), "Start")); // Analog sticks
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Back")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY"));
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX"));
// Analog sticks availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LY), "LY")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LX), "LX"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RY), "RY")); // Triggers
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RX), "RX")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT"));
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT"));
// Triggers
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "LT")); // Aliases, PlayStation style names
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "RT")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1"));
availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1"));
// Aliases, PlayStation style names availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "L1")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "R1")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "L2")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "R2")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "L3")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "R3")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Select")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "Cross")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "Circle")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "Square")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Triangle")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "Up")); availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "Down"));
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "Left")); return availableInputs;
availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "Right")); };
proxy->resetDeviceBindings = [this, &mapper] () -> bool {
return availableInputs; mapper.removeAllInputChannelsForDevice(_deviceID);
}; this->assignDefaultInputMapping(mapper);
proxy->resetDeviceBindings = [this, &mapper] () -> bool { return true;
mapper.removeAllInputChannelsForDevice(_deviceID); };
this->assignDefaultInputMapping(mapper); mapper.registerDevice(_deviceID, proxy);
return true; }
};
mapper.registerDevice(_deviceID, proxy); void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
} #ifdef HAVE_SDL2
const float JOYSTICK_MOVE_SPEED = 1.0f;
void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) { const float DPAD_MOVE_SPEED = 0.5f;
#ifdef HAVE_SDL2 const float JOYSTICK_YAW_SPEED = 0.5f;
const float JOYSTICK_MOVE_SPEED = 1.0f; const float JOYSTICK_PITCH_SPEED = 0.25f;
const float DPAD_MOVE_SPEED = 0.5f; const float BOOM_SPEED = 0.1f;
const float JOYSTICK_YAW_SPEED = 0.5f;
const float JOYSTICK_PITCH_SPEED = 0.25f; #endif
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(Controllers::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);
}
UserInputMapper::Input Joystick::makeInput(Controllers::StandardAxisChannel axis) {
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
}

View file

@ -1,73 +1,73 @@
// //
// Joystick.h // Joystick.h
// input-plugins/src/input-plugins // input-plugins/src/input-plugins
// //
// Created by Stephen Birarda on 2014-09-23. // Created by Stephen Birarda on 2014-09-23.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
// //
// 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
// //
#ifndef hifi_Joystick_h #ifndef hifi_Joystick_h
#define hifi_Joystick_h #define hifi_Joystick_h
#include <qobject.h> #include <qobject.h>
#include <qvector.h> #include <qvector.h>
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
#include <SDL.h> #include <SDL.h>
#undef main #undef main
#endif #endif
#include "InputDevice.h" #include <controllers/InputDevice.h>
#include "StandardControls.h" #include <controllers/StandardControls.h>
class Joystick : public QObject, public InputDevice { class Joystick : public QObject, public InputDevice {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString name READ getName) Q_PROPERTY(QString name READ getName)
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
Q_PROPERTY(int instanceId READ getInstanceId) Q_PROPERTY(int instanceId READ getInstanceId)
#endif #endif
public: public:
const QString& getName() const { return _name; } const QString& getName() const { return _name; }
// Device functions // Device functions
virtual void registerToUserInputMapper(UserInputMapper& mapper) override; virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
virtual void update(float deltaTime, bool jointsCaptured) override; virtual void update(float deltaTime, bool jointsCaptured) override;
virtual void focusOutEvent() override; virtual void focusOutEvent() override;
Joystick() : InputDevice("Joystick") {} Joystick() : InputDevice("Joystick") {}
~Joystick(); ~Joystick();
UserInputMapper::Input makeInput(Controllers::StandardButtonChannel button); UserInputMapper::Input makeInput(controller::StandardButtonChannel button);
UserInputMapper::Input makeInput(Controllers::StandardAxisChannel axis); UserInputMapper::Input makeInput(controller::StandardAxisChannel axis);
#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
void closeJoystick(); void closeJoystick();
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
void handleAxisEvent(const SDL_ControllerAxisEvent& event); void handleAxisEvent(const SDL_ControllerAxisEvent& event);
void handleButtonEvent(const SDL_ControllerButtonEvent& event); void handleButtonEvent(const SDL_ControllerButtonEvent& event);
#endif #endif
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
int getInstanceId() const { return _instanceId; } int getInstanceId() const { return _instanceId; }
#endif #endif
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
}; };
#endif // hifi_Joystick_h #endif // hifi_Joystick_h

View file

@ -16,7 +16,7 @@
#include <QtCore/QPoint> #include <QtCore/QPoint>
#include "InputDevice.h" #include <controllers/InputDevice.h>
#include "InputPlugin.h" #include "InputPlugin.h"
class QTouchEvent; class QTouchEvent;

View file

@ -16,9 +16,9 @@
#include <SDL.h> #include <SDL.h>
#endif #endif
#include "InputPlugin.h" #include <controllers/UserInputMapper.h>
#include "UserInputMapper.h"
#include "InputPlugin.h"
#include "Joystick.h" #include "Joystick.h"
class SDL2Manager : public InputPlugin { class SDL2Manager : public InputPlugin {

View file

@ -24,8 +24,9 @@
#endif #endif
#include <controllers/InputDevice.h>
#include "InputPlugin.h" #include "InputPlugin.h"
#include "InputDevice.h"
class QLibrary; class QLibrary;

View file

@ -19,7 +19,7 @@
#include <model/Geometry.h> #include <model/Geometry.h>
#include <gpu/Texture.h> #include <gpu/Texture.h>
#include "InputDevice.h" #include <controllers/InputDevice.h>
#include "InputPlugin.h" #include "InputPlugin.h"
#include <RenderArgs.h> #include <RenderArgs.h>
#include <render/Scene.h> #include <render/Scene.h>

View file

@ -1,3 +1,3 @@
set(TARGET_NAME script-engine) set(TARGET_NAME script-engine)
setup_hifi_library(Gui Network Script WebSockets Widgets) setup_hifi_library(Gui Network Script WebSockets Widgets)
link_hifi_libraries(shared networking octree gpu procedural model model-networking fbx entities animation audio physics) link_hifi_libraries(shared networking octree gpu procedural model model-networking fbx entities controllers animation audio physics)

View file

@ -1,125 +0,0 @@
//
// AbstractControllerScriptingInterface.h
// libraries/script-engine/src
//
// Created by Brad Hefta-Gaub on 12/17/13.
// Copyright 2013 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
//
#ifndef hifi_AbstractControllerScriptingInterface_h
#define hifi_AbstractControllerScriptingInterface_h
#include <QtCore/QObject>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "HFActionEvent.h"
#include "KeyEvent.h"
#include "MouseEvent.h"
#include "SpatialEvent.h"
#include "TouchEvent.h"
#include "WheelEvent.h"
class ScriptEngine;
class AbstractInputController : public QObject {
Q_OBJECT
public:
typedef unsigned int Key;
virtual void update() = 0;
virtual Key getKey() const = 0;
public slots:
virtual bool isActive() const = 0;
virtual glm::vec3 getAbsTranslation() const = 0;
virtual glm::quat getAbsRotation() const = 0;
virtual glm::vec3 getLocTranslation() const = 0;
virtual glm::quat getLocRotation() const = 0;
signals:
void spatialEvent(const SpatialEvent& event);
};
/// handles scripting of input controller commands from JS
class AbstractControllerScriptingInterface : public QObject {
Q_OBJECT
public slots:
virtual void registerControllerTypes(ScriptEngine* engine) = 0;
virtual bool isPrimaryButtonPressed() const = 0;
virtual glm::vec2 getPrimaryJoystickPosition() const = 0;
virtual int getNumberOfButtons() const = 0;
virtual bool isButtonPressed(int buttonIndex) const = 0;
virtual int getNumberOfTriggers() const = 0;
virtual float getTriggerValue(int triggerIndex) const = 0;
virtual int getNumberOfJoysticks() const = 0;
virtual glm::vec2 getJoystickPosition(int joystickIndex) const = 0;
virtual int getNumberOfSpatialControls() const = 0;
virtual glm::vec3 getSpatialControlPosition(int controlIndex) const = 0;
virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const = 0;
virtual glm::vec3 getSpatialControlNormal(int controlIndex) const = 0;
virtual glm::quat getSpatialControlRawRotation(int controlIndex) const = 0;
virtual void captureKeyEvents(const KeyEvent& event) = 0;
virtual void releaseKeyEvents(const KeyEvent& event) = 0;
virtual void captureMouseEvents() = 0;
virtual void releaseMouseEvents() = 0;
virtual void captureTouchEvents() = 0;
virtual void releaseTouchEvents() = 0;
virtual void captureWheelEvents() = 0;
virtual void releaseWheelEvents() = 0;
virtual void captureActionEvents() = 0;
virtual void releaseActionEvents() = 0;
virtual void captureJoystick(int joystickIndex) = 0;
virtual void releaseJoystick(int joystickIndex) = 0;
virtual glm::vec2 getViewportDimensions() const = 0;
virtual AbstractInputController* createInputController( const QString& category, const QString& tracker ) = 0;
signals:
void keyPressEvent(const KeyEvent& event);
void keyReleaseEvent(const KeyEvent& event);
void actionStartEvent(const HFActionEvent& event);
void actionEndEvent(const HFActionEvent& event);
void backStartEvent();
void backEndEvent();
void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0);
void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0);
void touchBeginEvent(const TouchEvent& event);
void touchEndEvent(const TouchEvent& event);
void touchUpdateEvent(const TouchEvent& event);
void wheelEvent(const WheelEvent& event);
void actionEvent(int action, float state);
};
#endif // hifi_AbstractControllerScriptingInterface_h

View file

@ -12,7 +12,10 @@
#ifndef hifi_AbstractScriptingServicesInterface_h #ifndef hifi_AbstractScriptingServicesInterface_h
#define hifi_AbstractScriptingServicesInterface_h #define hifi_AbstractScriptingServicesInterface_h
class AbstractControllerScriptingInterface; namespace controller {
class ScriptingInterface;
}
class Transform; class Transform;
class ScriptEngine; class ScriptEngine;
class QThread; class QThread;
@ -22,7 +25,7 @@ class AbstractScriptingServicesInterface {
public: public:
/// Returns the controller interface for the application /// Returns the controller interface for the application
virtual AbstractControllerScriptingInterface* getControllerScriptingInterface() = 0; virtual controller::ScriptingInterface* getControllerScriptingInterface() = 0;
/// Registers application specific services with a script engine. /// Registers application specific services with a script engine.
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) = 0; virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) = 0;

View file

@ -76,16 +76,16 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) {
out = qobject_cast<AvatarData*>(object.toQObject()); out = qobject_cast<AvatarData*>(object.toQObject());
} }
QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) { QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) {
return engine->newQObject(in); return engine->newQObject(in);
} }
void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputController* &out) { void inputControllerFromScriptValue(const QScriptValue &object, controller::InputController* &out) {
out = qobject_cast<AbstractInputController*>(object.toQObject()); out = qobject_cast<controller::InputController*>(object.toQObject());
} }
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) : controller::ScriptingInterface* controllerScriptingInterface, bool wantSignals) :
_scriptContents(scriptContents), _scriptContents(scriptContents),
_isFinished(false), _isFinished(false),
@ -93,7 +93,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
_isInitialized(false), _isInitialized(false),
_timerFunctionMap(), _timerFunctionMap(),
_wantSignals(wantSignals), _wantSignals(wantSignals),
_controllerScriptingInterface(controllerScriptingInterface), _controllerScriptingInterface(controllerScriptingInterface),
_fileNameString(fileNameString), _fileNameString(fileNameString),
_quatLibrary(), _quatLibrary(),
_vec3Library(), _vec3Library(),

View file

@ -26,8 +26,10 @@
#include <LimitedNodeList.h> #include <LimitedNodeList.h>
#include <EntityItemID.h> #include <EntityItemID.h>
#include <EntitiesScriptEngineProvider.h> #include <EntitiesScriptEngineProvider.h>
#include <controllers/ScriptingInterface.h>
#include "AbstractControllerScriptingInterface.h"
#include "MouseEvent.h"
#include "ArrayBufferClass.h" #include "ArrayBufferClass.h"
#include "AudioScriptingInterface.h" #include "AudioScriptingInterface.h"
#include "Quat.h" #include "Quat.h"
@ -53,7 +55,7 @@ class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScr
public: public:
ScriptEngine(const QString& scriptContents = NO_SCRIPT, ScriptEngine(const QString& scriptContents = NO_SCRIPT,
const QString& fileNameString = QString(""), const QString& fileNameString = QString(""),
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL, controller::ScriptingInterface* controllerScriptingInterface = nullptr,
bool wantSignals = true); bool wantSignals = true);
~ScriptEngine(); ~ScriptEngine();
@ -182,7 +184,7 @@ private:
QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot);
void stopTimer(QTimer* timer); void stopTimer(QTimer* timer);
AbstractControllerScriptingInterface* _controllerScriptingInterface; controller::ScriptingInterface* _controllerScriptingInterface;
QString _fileNameString; QString _fileNameString;
Quat _quatLibrary; Quat _quatLibrary;
Vec3 _vec3Library; Vec3 _vec3Library;

View file

@ -8,17 +8,17 @@ import "./controls"
Column { Column {
id: root id: root
property var actions: NewControllers.Actions property var actions: Controllers.Actions
property var standard: NewControllers.Standard property var standard: Controllers.Standard
property var testMapping: null property var testMapping: null
property var xbox: null property var xbox: null
Component.onCompleted: { Component.onCompleted: {
var patt = /^X360Controller/; var patt = /^X360Controller/;
for (var prop in NewControllers.Hardware) { for (var prop in Controllers.Hardware) {
if(patt.test(prop)) { if(patt.test(prop)) {
root.xbox = NewControllers.Hardware[prop] root.xbox = Controllers.Hardware[prop]
break break
} }
} }
@ -29,7 +29,7 @@ Column {
Timer { Timer {
interval: 50; running: true; repeat: true interval: 50; running: true; repeat: true
onTriggered: { onTriggered: {
NewControllers.update(); Controllers.update();
} }
} }
@ -38,7 +38,7 @@ Column {
Button { Button {
text: "Default Mapping" text: "Default Mapping"
onClicked: { onClicked: {
var mapping = NewControllers.newMapping("Default"); var mapping = Controllers.newMapping("Default");
mapping.from(xbox.A).to(standard.A); mapping.from(xbox.A).to(standard.A);
mapping.from(xbox.B).to(standard.B); mapping.from(xbox.B).to(standard.B);
mapping.from(xbox.X).to(standard.X); mapping.from(xbox.X).to(standard.X);
@ -59,7 +59,7 @@ Column {
mapping.from(xbox.RX).to(standard.RX); mapping.from(xbox.RX).to(standard.RX);
mapping.from(xbox.LT).to(standard.LT); mapping.from(xbox.LT).to(standard.LT);
mapping.from(xbox.RT).to(standard.RT); mapping.from(xbox.RT).to(standard.RT);
NewControllers.enableMapping("Default"); Controllers.enableMapping("Default");
enabled = false; enabled = false;
text = "Built" text = "Built"
} }
@ -68,16 +68,35 @@ Column {
Button { Button {
text: "Build Mapping" text: "Build Mapping"
onClicked: { onClicked: {
var mapping = NewControllers.newMapping(); var mapping = Controllers.newMapping();
// Inverting a value // Inverting a value
mapping.from(xbox.RY).invert().to(standard.RY); mapping.from(xbox.RY).invert().to(standard.RY);
// Assigning a value from a function // Assigning a value from a function
mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX); mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX);
// Constrainting a value to -1, 0, or 1, with a deadzone // Constrainting a value to -1, 0, or 1, with a deadzone
mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY); mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY);
mapping.join(standard.LB, standard.RB).pulse(0.5).to(actions.Yaw); // change join to makeAxis
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(0, 1).invert().to(actions.YAW_RIGHT);
mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT); 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; testMapping = mapping;
enabled = false enabled = false
text = "Built" text = "Built"
@ -105,7 +124,7 @@ Column {
Row { Row {
spacing: 8 spacing: 8
ScrollingGraph { ScrollingGraph {
controlId: NewControllers.Actions.Yaw controlId: Controllers.Actions.Yaw
label: "Yaw" label: "Yaw"
min: -3.0 min: -3.0
max: 3.0 max: 3.0
@ -113,7 +132,7 @@ Column {
} }
ScrollingGraph { ScrollingGraph {
controlId: NewControllers.Actions.YAW_LEFT controlId: Controllers.Actions.YAW_LEFT
label: "Yaw Left" label: "Yaw Left"
min: -3.0 min: -3.0
max: 3.0 max: 3.0
@ -121,7 +140,7 @@ Column {
} }
ScrollingGraph { ScrollingGraph {
controlId: NewControllers.Actions.YAW_RIGHT controlId: Controllers.Actions.YAW_RIGHT
label: "Yaw Right" label: "Yaw Right"
min: -3.0 min: -3.0
max: 3.0 max: 3.0

View file

@ -13,7 +13,7 @@ Item {
property color color: 'black' property color color: 'black'
function update() { function update() {
value = NewControllers.getValue(controlId); value = Controllers.getValue(controlId);
canvas.requestPaint(); canvas.requestPaint();
} }

View file

@ -15,8 +15,8 @@ Item {
function update() { function update() {
value = Qt.vector2d( value = Qt.vector2d(
NewControllers.getValue(controlIds[0]), Controllers.getValue(controlIds[0]),
NewControllers.getValue(controlIds[1]) Controllers.getValue(controlIds[1])
); );
canvas.requestPaint(); canvas.requestPaint();
} }

View file

@ -22,7 +22,7 @@ Item {
property string label: "" property string label: ""
function update() { function update() {
value = NewControllers.getValue(controlId); value = Controllers.getValue(controlId);
canvas.requestPaint(); canvas.requestPaint();
} }

View file

@ -15,7 +15,7 @@ Item {
Timer { Timer {
interval: 50; running: true; repeat: true interval: 50; running: true; repeat: true
onTriggered: { onTriggered: {
root.value = NewControllers.getValue(root.controlId); root.value = Controllers.getValue(root.controlId);
canvas.requestPaint(); canvas.requestPaint();
} }
} }

View file

@ -38,10 +38,10 @@
#include <plugins/PluginManager.h> #include <plugins/PluginManager.h>
#include <input-plugins/InputPlugin.h> #include <input-plugins/InputPlugin.h>
#include <input-plugins/KeyboardMouseDevice.h> #include <input-plugins/KeyboardMouseDevice.h>
#include <controllers/NewControllerScriptingInterface.h> #include <controllers/ScriptingInterface.h>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <input-plugins/UserInputMapper.h> #include <controllers/UserInputMapper.h>
const QString& getQmlDir() { const QString& getQmlDir() {
static QString dir; static QString dir;
@ -79,6 +79,12 @@ public:
virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; } virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; }
}; };
class MyControllerScriptingInterface : public controller::ScriptingInterface {
public:
virtual void registerControllerTypes(QScriptEngine* engine) {};
};
int main(int argc, char** argv) { int main(int argc, char** argv) {
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
@ -87,6 +93,22 @@ int main(int argc, char** argv) {
} }
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [] {
static float last = secTimestampNow();
float now = secTimestampNow();
float delta = now - last;
last = now;
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
inputPlugin->pluginUpdate(delta, false);
}
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->update(delta);
});
timer.start(50);
{ {
DependencyManager::set<UserInputMapper>(); DependencyManager::set<UserInputMapper>();
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
@ -98,17 +120,9 @@ int main(int argc, char** argv) {
keyboardMouseDevice->registerToUserInputMapper(*userInputMapper); keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
} }
} }
//new PluginContainerProxy(); //new PluginContainerProxy();
auto rootContext = engine.rootContext(); auto rootContext = engine.rootContext();
rootContext->setContextProperty("Controllers", new MyControllerScriptingInterface());
auto controllers = new NewControllerScriptingInterface();
rootContext->setContextProperty("NewControllers", controllers);
QVariantMap map;
map.insert("Hardware", controllers->property("Hardware"));
map.insert("Actions", controllers->property("Actions"));
rootContext->setContextProperty("ControllerIds", map);
} }
engine.load(getQmlDir() + "main.qml"); engine.load(getQmlDir() + "main.qml");
app.exec(); app.exec();