diff --git a/examples/example/scripts/controllerScriptingExamples.js b/examples/example/scripts/controllerScriptingExamples.js new file mode 100644 index 0000000000..26a1999bbb --- /dev/null +++ b/examples/example/scripts/controllerScriptingExamples.js @@ -0,0 +1,96 @@ +// +// controllerScriptingExamples.js +// examples +// +// Created by Sam Gondelman on 6/2/15 +// 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 +// + +// Assumes you only have the default keyboard connected + +// Resets every device to its default key bindings: +Controller.resetAllDeviceBindings(); + +// Query all actions +print("All Actions: \n" + Controller.getAllActions()); + +// Each action stores: +// action: int representation of enum +print("Action 5 int: \n" + Controller.getAllActions()[5].action); + +// actionName: string representation of enum +print("Action 5 name: \n" + Controller.getAllActions()[5].actionName); + +// inputChannels: list of all inputchannels that control that action +print("Action 5 input channels: \n" + Controller.getAllActions()[5].inputChannels + "\n"); + + +// Each input channel stores: +// action: Action that this InputChannel maps to +print("Input channel action: \n" + Controller.getAllActions()[5].inputChannels[0].action); + +// scale: sensitivity of input +print("Input channel scale: \n" + Controller.getAllActions()[5].inputChannels[0].scale); + +// 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"); + + +// Each Input stores: +// device: device of input +print("Input device: \n" + Controller.getAllActions()[5].inputChannels[0].input.device); + +// channel: channel of input +print("Input channel: \n" + Controller.getAllActions()[5].inputChannels[0].input.channel); + +// type: type of input (Unknown, Button, Axis, Joint) +print("Input type: \n" + Controller.getAllActions()[5].inputChannels[0].input.type); + +// id: id of input +print("Input id: \n" + Controller.getAllActions()[5].inputChannels[0].input.id + "\n"); + + +// 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)); + +// You can also get all of a devices input channels +print("Device 1's input channels: \n" + Controller.getAllInputsForDevice(1) + "\n"); + + +// Modifying properties: +// The following code will switch the "w" and "s" key functionality and adjust their scales +var s = Controller.getAllActions()[0].inputChannels[0]; +var w = Controller.getAllActions()[1].inputChannels[0]; + +// You must remove an input controller before modifying it so the old input controller isn't registered anymore +// removeInputChannel and addInputChannel return true if successful, false otherwise +Controller.removeInputChannel(s); +Controller.removeInputChannel(w); +print(s.scale); +s.action = 1; +s.scale = .01; + +w.action = 0; +w.scale = 10000; +Controller.addInputChannel(s); +Controller.addInputChannel(w); +print(s.scale); + +// You can get all the available inputs for any device +// Each AvailableInput has: +// input: the Input itself +// inputName: string representing the input +var availableInputs = Controller.getAvailableInputs(1); +for (i = 0; i < availableInputs.length; i++) { + print(availableInputs[i].inputName); +} + +// You can modify key bindings by using these avaiable inputs +// This will replace e (up) with 6 +var e = Controller.getAllActions()[5].inputChannels[0]; +Controller.removeInputChannel(e); +e.input = availableInputs[6].input; +Controller.addInputChannel(e); \ No newline at end of file diff --git a/interface/src/Application.h b/interface/src/Application.h index f63802ce24..68bf60781a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -149,6 +149,7 @@ public: static glm::quat getOrientationForPath() { return getInstance()->_myAvatar->getOrientation(); } static glm::vec3 getPositionForAudio() { return getInstance()->_myAvatar->getHead()->getPosition(); } static glm::quat getOrientationForAudio() { return getInstance()->_myAvatar->getHead()->getFinalOrientationInWorldFrame(); } + static UserInputMapper* getUserInputMapper() { return &getInstance()->_userInputMapper; } static void initPlugins(); static void shutdownPlugins(); diff --git a/interface/src/devices/KeyboardMouseDevice.cpp b/interface/src/devices/KeyboardMouseDevice.cpp index 7b0f8c056c..8a336064e5 100755 --- a/interface/src/devices/KeyboardMouseDevice.cpp +++ b/interface/src/devices/KeyboardMouseDevice.cpp @@ -159,9 +159,25 @@ void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) { // Grab the current free device ID _deviceID = mapper.getFreeDeviceID(); - auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy()); + auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("Keyboard")); proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input._channel); }; proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input._channel); }; + proxy->getAvailabeInputs = [this] () -> QVector { + QVector availableInputs; + for (int i = (int) Qt::Key_0; i <= (int) Qt::Key_9; i++) { + availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString())); + } + for (int i = (int) Qt::Key_A; i <= (int) Qt::Key_Z; i++) { + availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString())); + } + availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_Space), QKeySequence(Qt::Key_Space).toString())); + return availableInputs; + }; + proxy->resetDeviceBindings = [this, &mapper] () -> bool { + mapper.removeAllInputChannelsForDevice(_deviceID); + this->assignDefaultInputMapping(mapper); + return true; + }; mapper.registerDevice(_deviceID, proxy); } diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 5f12d73b37..2c747195a7 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -28,6 +28,94 @@ ControllerScriptingInterface::ControllerScriptingInterface() : { } +static int actionMetaTypeId = qRegisterMetaType(); +static int inputChannelMetaTypeId = qRegisterMetaType(); +static int inputMetaTypeId = qRegisterMetaType(); +static int inputPairMetaTypeId = qRegisterMetaType(); + +QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input); +void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input); +QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel); +void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel); +QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action); +void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action); +QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair); +void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair); + +QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) { + QScriptValue obj = engine->newObject(); + obj.setProperty("device", input.getDevice()); + obj.setProperty("channel", input.getChannel()); + obj.setProperty("type", (unsigned short) input.getType()); + obj.setProperty("id", input.getID()); + return obj; +} + +void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) { + input.setDevice(object.property("device").toUInt16()); + input.setChannel(object.property("channel").toUInt16()); + input.setType(object.property("type").toUInt16()); + input.setID(object.property("id").toInt32()); +} + +QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel) { + QScriptValue obj = engine->newObject(); + obj.setProperty("input", inputToScriptValue(engine, inputChannel.getInput())); + obj.setProperty("modifier", inputToScriptValue(engine, inputChannel.getModifier())); + obj.setProperty("action", inputChannel.getAction()); + obj.setProperty("scale", inputChannel.getScale()); + return obj; +} + +void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel) { + UserInputMapper::Input input; + UserInputMapper::Input modifier; + inputFromScriptValue(object.property("input"), input); + inputChannel.setInput(input); + inputFromScriptValue(object.property("modifier"), modifier); + inputChannel.setModifier(modifier); + inputChannel.setAction(UserInputMapper::Action(object.property("action").toVariant().toInt())); + inputChannel.setScale(object.property("scale").toVariant().toFloat()); +} + +QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) { + QScriptValue obj = engine->newObject(); + QVector inputChannels = Application::getUserInputMapper()->getInputChannelsForAction(action); + QScriptValue _inputChannels = engine->newArray(inputChannels.size()); + for (int i = 0; i < inputChannels.size(); i++) { + _inputChannels.setProperty(i, inputChannelToScriptValue(engine, inputChannels[i])); + } + obj.setProperty("action", (int) action); + obj.setProperty("actionName", Application::getUserInputMapper()->getActionName(action)); + obj.setProperty("inputChannels", _inputChannels); + return obj; +} + +void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) { + action = UserInputMapper::Action(object.property("action").toVariant().toInt()); +} + +QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) { + QScriptValue obj = engine->newObject(); + obj.setProperty("input", inputToScriptValue(engine, inputPair.first)); + obj.setProperty("inputName", inputPair.second); + return obj; +} + +void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) { + inputFromScriptValue(object.property("input"), inputPair.first); + inputPair.second = QString(object.property("inputName").toVariant().toString()); +} + +void ControllerScriptingInterface::registerControllerTypes(QScriptEngine* engine) { + qScriptRegisterSequenceMetaType >(engine); + qScriptRegisterSequenceMetaType >(engine); + qScriptRegisterSequenceMetaType >(engine); + qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue); + qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue); + qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); + qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); +} void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { if (event->type() == HFActionEvent::startType()) { @@ -337,6 +425,37 @@ void ControllerScriptingInterface::updateInputControllers() { } } +QVector ControllerScriptingInterface::getAllActions() { + return Application::getUserInputMapper()->getAllActions(); +} + +QVector ControllerScriptingInterface::getInputChannelsForAction(UserInputMapper::Action action) { + return Application::getUserInputMapper()->getInputChannelsForAction(action); +} + +QString ControllerScriptingInterface::getDeviceName(unsigned int device) { + return Application::getUserInputMapper()->getDeviceName((unsigned short) device); +} + +QVector ControllerScriptingInterface::getAllInputsForDevice(unsigned int device) { + return Application::getUserInputMapper()->getAllInputsForDevice(device); +} + +bool ControllerScriptingInterface::addInputChannel(UserInputMapper::InputChannel inputChannel) { + return Application::getUserInputMapper()->addInputChannel(inputChannel._action, inputChannel._input, inputChannel._modifier, inputChannel._scale); +} + +bool ControllerScriptingInterface::removeInputChannel(UserInputMapper::InputChannel inputChannel) { + return Application::getUserInputMapper()->removeInputChannel(inputChannel); +} + +QVector ControllerScriptingInterface::getAvailableInputs(unsigned int device) { + return Application::getUserInputMapper()->getAvailableInputs((unsigned short) device); +} + +void ControllerScriptingInterface::resetAllDeviceBindings() { + Application::getUserInputMapper()->resetAllDeviceBindings(); +} InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : AbstractInputController(), @@ -373,4 +492,4 @@ const unsigned int INPUTCONTROLLER_KEY_DEVICE_MASK = 16; InputController::Key InputController::getKey() const { return (((_deviceTrackerId & INPUTCONTROLLER_KEY_DEVICE_MASK) << INPUTCONTROLLER_KEY_DEVICE_OFFSET) | _subTrackerId); -} +} \ No newline at end of file diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index c088dd6c9a..9414dc887b 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -14,10 +14,11 @@ #include +#include "ui/UserInputMapper.h" + #include class PalmData; - class InputController : public AbstractInputController { Q_OBJECT @@ -54,6 +55,9 @@ class ControllerScriptingInterface : public AbstractControllerScriptingInterface public: ControllerScriptingInterface(); + + virtual void registerControllerTypes(QScriptEngine* engine); + void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } @@ -79,6 +83,14 @@ public: void updateInputControllers(); public slots: + Q_INVOKABLE virtual QVector getAllActions(); + Q_INVOKABLE virtual QVector getInputChannelsForAction(UserInputMapper::Action action); + Q_INVOKABLE virtual QString getDeviceName(unsigned int device); + Q_INVOKABLE virtual QVector getAllInputsForDevice(unsigned int device); + Q_INVOKABLE virtual bool addInputChannel(UserInputMapper::InputChannel inputChannel); + Q_INVOKABLE virtual bool removeInputChannel(UserInputMapper::InputChannel inputChannel); + Q_INVOKABLE virtual QVector getAvailableInputs(unsigned int device); + Q_INVOKABLE virtual void resetAllDeviceBindings(); virtual bool isPrimaryButtonPressed() const; virtual glm::vec2 getPrimaryJoystickPosition() const; diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp index 892ab6a9b6..e994b3cf30 100755 --- a/interface/src/ui/UserInputMapper.cpp +++ b/interface/src/ui/UserInputMapper.cpp @@ -13,7 +13,15 @@ // UserInputMapper Class + +// Default contruct allocate the poutput size with the current hardcoded action channels +UserInputMapper::UserInputMapper() { + assignDefaulActionScales(); + createActionNames(); +} + bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){ + proxy->_name += " (" + QString::number(deviceID) + ")"; _registeredDevices[deviceID] = proxy; return true; } @@ -27,6 +35,12 @@ UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Inpu } } +void UserInputMapper::resetAllDeviceBindings() { + for (auto device : _registeredDevices) { + device.second->resetDeviceBindings(); + } +} + bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) { return addInputChannel(action, input, Input(), scale); } @@ -37,7 +51,7 @@ bool UserInputMapper::addInputChannel(Action action, const Input& input, const I qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped."; return false; } - + auto inputChannel = InputChannel(input, modifier, action, scale); // Insert or replace the input to modifiers @@ -61,6 +75,37 @@ int UserInputMapper::addInputChannels(const InputChannels& channels) { return nbAdded; } +bool UserInputMapper::removeInputChannel(InputChannel inputChannel) { + // Remove from Input to Modifiers map + if (inputChannel.hasModifier()) { + _inputToModifiersMap.erase(inputChannel._input.getID()); + } + + // Remove from Action to Inputs map + std::pair ret; + ret = _actionToInputsMap.equal_range(inputChannel._action); + for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) { + if (it->second == inputChannel) { + _actionToInputsMap.erase(it); + return true; + } + } + + return false; +} + +void UserInputMapper::removeAllInputChannels() { + _inputToModifiersMap.clear(); + _actionToInputsMap.clear(); +} + +void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) { + QVector channels = getAllInputsForDevice(device); + for (auto& channel : channels) { + removeInputChannel(channel); + } +} + int UserInputMapper::getInputChannels(InputChannels& channels) const { for (auto& channel : _actionToInputsMap) { channels.push_back(channel.second); @@ -69,6 +114,20 @@ int UserInputMapper::getInputChannels(InputChannels& channels) const { return _actionToInputsMap.size(); } +QVector UserInputMapper::getAllInputsForDevice(uint16 device) { + InputChannels allChannels; + getInputChannels(allChannels); + + QVector channels; + for (InputChannel inputChannel : allChannels) { + if (inputChannel._input._device == device) { + channels.push_back(inputChannel); + } + } + + return channels; +} + void UserInputMapper::update(float deltaTime) { // Reset the axis state for next loop @@ -130,6 +189,24 @@ void UserInputMapper::update(float deltaTime) { } } +QVector UserInputMapper::getAllActions() { + QVector actions; + for (auto i = 0; i < NUM_ACTIONS; i++) { + actions.append(Action(i)); + } + return actions; +} + +QVector UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) { + QVector inputChannels; + std::pair ret; + ret = _actionToInputsMap.equal_range(action); + for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) { + inputChannels.append(it->second); + } + return inputChannels; +} + void UserInputMapper::assignDefaulActionScales() { _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit @@ -144,3 +221,20 @@ void UserInputMapper::assignDefaulActionScales() { _actionScales[BOOM_IN] = 1.0f; // 1m per unit _actionScales[BOOM_OUT] = 1.0f; // 1m per unit } + +// This is only necessary as long as the actions are hardcoded +// Eventually you can just add the string when you add the action +void UserInputMapper::createActionNames() { + _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD"; + _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD"; + _actionNames[LATERAL_LEFT] = "LATERAL_LEFT"; + _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT"; + _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN"; + _actionNames[VERTICAL_UP] = "VERTICAL_UP"; + _actionNames[YAW_LEFT] = "YAW_LEFT"; + _actionNames[YAW_RIGHT] = "YAW_RIGHT"; + _actionNames[PITCH_DOWN] = "PITCH_DOWN"; + _actionNames[PITCH_UP] = "PITCH_UP"; + _actionNames[BOOM_IN] = "BOOM_IN"; + _actionNames[BOOM_OUT] = "BOOM_OUT"; +} \ No newline at end of file diff --git a/interface/src/ui/UserInputMapper.h b/interface/src/ui/UserInputMapper.h index ab63bdbef7..0a08e277db 100755 --- a/interface/src/ui/UserInputMapper.h +++ b/interface/src/ui/UserInputMapper.h @@ -21,6 +21,7 @@ class UserInputMapper : public QObject { Q_OBJECT + Q_ENUMS(Action) public: typedef unsigned short uint16; typedef unsigned int uint32; @@ -51,8 +52,13 @@ public: uint16 getDevice() const { return _device; } uint16 getChannel() const { return _channel; } uint32 getID() const { return _id; } - ChannelType getType() const { return (ChannelType) _type; } + + void setDevice(uint16 device) { _device = device; } + void setChannel(uint16 channel) { _channel = channel; } + void setType(uint16 type) { _type = type; } + void setID(uint32 ID) { _id = ID; } + bool isButton() const { return getType() == ChannelType::BUTTON; } bool isAxis() const { return getType() == ChannelType::AXIS; } bool isJoint() const { return getType() == ChannelType::JOINT; } @@ -64,6 +70,7 @@ public: explicit Input(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)) {} Input(const Input& src) : _id(src._id) {} Input& operator = (const Input& src) { _id = src._id; return (*this); } + bool operator ==(const Input& right) const { return _id == right._id; } bool operator < (const Input& src) const { return _id < src._id; } }; @@ -83,22 +90,32 @@ public: typedef std::function ButtonGetter; typedef std::function AxisGetter; typedef std::function JointGetter; + typedef QPair InputPair; + typedef std::function ()> AvailableInputGetter; + typedef std::function ResetBindings; + + typedef QVector AvailableInput; class DeviceProxy { public: - DeviceProxy() {} - - ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; }; - AxisGetter getAxis = [] (const Input& input, int timestamp) -> bool { return 0.0f; }; - JointGetter getJoint = [] (const Input& input, int timestamp) -> JointValue { return JointValue(); }; - - typedef std::shared_ptr Pointer; + DeviceProxy(QString name) { _name = name; } + + QString _name; + ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; }; + AxisGetter getAxis = [] (const Input& input, int timestamp) -> bool { return 0.0f; }; + JointGetter getJoint = [] (const Input& input, int timestamp) -> JointValue { return JointValue(); }; + AvailableInputGetter getAvailabeInputs = [] () -> AvailableInput { return QVector(); }; + ResetBindings resetDeviceBindings = [] () -> bool { return true; }; + + typedef std::shared_ptr Pointer; }; // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device. uint16 getFreeDeviceID() { return _nextFreeDeviceID++; } bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device); DeviceProxy::Pointer getDeviceProxy(const Input& input); - + QString getDeviceName(uint16 deviceID) { return _registeredDevices[deviceID]->_name; } + QVector getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); } + void resetAllDeviceBindings(); // 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 @@ -123,7 +140,12 @@ public: NUM_ACTIONS, }; + + std::vector _actionNames = std::vector(NUM_ACTIONS); + void createActionNames(); + QVector getAllActions(); + QString getActionName(Action action) { return UserInputMapper::_actionNames[(int) action]; } float getActionState(Action action) const { return _actionStates[action]; } void assignDefaulActionScales(); @@ -140,27 +162,43 @@ public: Input _modifier = Input(); // make it invalid by default, meaning no modifier Action _action = LONGITUDINAL_BACKWARD; float _scale = 0.0f; + + Input getInput() const { return _input; } + Input getModifier() const { return _modifier; } + Action getAction() const { return _action; } + float getScale() const { return _scale; } + + void setInput(Input input) { _input = input; } + void setModifier(Input modifier) { _modifier = modifier; } + void setAction(Action action) { _action = action; } + void setScale(float scale) { _scale = scale; } InputChannel() {} InputChannel(const Input& input, const Input& modifier, Action action, float scale = 1.0f) : _input(input), _modifier(modifier), _action(action), _scale(scale) {} InputChannel(const InputChannel& src) : InputChannel(src._input, src._modifier, src._action, src._scale) {} InputChannel& operator = (const InputChannel& src) { _input = src._input; _modifier = src._modifier; _action = src._action; _scale = src._scale; return (*this); } - + bool operator ==(const InputChannel& right) const { return _input == right._input && _modifier == right._modifier && _action == right._action && _scale == right._scale; } bool hasModifier() { return _modifier.isValid(); } }; typedef std::vector< InputChannel > InputChannels; // Add a bunch of input channels, return the true number of channels that successfully were added int addInputChannels(const InputChannels& channels); + // Remove the first found instance of the input channel from the input mapper, true if found + bool removeInputChannel(InputChannel channel); + void removeAllInputChannels(); + void removeAllInputChannelsForDevice(uint16 device); //Grab all the input channels currently in use, return the number int getInputChannels(InputChannels& channels) const; + QVector getAllInputsForDevice(uint16 device); + QVector getInputChannelsForAction(UserInputMapper::Action action); + std::multimap getActionToInputsMap() { return _actionToInputsMap; } // Update means go grab all the device input channels and update the output channel values void update(float deltaTime); - - // Default contruct allocate the poutput size with the current hardcoded action channels - UserInputMapper() { assignDefaulActionScales(); } + + UserInputMapper(); protected: typedef std::map DevicesMap; @@ -177,4 +215,12 @@ protected: std::vector _actionScales = std::vector(NUM_ACTIONS, 1.0f); }; +Q_DECLARE_METATYPE(UserInputMapper::InputPair) +Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(UserInputMapper::Input) +Q_DECLARE_METATYPE(UserInputMapper::InputChannel) +Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(UserInputMapper::Action) +Q_DECLARE_METATYPE(QVector) + #endif // hifi_UserInputMapper_h diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 11755add8e..43076039a9 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -52,6 +52,8 @@ class AbstractControllerScriptingInterface : public QObject { Q_OBJECT public slots: + virtual void registerControllerTypes(QScriptEngine* engine) = 0; + virtual bool isPrimaryButtonPressed() const = 0; virtual glm::vec2 getPrimaryJoystickPosition() const = 0; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 30c3fbe8e4..182a0aea8d 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -317,6 +317,7 @@ void ScriptEngine::init() { registerAnimationTypes(this); registerAvatarTypes(this); registerAudioMetaTypes(this); + _controllerScriptingInterface->registerControllerTypes(this); qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);