mirror of
https://github.com/overte-org/overte.git
synced 2025-07-23 13:04:07 +02:00
Merge pull request #5085 from SamGondelman/master
Exposing Input Key Binding To JavaScript
This commit is contained in:
commit
24fda9a733
9 changed files with 404 additions and 17 deletions
96
examples/example/scripts/controllerScriptingExamples.js
Normal file
96
examples/example/scripts/controllerScriptingExamples.js
Normal file
|
@ -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);
|
|
@ -149,6 +149,7 @@ public:
|
||||||
static glm::quat getOrientationForPath() { return getInstance()->_myAvatar->getOrientation(); }
|
static glm::quat getOrientationForPath() { return getInstance()->_myAvatar->getOrientation(); }
|
||||||
static glm::vec3 getPositionForAudio() { return getInstance()->_myAvatar->getHead()->getPosition(); }
|
static glm::vec3 getPositionForAudio() { return getInstance()->_myAvatar->getHead()->getPosition(); }
|
||||||
static glm::quat getOrientationForAudio() { return getInstance()->_myAvatar->getHead()->getFinalOrientationInWorldFrame(); }
|
static glm::quat getOrientationForAudio() { return getInstance()->_myAvatar->getHead()->getFinalOrientationInWorldFrame(); }
|
||||||
|
static UserInputMapper* getUserInputMapper() { return &getInstance()->_userInputMapper; }
|
||||||
static void initPlugins();
|
static void initPlugins();
|
||||||
static void shutdownPlugins();
|
static void shutdownPlugins();
|
||||||
|
|
||||||
|
|
|
@ -159,9 +159,25 @@ void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||||
// Grab the current free device ID
|
// Grab the current free device ID
|
||||||
_deviceID = mapper.getFreeDeviceID();
|
_deviceID = mapper.getFreeDeviceID();
|
||||||
|
|
||||||
auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy());
|
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->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->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input._channel); };
|
||||||
|
proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
|
||||||
|
QVector<UserInputMapper::InputPair> 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);
|
mapper.registerDevice(_deviceID, proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,94 @@ ControllerScriptingInterface::ControllerScriptingInterface() :
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
|
||||||
|
static int inputChannelMetaTypeId = qRegisterMetaType<UserInputMapper::InputChannel>();
|
||||||
|
static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
|
||||||
|
static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
|
||||||
|
|
||||||
|
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<UserInputMapper::InputChannel> 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<QVector<UserInputMapper::Action> >(engine);
|
||||||
|
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputChannel> >(engine);
|
||||||
|
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
|
||||||
|
qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
|
||||||
|
qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue);
|
||||||
|
qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
|
||||||
|
qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
|
||||||
|
}
|
||||||
|
|
||||||
void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
|
void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
|
||||||
if (event->type() == HFActionEvent::startType()) {
|
if (event->type() == HFActionEvent::startType()) {
|
||||||
|
@ -337,6 +425,37 @@ void ControllerScriptingInterface::updateInputControllers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<UserInputMapper::Action> ControllerScriptingInterface::getAllActions() {
|
||||||
|
return Application::getUserInputMapper()->getAllActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<UserInputMapper::InputChannel> ControllerScriptingInterface::getInputChannelsForAction(UserInputMapper::Action action) {
|
||||||
|
return Application::getUserInputMapper()->getInputChannelsForAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ControllerScriptingInterface::getDeviceName(unsigned int device) {
|
||||||
|
return Application::getUserInputMapper()->getDeviceName((unsigned short) device);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<UserInputMapper::InputChannel> 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<UserInputMapper::InputPair> 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) :
|
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
|
||||||
AbstractInputController(),
|
AbstractInputController(),
|
||||||
|
@ -373,4 +492,4 @@ 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);
|
||||||
}
|
}
|
|
@ -14,10 +14,11 @@
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
#include "ui/UserInputMapper.h"
|
||||||
|
|
||||||
#include <AbstractControllerScriptingInterface.h>
|
#include <AbstractControllerScriptingInterface.h>
|
||||||
class PalmData;
|
class PalmData;
|
||||||
|
|
||||||
|
|
||||||
class InputController : public AbstractInputController {
|
class InputController : public AbstractInputController {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -54,6 +55,9 @@ class ControllerScriptingInterface : public AbstractControllerScriptingInterface
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ControllerScriptingInterface();
|
ControllerScriptingInterface();
|
||||||
|
|
||||||
|
virtual void registerControllerTypes(QScriptEngine* engine);
|
||||||
|
|
||||||
void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
|
void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
|
||||||
void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }
|
void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }
|
||||||
|
|
||||||
|
@ -79,6 +83,14 @@ public:
|
||||||
void updateInputControllers();
|
void updateInputControllers();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
Q_INVOKABLE virtual QVector<UserInputMapper::Action> getAllActions();
|
||||||
|
Q_INVOKABLE virtual QVector<UserInputMapper::InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
|
||||||
|
Q_INVOKABLE virtual QString getDeviceName(unsigned int device);
|
||||||
|
Q_INVOKABLE virtual QVector<UserInputMapper::InputChannel> getAllInputsForDevice(unsigned int device);
|
||||||
|
Q_INVOKABLE virtual bool addInputChannel(UserInputMapper::InputChannel inputChannel);
|
||||||
|
Q_INVOKABLE virtual bool removeInputChannel(UserInputMapper::InputChannel inputChannel);
|
||||||
|
Q_INVOKABLE virtual QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
|
||||||
|
Q_INVOKABLE virtual void resetAllDeviceBindings();
|
||||||
virtual bool isPrimaryButtonPressed() const;
|
virtual bool isPrimaryButtonPressed() const;
|
||||||
virtual glm::vec2 getPrimaryJoystickPosition() const;
|
virtual glm::vec2 getPrimaryJoystickPosition() const;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,15 @@
|
||||||
|
|
||||||
|
|
||||||
// UserInputMapper Class
|
// 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){
|
bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
|
||||||
|
proxy->_name += " (" + QString::number(deviceID) + ")";
|
||||||
_registeredDevices[deviceID] = proxy;
|
_registeredDevices[deviceID] = proxy;
|
||||||
return true;
|
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) {
|
bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
|
||||||
return addInputChannel(action, input, Input(), 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.";
|
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
|
||||||
|
@ -61,6 +75,37 @@ int UserInputMapper::addInputChannels(const InputChannels& channels) {
|
||||||
return nbAdded;
|
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<ActionToInputsMap::iterator, ActionToInputsMap::iterator> 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<InputChannel> channels = getAllInputsForDevice(device);
|
||||||
|
for (auto& channel : channels) {
|
||||||
|
removeInputChannel(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
@ -69,6 +114,20 @@ int UserInputMapper::getInputChannels(InputChannels& channels) const {
|
||||||
return _actionToInputsMap.size();
|
return _actionToInputsMap.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<UserInputMapper::InputChannel> UserInputMapper::getAllInputsForDevice(uint16 device) {
|
||||||
|
InputChannels allChannels;
|
||||||
|
getInputChannels(allChannels);
|
||||||
|
|
||||||
|
QVector<InputChannel> channels;
|
||||||
|
for (InputChannel inputChannel : allChannels) {
|
||||||
|
if (inputChannel._input._device == device) {
|
||||||
|
channels.push_back(inputChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -130,6 +189,24 @@ void UserInputMapper::update(float deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<UserInputMapper::Action> UserInputMapper::getAllActions() {
|
||||||
|
QVector<Action> actions;
|
||||||
|
for (auto i = 0; i < NUM_ACTIONS; i++) {
|
||||||
|
actions.append(Action(i));
|
||||||
|
}
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<UserInputMapper::InputChannel> UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) {
|
||||||
|
QVector<InputChannel> inputChannels;
|
||||||
|
std::pair <ActionToInputsMap::iterator, ActionToInputsMap::iterator> 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() {
|
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
|
||||||
|
@ -144,3 +221,20 @@ void UserInputMapper::assignDefaulActionScales() {
|
||||||
_actionScales[BOOM_IN] = 1.0f; // 1m per unit
|
_actionScales[BOOM_IN] = 1.0f; // 1m per unit
|
||||||
_actionScales[BOOM_OUT] = 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";
|
||||||
|
}
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
class UserInputMapper : public QObject {
|
class UserInputMapper : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_ENUMS(Action)
|
||||||
public:
|
public:
|
||||||
typedef unsigned short uint16;
|
typedef unsigned short uint16;
|
||||||
typedef unsigned int uint32;
|
typedef unsigned int uint32;
|
||||||
|
@ -51,8 +52,13 @@ public:
|
||||||
uint16 getDevice() const { return _device; }
|
uint16 getDevice() const { return _device; }
|
||||||
uint16 getChannel() const { return _channel; }
|
uint16 getChannel() const { return _channel; }
|
||||||
uint32 getID() const { return _id; }
|
uint32 getID() const { return _id; }
|
||||||
|
|
||||||
ChannelType getType() const { return (ChannelType) _type; }
|
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 isButton() const { return getType() == ChannelType::BUTTON; }
|
||||||
bool isAxis() const { return getType() == ChannelType::AXIS; }
|
bool isAxis() const { return getType() == ChannelType::AXIS; }
|
||||||
bool isJoint() const { return getType() == ChannelType::JOINT; }
|
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)) {}
|
explicit Input(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)) {}
|
||||||
Input(const Input& src) : _id(src._id) {}
|
Input(const Input& src) : _id(src._id) {}
|
||||||
Input& operator = (const Input& src) { _id = src._id; return (*this); }
|
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; }
|
bool operator < (const Input& src) const { return _id < src._id; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,22 +90,32 @@ public:
|
||||||
typedef std::function<bool (const Input& input, int timestamp)> ButtonGetter;
|
typedef std::function<bool (const Input& input, int timestamp)> ButtonGetter;
|
||||||
typedef std::function<float (const Input& input, int timestamp)> AxisGetter;
|
typedef std::function<float (const Input& input, int timestamp)> AxisGetter;
|
||||||
typedef std::function<JointValue (const Input& input, int timestamp)> JointGetter;
|
typedef std::function<JointValue (const Input& input, int timestamp)> JointGetter;
|
||||||
|
typedef QPair<Input, QString> InputPair;
|
||||||
|
typedef std::function<QVector<InputPair> ()> AvailableInputGetter;
|
||||||
|
typedef std::function<bool ()> ResetBindings;
|
||||||
|
|
||||||
|
typedef QVector<InputPair> AvailableInput;
|
||||||
|
|
||||||
class DeviceProxy {
|
class DeviceProxy {
|
||||||
public:
|
public:
|
||||||
DeviceProxy() {}
|
DeviceProxy(QString name) { _name = name; }
|
||||||
|
|
||||||
ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
|
QString _name;
|
||||||
AxisGetter getAxis = [] (const Input& input, int timestamp) -> bool { return 0.0f; };
|
ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
|
||||||
JointGetter getJoint = [] (const Input& input, int timestamp) -> JointValue { return JointValue(); };
|
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<DeviceProxy> Pointer;
|
AvailableInputGetter getAvailabeInputs = [] () -> AvailableInput { return QVector<InputPair>(); };
|
||||||
|
ResetBindings resetDeviceBindings = [] () -> bool { return true; };
|
||||||
|
|
||||||
|
typedef std::shared_ptr<DeviceProxy> Pointer;
|
||||||
};
|
};
|
||||||
// GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
|
// GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
|
||||||
uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
|
uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
|
||||||
bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device);
|
bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device);
|
||||||
DeviceProxy::Pointer getDeviceProxy(const Input& input);
|
DeviceProxy::Pointer getDeviceProxy(const Input& input);
|
||||||
|
QString getDeviceName(uint16 deviceID) { return _registeredDevices[deviceID]->_name; }
|
||||||
|
QVector<InputPair> getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); }
|
||||||
|
void resetAllDeviceBindings();
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -123,7 +140,12 @@ public:
|
||||||
|
|
||||||
NUM_ACTIONS,
|
NUM_ACTIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<QString> _actionNames = std::vector<QString>(NUM_ACTIONS);
|
||||||
|
void createActionNames();
|
||||||
|
|
||||||
|
QVector<Action> getAllActions();
|
||||||
|
QString getActionName(Action action) { return UserInputMapper::_actionNames[(int) action]; }
|
||||||
float getActionState(Action action) const { return _actionStates[action]; }
|
float getActionState(Action action) const { return _actionStates[action]; }
|
||||||
void assignDefaulActionScales();
|
void assignDefaulActionScales();
|
||||||
|
|
||||||
|
@ -140,27 +162,43 @@ public:
|
||||||
Input _modifier = Input(); // make it invalid by default, meaning no modifier
|
Input _modifier = Input(); // make it invalid by default, meaning no modifier
|
||||||
Action _action = LONGITUDINAL_BACKWARD;
|
Action _action = LONGITUDINAL_BACKWARD;
|
||||||
float _scale = 0.0f;
|
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() {}
|
||||||
InputChannel(const Input& input, const Input& modifier, Action action, float scale = 1.0f) :
|
InputChannel(const Input& input, const Input& modifier, Action action, float scale = 1.0f) :
|
||||||
_input(input), _modifier(modifier), _action(action), _scale(scale) {}
|
_input(input), _modifier(modifier), _action(action), _scale(scale) {}
|
||||||
InputChannel(const InputChannel& src) : InputChannel(src._input, src._modifier, src._action, src._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); }
|
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(); }
|
bool hasModifier() { return _modifier.isValid(); }
|
||||||
};
|
};
|
||||||
typedef std::vector< InputChannel > InputChannels;
|
typedef std::vector< InputChannel > InputChannels;
|
||||||
|
|
||||||
// Add a bunch of input channels, return the true number of channels that successfully were added
|
// Add a bunch of input channels, return the true number of channels that successfully were added
|
||||||
int addInputChannels(const InputChannels& channels);
|
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
|
//Grab all the input channels currently in use, return the number
|
||||||
int getInputChannels(InputChannels& channels) const;
|
int getInputChannels(InputChannels& channels) const;
|
||||||
|
QVector<InputChannel> getAllInputsForDevice(uint16 device);
|
||||||
|
QVector<InputChannel> getInputChannelsForAction(UserInputMapper::Action action);
|
||||||
|
std::multimap<Action, InputChannel> getActionToInputsMap() { return _actionToInputsMap; }
|
||||||
|
|
||||||
// Update means go grab all the device input channels and update the output channel values
|
// Update means go grab all the device input channels and update the output channel values
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
|
|
||||||
// Default contruct allocate the poutput size with the current hardcoded action channels
|
UserInputMapper();
|
||||||
UserInputMapper() { assignDefaulActionScales(); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef std::map<int, DeviceProxy::Pointer> DevicesMap;
|
typedef std::map<int, DeviceProxy::Pointer> DevicesMap;
|
||||||
|
@ -177,4 +215,12 @@ protected:
|
||||||
std::vector<float> _actionScales = std::vector<float>(NUM_ACTIONS, 1.0f);
|
std::vector<float> _actionScales = std::vector<float>(NUM_ACTIONS, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(UserInputMapper::InputPair)
|
||||||
|
Q_DECLARE_METATYPE(QVector<UserInputMapper::InputPair>)
|
||||||
|
Q_DECLARE_METATYPE(UserInputMapper::Input)
|
||||||
|
Q_DECLARE_METATYPE(UserInputMapper::InputChannel)
|
||||||
|
Q_DECLARE_METATYPE(QVector<UserInputMapper::InputChannel>)
|
||||||
|
Q_DECLARE_METATYPE(UserInputMapper::Action)
|
||||||
|
Q_DECLARE_METATYPE(QVector<UserInputMapper::Action>)
|
||||||
|
|
||||||
#endif // hifi_UserInputMapper_h
|
#endif // hifi_UserInputMapper_h
|
||||||
|
|
|
@ -52,6 +52,8 @@ class AbstractControllerScriptingInterface : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
virtual void registerControllerTypes(QScriptEngine* engine) = 0;
|
||||||
|
|
||||||
virtual bool isPrimaryButtonPressed() const = 0;
|
virtual bool isPrimaryButtonPressed() const = 0;
|
||||||
virtual glm::vec2 getPrimaryJoystickPosition() const = 0;
|
virtual glm::vec2 getPrimaryJoystickPosition() const = 0;
|
||||||
|
|
||||||
|
|
|
@ -317,6 +317,7 @@ void ScriptEngine::init() {
|
||||||
registerAnimationTypes(this);
|
registerAnimationTypes(this);
|
||||||
registerAvatarTypes(this);
|
registerAvatarTypes(this);
|
||||||
registerAudioMetaTypes(this);
|
registerAudioMetaTypes(this);
|
||||||
|
_controllerScriptingInterface->registerControllerTypes(this);
|
||||||
|
|
||||||
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
|
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
|
||||||
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
|
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
|
||||||
|
|
Loading…
Reference in a new issue