Moving conditionals and endpoints out of UserInputMapper

Conflicts:
	libraries/controllers/src/controllers/UserInputMapper.cpp
This commit is contained in:
Brad Davis 2015-10-23 13:28:36 -07:00
parent 2c2273df0b
commit 0fdd32709f
37 changed files with 766 additions and 332 deletions

View file

@ -24,9 +24,22 @@
#include "Logging.h"
#include "Endpoint.h"
#include "Route.h"
#include "Mapping.h"
#include "impl/conditionals/AndConditional.h"
#include "impl/conditionals/EndpointConditional.h"
#include "impl/conditionals/ScriptConditional.h"
#include "impl/endpoints/ActionEndpoint.h"
#include "impl/endpoints/AnyEndpoint.h"
#include "impl/endpoints/ArrayEndpoint.h"
#include "impl/endpoints/CompositeEndpoint.h"
#include "impl/endpoints/InputEndpoint.h"
#include "impl/endpoints/JSEndpoint.h"
#include "impl/endpoints/ScriptEndpoint.h"
#include "impl/endpoints/StandardEndpoint.h"
#include "impl/Route.h"
#include "impl/Mapping.h"
namespace controller {
const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
@ -42,300 +55,6 @@ controller::UserInputMapper::UserInputMapper() {
namespace controller {
class ScriptEndpoint : public Endpoint {
Q_OBJECT;
public:
ScriptEndpoint(const QScriptValue& callable)
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
}
virtual float value();
virtual void apply(float newValue, float oldValue, const Pointer& source);
protected:
Q_INVOKABLE void updateValue();
Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID);
private:
QScriptValue _callable;
float _lastValue = 0.0f;
};
class StandardEndpoint : public VirtualEndpoint {
public:
StandardEndpoint(const Input& input) : VirtualEndpoint(input) {}
virtual bool writeable() const override { return !_written; }
virtual bool readable() const override { return !_read; }
virtual void reset() override {
apply(0.0f, 0.0f, Endpoint::Pointer());
apply(Pose(), Pose(), Endpoint::Pointer());
_written = _read = false;
}
virtual float value() override {
_read = true;
return VirtualEndpoint::value();
}
virtual void apply(float newValue, float oldValue, const Pointer& source) override {
// For standard endpoints, the first NON-ZERO write counts.
if (newValue != 0.0) {
_written = true;
}
VirtualEndpoint::apply(newValue, oldValue, source);
}
virtual Pose pose() override {
_read = true;
return VirtualEndpoint::pose();
}
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
if (newValue != Pose()) {
_written = true;
}
VirtualEndpoint::apply(newValue, oldValue, source);
}
private:
bool _written { false };
bool _read { false };
};
class JSEndpoint : public Endpoint {
public:
JSEndpoint(const QJSValue& callable)
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
}
virtual float value() {
float result = (float)_callable.call().toNumber();;
return result;
}
virtual void apply(float newValue, float oldValue, const Pointer& source) {
_callable.call(QJSValueList({ QJSValue(newValue) }));
}
private:
QJSValue _callable;
};
float ScriptEndpoint::value() {
updateValue();
return _lastValue;
}
void ScriptEndpoint::updateValue() {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
return;
}
_lastValue = (float)_callable.call().toNumber();
}
void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
internalApply(newValue, oldValue, source->getInput().getID());
}
void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
Q_ARG(float, newValue),
Q_ARG(float, oldValue),
Q_ARG(int, sourceID));
return;
}
_callable.call(QScriptValue(),
QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) }));
}
static const Input INVALID_STANDARD_INPUT = Input(UserInputMapper::STANDARD_DEVICE, Input::INVALID_CHANNEL, ChannelType::INVALID);
class CompositeEndpoint : public Endpoint, Endpoint::Pair {
public:
CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
: Endpoint(Input::INVALID_INPUT), Pair(first, second) {
if (first->getInput().device == UserInputMapper::STANDARD_DEVICE &&
second->getInput().device == UserInputMapper::STANDARD_DEVICE) {
this->_input = INVALID_STANDARD_INPUT;
}
}
virtual float value() {
float result = first->value() * -1.0f + second->value();
return result;
}
virtual void apply(float newValue, float oldValue, const Pointer& source) {
// Composites are read only
}
};
class ArrayEndpoint : public Endpoint {
friend class UserInputMapper;
public:
using Pointer = std::shared_ptr<ArrayEndpoint>;
ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
virtual float value() override {
return 0.0;
}
virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
for (auto& child : _children) {
if (child->writeable()) {
child->apply(newValue, oldValue, source);
}
}
}
virtual bool readable() const override { return false; }
private:
Endpoint::List _children;
};
class AnyEndpoint : public Endpoint {
friend class UserInputMapper;
public:
using Pointer = std::shared_ptr<AnyEndpoint>;
AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPUT), _children(children) {
bool standard = true;
// Ensure if we're building a composite of standard devices the composite itself
// is treated as a standard device for rule processing order
for (auto endpoint : children) {
if (endpoint->getInput().device != UserInputMapper::STANDARD_DEVICE) {
standard = false;
break;
}
}
if (standard) {
this->_input = INVALID_STANDARD_INPUT;
}
}
virtual float value() override {
float result = 0.0f;
for (auto& child : _children) {
float childResult = child->value();
if (childResult != 0.0f && result == 0.0f) {
result = childResult;
}
}
return result;
}
virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
qFatal("AnyEndpoint is read only");
}
// AnyEndpoint is used for reading, so return false if any child returns false (has been written to)
virtual bool writeable() const override {
for (auto& child : _children) {
if (!child->writeable()) {
return false;
}
}
return true;
}
virtual bool readable() const override {
for (auto& child : _children) {
if (!child->readable()) {
return false;
}
}
return true;
}
private:
Endpoint::List _children;
};
class InputEndpoint : public Endpoint {
public:
InputEndpoint(const Input& id = Input::INVALID_INPUT)
: Endpoint(id) {
}
virtual float value() override {
_read = true;
if (isPose()) {
return pose().valid ? 1.0f : 0.0f;
}
auto userInputMapper = DependencyManager::get<UserInputMapper>();
auto deviceProxy = userInputMapper->getDeviceProxy(_input);
if (!deviceProxy) {
return 0.0f;
}
return deviceProxy->getValue(_input, 0);
}
// FIXME need support for writing back to vibration / force feedback effects
virtual void apply(float newValue, float oldValue, const Pointer& source) override {}
virtual Pose pose() override {
_read = true;
if (!isPose()) {
return Pose();
}
auto userInputMapper = DependencyManager::get<UserInputMapper>();
auto deviceProxy = userInputMapper->getDeviceProxy(_input);
if (!deviceProxy) {
return Pose();
}
return deviceProxy->getPose(_input, 0);
}
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
virtual bool writeable() const { return false; }
virtual bool readable() const { return !_read; }
virtual void reset() { _read = false; }
private:
bool _read { false };
};
class ActionEndpoint : public Endpoint {
public:
ActionEndpoint(const Input& id = Input::INVALID_INPUT)
: Endpoint(id) {
}
virtual float value() override { return _currentValue; }
virtual void apply(float newValue, float oldValue, const Pointer& source) override {
_currentValue += newValue;
if (_input != Input::INVALID_INPUT) {
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
}
}
virtual Pose pose() override { return _currentPose; }
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
_currentPose = newValue;
if (!_currentPose.isValid()) {
return;
}
if (_input != Input::INVALID_INPUT) {
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->setActionState(Action(_input.getChannel()), _currentPose);
}
}
virtual void reset() override {
_currentValue = 0.0f;
_currentPose = Pose();
}
private:
float _currentValue{ 0.0f };
Pose _currentPose{};
};
UserInputMapper::~UserInputMapper() {
}
@ -1019,33 +738,6 @@ Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) {
return result;
}
class AndConditional : public Conditional {
public:
using Pointer = std::shared_ptr<AndConditional>;
AndConditional(Conditional::List children) : _children(children) { }
virtual bool satisfied() override {
for (auto& conditional : _children) {
if (!conditional->satisfied()) {
return false;
}
}
return true;
}
private:
Conditional::List _children;
};
class EndpointConditional : public Conditional {
public:
EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
private:
Endpoint::Pointer _endpoint;
};
Conditional::Pointer UserInputMapper::parseConditional(const QJsonValue& value) {
if (value.isArray()) {
// Support "when" : [ "GamePad.RB", "GamePad.LB" ]
@ -1290,4 +982,3 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
}
#include "UserInputMapper.moc"

View file

@ -16,8 +16,8 @@
#include <QtCore/QObject>
#include "Input.h"
#include "Pose.h"
#include "../Input.h"
#include "../Pose.h"
class QScriptValue;

View file

@ -12,8 +12,8 @@
#include <QtCore/QObject>
#include <QtCore/QString>
#include "../Mapping.h"
#include "../Endpoint.h"
#include "Mapping.h"
#include "Endpoint.h"
class QJSValue;
class QScriptValue;

View file

@ -11,10 +11,12 @@
#include <QtCore/QObject>
#include "../Filter.h"
#include "../Route.h"
#include "../Mapping.h"
#include "Filter.h"
#include "Route.h"
#include "Mapping.h"
#include "../UserInputMapper.h"
class QJSValue;
class QScriptValue;
class QJsonValue;

View file

@ -0,0 +1,20 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AndConditional.h"
using namespace controller;
bool AndConditional::satisfied() {
for (auto& conditional : _children) {
if (!conditional->satisfied()) {
return false;
}
}
return true;
}

View file

@ -0,0 +1,32 @@
//
// Created by Bradley Austin Davis 2015/10/20
// 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_AndConditional_h
#define hifi_Controllers_AndConditional_h
#include "../Conditional.h"
namespace controller {
class AndConditional : public Conditional {
public:
using Pointer = std::shared_ptr<AndConditional>;
AndConditional(Conditional::List children) : _children(children) { }
virtual bool satisfied() override;
private:
Conditional::List _children;
};
}
#endif

View file

@ -0,0 +1,9 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EndpointConditional.h"

View file

@ -0,0 +1,27 @@
//
// Created by Bradley Austin Davis 2015/10/20
// 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_EndpointConditional_h
#define hifi_Controllers_EndpointConditional_h
#include "../Conditional.h"
#include "../Endpoint.h"
namespace controller {
class EndpointConditional : public Conditional {
public:
EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
private:
Endpoint::Pointer _endpoint;
};
}
#endif

View file

@ -0,0 +1,9 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "NotConditional.h"

View file

@ -0,0 +1,16 @@
//
// Created by Bradley Austin Davis 2015/10/20
// 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_NotConditional_h
#define hifi_Controllers_NotConditional_h
#include "../Conditional.h"
#endif

View file

@ -0,0 +1,27 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ScriptConditional.h"
#include <QtCore/QThread>
using namespace controller;
bool ScriptConditional::satisfied() {
updateValue();
return _lastValue;
}
void ScriptConditional::updateValue() {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
return;
}
_lastValue = _callable.call().toBool();
}

View file

@ -0,0 +1,34 @@
//
// Created by Bradley Austin Davis 2015/10/20
// 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_ScriptConditional_h
#define hifi_Controllers_ScriptConditional_h
#include <QtCore/QObject>
#include <QtScript/QScriptValue>
#include "../Conditional.h"
namespace controller {
class ScriptConditional : public QObject, public Conditional {
Q_OBJECT;
public:
ScriptConditional(const QScriptValue& callable) : _callable(callable) { }
virtual bool satisfied() override;
protected:
Q_INVOKABLE void updateValue();
private:
QScriptValue _callable;
bool _lastValue { false };
};
}
#endif

View file

@ -0,0 +1,40 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ActionEndpoint.h"
#include <DependencyManager.h>
#include "../../UserInputMapper.h"
using namespace controller;
void ActionEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
_currentValue += newValue;
if (_input != Input::INVALID_INPUT) {
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
}
}
void ActionEndpoint::apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) {
_currentPose = newValue;
if (!_currentPose.isValid()) {
return;
}
if (_input != Input::INVALID_INPUT) {
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->setActionState(Action(_input.getChannel()), _currentPose);
}
}
void ActionEndpoint::reset() {
_currentValue = 0.0f;
_currentPose = Pose();
}

View file

@ -0,0 +1,41 @@
//
// Created by Bradley Austin Davis 2015/10/23
// 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_ActionEndpoint_h
#define hifi_Controllers_ActionEndpoint_h
#include "../Endpoint.h"
#include "../../Actions.h"
#include <DependencyManager.h>
#include "../../UserInputMapper.h"
namespace controller {
class ActionEndpoint : public Endpoint {
public:
ActionEndpoint(const Input& id = Input::INVALID_INPUT) : Endpoint(id) { }
virtual float value() override { return _currentValue; }
virtual void apply(float newValue, float oldValue, const Pointer& source) override;
virtual Pose pose() override { return _currentPose; }
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override;
virtual void reset() override;
private:
float _currentValue{ 0.0f };
Pose _currentPose{};
};
}
#endif

View file

@ -0,0 +1,63 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AnyEndpoint.h"
#include "../../UserInputMapper.h"
using namespace controller;
AnyEndpoint::AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPUT), _children(children) {
bool standard = true;
// Ensure if we're building a composite of standard devices the composite itself
// is treated as a standard device for rule processing order
for (auto endpoint : children) {
if (endpoint->getInput().device != UserInputMapper::STANDARD_DEVICE) {
standard = false;
break;
}
}
if (standard) {
this->_input.device = UserInputMapper::STANDARD_DEVICE;
}
}
float AnyEndpoint::value() {
float result = 0;
for (auto& child : _children) {
float childResult = child->value();
if (childResult != 0.0f) {
result = childResult;
}
}
return result;
}
void AnyEndpoint::apply(float newValue, float oldValue, const Endpoint::Pointer& source) {
qFatal("AnyEndpoint is read only");
}
// AnyEndpoint is used for reading, so return false if any child returns false (has been written to)
bool AnyEndpoint::writeable() const {
for (auto& child : _children) {
if (!child->writeable()) {
return false;
}
}
return true;
}
bool AnyEndpoint::readable() const {
for (auto& child : _children) {
if (!child->readable()) {
return false;
}
}
return true;
}

View file

@ -0,0 +1,32 @@
//
// Created by Bradley Austin Davis 2015/10/23
// 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_AnyEndpoint_h
#define hifi_Controllers_AnyEndpoint_h
#include "../Endpoint.h"
namespace controller {
class AnyEndpoint : public Endpoint {
friend class UserInputMapper;
public:
AnyEndpoint(Endpoint::List children);
virtual float value() override;
virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override;
virtual bool writeable() const override;
virtual bool readable() const override;
private:
Endpoint::List _children;
};
}
#endif

View file

@ -0,0 +1,9 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ArrayEndpoint.h"

View file

@ -0,0 +1,43 @@
//
// Created by Bradley Austin Davis 2015/10/23
// 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_ArrayEndpoint_h
#define hifi_Controllers_ArrayEndpoint_h
#include "../Endpoint.h"
namespace controller {
class ArrayEndpoint : public Endpoint {
friend class UserInputMapper;
public:
using Pointer = std::shared_ptr<ArrayEndpoint>;
ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
virtual float value() override {
return 0.0;
}
virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
for (auto& child : _children) {
if (child->writeable()) {
child->apply(newValue, oldValue, source);
}
}
}
virtual bool readable() const override { return false; }
private:
Endpoint::List _children;
};
}
#endif

View file

@ -0,0 +1,32 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "CompositeEndpoint.h"
#include "../../UserInputMapper.h"
namespace controller {
CompositeEndpoint::CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
: Endpoint(Input::INVALID_INPUT), Pair(first, second) {
if (first->getInput().device == UserInputMapper::STANDARD_DEVICE &&
second->getInput().device == UserInputMapper::STANDARD_DEVICE) {
this->_input.device = UserInputMapper::STANDARD_DEVICE;
}
}
float CompositeEndpoint::value() {
float result = first->value() * -1.0f + second->value();
return result;
}
void CompositeEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
// Composites are read only
}
}

View file

@ -0,0 +1,26 @@
//
// Created by Bradley Austin Davis 2015/10/23
// 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_CompositeEndpoint_h
#define hifi_Controllers_CompositeEndpoint_h
#include "../Endpoint.h"
namespace controller {
class CompositeEndpoint : public Endpoint, Endpoint::Pair {
public:
CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second);
virtual float value() override;
virtual void apply(float newValue, float oldValue, const Pointer& source) override;
};
}
#endif

View file

@ -0,0 +1,41 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "InputEndpoint.h"
#include <DependencyManager.h>
#include "../../UserInputMapper.h"
using namespace controller;
float InputEndpoint::value(){
_read = true;
if (isPose()) {
return pose().valid ? 1.0f : 0.0f;
}
auto userInputMapper = DependencyManager::get<UserInputMapper>();
auto deviceProxy = userInputMapper->getDeviceProxy(_input);
if (!deviceProxy) {
return 0.0f;
}
return deviceProxy->getValue(_input, 0);
}
Pose InputEndpoint::pose() {
_read = true;
if (!isPose()) {
return Pose();
}
auto userInputMapper = DependencyManager::get<UserInputMapper>();
auto deviceProxy = userInputMapper->getDeviceProxy(_input);
if (!deviceProxy) {
return Pose();
}
return deviceProxy->getPose(_input, 0);
}

View file

@ -0,0 +1,39 @@
//
// Created by Bradley Austin Davis 2015/10/23
// 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_InputEndpoint_h
#define hifi_Controllers_InputEndpoint_h
#include "../Endpoint.h"
namespace controller {
class InputEndpoint : public Endpoint {
public:
InputEndpoint(const Input& id = Input::INVALID_INPUT)
: Endpoint(id) {
}
virtual float value() override;
// FIXME need support for writing back to vibration / force feedback effects
virtual void apply(float newValue, float oldValue, const Pointer& source) override {}
virtual Pose pose() override;
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
virtual bool writeable() const { return false; }
virtual bool readable() const { return !_read; }
virtual void reset() { _read = false; }
private:
bool _read { false };
};
}
#endif

View file

@ -0,0 +1,9 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "JSEndpoint.h"

View file

@ -0,0 +1,41 @@
//
// Created by Bradley Austin Davis 2015/10/23
// 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_JSEndpoint_h
#define hifi_Controllers_JSEndpoint_h
#include "../Endpoint.h"
#include <QtQml/QJSValue>
#include <QtQml/QJSValueList>
namespace controller {
class JSEndpoint : public Endpoint {
public:
JSEndpoint(const QJSValue& callable)
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
}
virtual float value() {
float result = (float)_callable.call().toNumber();
return result;
}
virtual void apply(float newValue, float oldValue, const Pointer& source) {
_callable.call(QJSValueList({ QJSValue(newValue) }));
}
private:
QJSValue _callable;
};
}
#endif

View file

@ -0,0 +1,43 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ScriptEndpoint.h"
#include <QtCore/QThread>
using namespace controller;
float ScriptEndpoint::value() {
updateValue();
return _lastValue;
}
void ScriptEndpoint::updateValue() {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
return;
}
_lastValue = (float)_callable.call().toNumber();
}
void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
internalApply(newValue, oldValue, source->getInput().getID());
}
void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
Q_ARG(float, newValue),
Q_ARG(float, oldValue),
Q_ARG(int, sourceID));
return;
}
_callable.call(QScriptValue(),
QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) }));
}

View file

@ -0,0 +1,39 @@
//
// Created by Bradley Austin Davis 2015/10/23
// 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_ScriptEndpoint_h
#define hifi_Controllers_ScriptEndpoint_h
#include <QtScript/QScriptValue>
#include "../Endpoint.h"
namespace controller {
class ScriptEndpoint : public Endpoint {
Q_OBJECT;
public:
ScriptEndpoint(const QScriptValue& callable)
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
}
virtual float value();
virtual void apply(float newValue, float oldValue, const Pointer& source);
protected:
Q_INVOKABLE void updateValue();
Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID);
private:
QScriptValue _callable;
float _lastValue = 0.0f;
};
}
#endif

View file

@ -0,0 +1,9 @@
//
// Created by Bradley Austin Davis 2015/10/23
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "StandardEndpoint.h"

View file

@ -0,0 +1,60 @@
//
// Created by Bradley Austin Davis 2015/10/23
// 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_StandardEndpoint_h
#define hifi_Controllers_StandardEndpoint_h
#include "../Endpoint.h"
namespace controller {
class StandardEndpoint : public VirtualEndpoint {
public:
StandardEndpoint(const Input& input) : VirtualEndpoint(input) {}
virtual bool writeable() const override { return !_written; }
virtual bool readable() const override { return !_read; }
virtual void reset() override {
apply(0.0f, 0.0f, Endpoint::Pointer());
apply(Pose(), Pose(), Endpoint::Pointer());
_written = _read = false;
}
virtual float value() override {
_read = true;
return VirtualEndpoint::value();
}
virtual void apply(float newValue, float oldValue, const Pointer& source) override {
// For standard endpoints, the first NON-ZERO write counts.
if (newValue != 0.0) {
_written = true;
}
VirtualEndpoint::apply(newValue, oldValue, source);
}
virtual Pose pose() override {
_read = true;
return VirtualEndpoint::pose();
}
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
if (newValue != Pose()) {
_written = true;
}
VirtualEndpoint::apply(newValue, oldValue, source);
}
private:
bool _written { false };
bool _read { false };
};
}
#endif