Moving omniTool to a route mapped input

This commit is contained in:
Brad Davis 2015-10-23 12:15:30 -07:00
parent be148686a7
commit 56deef9d6e
7 changed files with 139 additions and 51 deletions

View file

@ -22,10 +22,10 @@ OmniTool = function(left) {
this.MAX_FRAMERATE = 60;
this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
this.left = left;
this.triggered = false;
var actions = Controller.Actions;
var standard = Controller.Standard;
this.palmControl = left ? actions.LeftHand : actions.RightHand;
this.action = left ? standard.LeftPrimaryThumb : standard.RightPrimaryThumb;
logDebug("Init OmniTool " + (left ? "left" : "right"));
this.highlighter = new Highlighter();
this.ignoreEntities = {};
@ -50,9 +50,6 @@ OmniTool = function(left) {
// Connect to desired events
var that = this;
Controller.inputEvent.connect(function(action, state) {
that.onInputEvent(action, state);
});
Script.update.connect(function(deltaTime) {
that.lastUpdateInterval += deltaTime;
@ -65,6 +62,12 @@ OmniTool = function(left) {
Script.scriptEnding.connect(function() {
that.onCleanup();
});
this.mapping = Controller.newMapping();
this.mapping.from(left ? standard.LeftPrimaryThumb : standard.RightPrimaryThumb).to(function(value){
that.onUpdateTrigger(value);
})
this.mapping.enable();
}
OmniTool.prototype.showWand = function(show) {
@ -83,29 +86,23 @@ OmniTool.prototype.showWand = function(show) {
}
}
OmniTool.prototype.onCleanup = function(action) {
this.mapping.disable();
this.unloadModule();
}
OmniTool.prototype.onInputEvent = function(action, state) {
// FIXME figure out the issues when only one spatial controller is active
var actionNames = Controller.getActionNames();
if (this.module && this.module.onInputEvent) {
this.module.onInputEvent(action, state);
}
if (action == this.action) {
if (state) {
OmniTool.prototype.onUpdateTrigger = function (value) {
//logDebug("Trigger update value " + value);
var triggered = value != 0;
if (triggered != this.triggered) {
this.triggered = triggered;
if (this.triggered) {
this.onClick();
} else {
this.onRelease();
}
}
// FIXME Does not work
//// with only one controller active (listed as 2 here because 'tip' + 'palm')
//// then treat the alt action button as the action button
}
OmniTool.prototype.getOmniToolData = function(entityId) {

View file

@ -36,6 +36,7 @@ namespace controller {
using WriteLambda = std::function<void(float)>;
Endpoint(const Input& input) : _input(input) {}
virtual uint8_t priority() const { return 0x7f; }
virtual float value() = 0;
virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
virtual Pose pose() { return Pose(); }

View file

@ -0,0 +1,37 @@
//
// 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_Forward_h
#define hifi_Controllers_Forward_h
namespace controller {
class Endpoint;
using EndpointPointer = std::shared_ptr<Endpoint>;
using EndpointList = std::list<EndpointPointer>;
class Filter;
using FilterPointer = std::shared_ptr<Filter>;
using FilterList = std::list<FilterPointer>;
class Route;
using RoutePointer = std::shared_ptr<Route>;
using RouteList = std::list<RoutePointer>;
class Conditional;
using ConditionalPointer = std::shared_ptr<Conditional>;
using ConditionalList = std::list<ConditionalPointer>;
class Mapping;
using MappingPointer = std::shared_ptr<Mapping>;
using MappingList = std::list<MappingPointer>;
}
#endif

View file

@ -21,8 +21,13 @@
#include <NumericalConstants.h>
#include "StandardController.h"
#include "Logging.h"
#include "Endpoint.h"
#include "Route.h"
#include "Mapping.h"
namespace controller {
const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
@ -211,6 +216,9 @@ public:
}
}
// Process later than normal
virtual uint8_t priority() const override { return 0x6F; }
virtual float value() override {
float result = 0;
for (auto& child : _children) {
@ -674,19 +682,27 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
static auto lastDebugTime = usecTimestampNow();
static auto debugRoutes = false;
static auto debuggableRoutes = false;
static const auto DEBUG_INTERVAL = USECS_PER_SECOND;
void UserInputMapper::runMappings() {
auto now = usecTimestampNow();
if (now - lastDebugTime > DEBUG_INTERVAL) {
if (debuggableRoutes && now - lastDebugTime > DEBUG_INTERVAL) {
lastDebugTime = now;
debugRoutes = true;
}
if (debugRoutes) {
qCDebug(controllers) << "Beginning mapping frame";
}
static auto deviceNames = getDeviceNames();
for (auto endpointEntry : this->_endpointsByInput) {
endpointEntry.second->reset();
}
if (debugRoutes) {
qCDebug(controllers) << "Processing device routes";
}
// Now process the current values for each level of the stack
for (const auto& route : _deviceRoutes) {
if (!route) {
@ -695,12 +711,19 @@ void UserInputMapper::runMappings() {
applyRoute(route);
}
if (debugRoutes) {
qCDebug(controllers) << "Processing standard routes";
}
for (const auto& route : _standardRoutes) {
if (!route) {
continue;
}
applyRoute(route);
}
if (debugRoutes) {
qCDebug(controllers) << "Done with mappings";
}
debugRoutes = false;
}
@ -1174,6 +1197,22 @@ Mapping::Pointer UserInputMapper::parseMapping(const QString& json) {
return parseMapping(doc.object());
}
template <typename T>
bool hasDebuggableRoute(const T& routes) {
for (auto route : routes) {
if (route->debug) {
return true;
}
}
return false;
}
void sortRoutes(Route::List& routes) {
std::stable_sort(routes.begin(), routes.end(), [](const Route::Pointer a, const Route::Pointer b) {
return a->source->priority() < b->source->priority();
});
}
void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
Locker locker(_lock);
@ -1186,12 +1225,18 @@ void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
return (value->source->getInput().device != STANDARD_DEVICE);
});
_standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end());
sortRoutes(_standardRoutes);
Route::List deviceRoutes = mapping->routes;
deviceRoutes.remove_if([](const Route::Pointer& value) {
return (value->source->getInput().device == STANDARD_DEVICE);
});
_deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
sortRoutes(_standardRoutes);
if (!debuggableRoutes) {
debuggableRoutes = hasDebuggableRoute(_deviceRoutes) || hasDebuggableRoute(_standardRoutes);
}
}
void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
@ -1204,6 +1249,10 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
_standardRoutes.remove_if([&](const Route::Pointer& value) {
return routeSet.count(value) != 0;
});
if (debuggableRoutes) {
debuggableRoutes = hasDebuggableRoute(_deviceRoutes) || hasDebuggableRoute(_standardRoutes);
}
}
}

View file

@ -23,13 +23,12 @@
#include <DependencyManager.h>
#include <RegisteredMetaTypes.h>
#include "Forward.h"
#include "Pose.h"
#include "Input.h"
#include "InputDevice.h"
#include "DeviceProxy.h"
#include "StandardControls.h"
#include "Mapping.h"
#include "Endpoint.h"
#include "Actions.h"
namespace controller {
@ -45,15 +44,14 @@ namespace controller {
public:
using InputPair = Input::NamedPair;
// FIXME move to unordered set / map
using EndpointToInputMap = std::map<Endpoint::Pointer, Input>;
using MappingNameMap = std::map<QString, Mapping::Pointer>;
using MappingDeviceMap = std::map<uint16_t, Mapping::Pointer>;
using MappingStack = std::list<Mapping::Pointer>;
using InputToEndpointMap = std::map<Input, Endpoint::Pointer>;
using EndpointSet = std::unordered_set<Endpoint::Pointer>;
using EndpointOverrideMap = std::map<Endpoint::Pointer, Endpoint::Pointer>;
using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>;
using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
using EndpointToInputMap = std::map<EndpointPointer, Input>;
using MappingNameMap = std::map<QString, MappingPointer>;
using MappingDeviceMap = std::map<uint16_t, MappingPointer>;
using MappingStack = std::list<MappingPointer>;
using InputToEndpointMap = std::map<Input, EndpointPointer>;
using EndpointSet = std::unordered_set<EndpointPointer>;
using EndpointPair = std::pair<EndpointPointer, EndpointPointer>;
using EndpointPairMap = std::map<EndpointPair, EndpointPointer>;
using DevicesMap = std::map<int, DeviceProxy::Pointer>;
using uint16 = uint16_t;
using uint32 = uint32_t;
@ -107,9 +105,9 @@ namespace controller {
uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
Mapping::Pointer newMapping(const QString& mappingName);
Mapping::Pointer parseMapping(const QString& json);
Mapping::Pointer loadMapping(const QString& jsonFile);
MappingPointer newMapping(const QString& mappingName);
MappingPointer parseMapping(const QString& json);
MappingPointer loadMapping(const QString& jsonFile);
void enableMapping(const QString& mappingName, bool enable = true);
float getValue(const Input& input) const;
@ -138,30 +136,30 @@ namespace controller {
int recordDeviceOfType(const QString& deviceName);
QHash<const QString&, int> _deviceCounts;
float getValue(const Endpoint::Pointer& endpoint) const;
Pose getPose(const Endpoint::Pointer& endpoint) const;
float getValue(const EndpointPointer& endpoint) const;
Pose getPose(const EndpointPointer& endpoint) const;
friend class RouteBuilderProxy;
friend class MappingBuilderProxy;
void runMappings();
void applyRoute(const Route::Pointer& route);
void enableMapping(const Mapping::Pointer& mapping);
void disableMapping(const Mapping::Pointer& mapping);
Endpoint::Pointer endpointFor(const QJSValue& endpoint);
Endpoint::Pointer endpointFor(const QScriptValue& endpoint);
Endpoint::Pointer endpointFor(const Input& endpoint) const;
Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second);
void applyRoute(const RoutePointer& route);
void enableMapping(const MappingPointer& mapping);
void disableMapping(const MappingPointer& mapping);
EndpointPointer endpointFor(const QJSValue& endpoint);
EndpointPointer endpointFor(const QScriptValue& endpoint);
EndpointPointer endpointFor(const Input& endpoint) const;
EndpointPointer compositeEndpointFor(EndpointPointer first, EndpointPointer second);
Mapping::Pointer parseMapping(const QJsonValue& json);
Route::Pointer parseRoute(const QJsonValue& value);
Endpoint::Pointer parseDestination(const QJsonValue& value);
Endpoint::Pointer parseSource(const QJsonValue& value);
Endpoint::Pointer parseEndpoint(const QJsonValue& value);
Conditional::Pointer parseConditional(const QJsonValue& value);
MappingPointer parseMapping(const QJsonValue& json);
RoutePointer parseRoute(const QJsonValue& value);
EndpointPointer parseDestination(const QJsonValue& value);
EndpointPointer parseSource(const QJsonValue& value);
EndpointPointer parseEndpoint(const QJsonValue& value);
ConditionalPointer parseConditional(const QJsonValue& value);
static Filter::Pointer parseFilter(const QJsonValue& value);
static Filter::List parseFilters(const QJsonValue& value);
static FilterPointer parseFilter(const QJsonValue& value);
static FilterList parseFilters(const QJsonValue& value);
InputToEndpointMap _endpointsByInput;
EndpointToInputMap _inputsByEndpoint;
@ -170,8 +168,8 @@ namespace controller {
MappingNameMap _mappingsByName;
MappingDeviceMap _mappingsByDevice;
Route::List _deviceRoutes;
Route::List _standardRoutes;
RouteList _deviceRoutes;
RouteList _standardRoutes;
using Locker = std::unique_lock<std::recursive_mutex>;

View file

@ -39,6 +39,11 @@ void RouteBuilderProxy::to(const Endpoint::Pointer& destination) {
deleteLater();
}
QObject* RouteBuilderProxy::debug(bool enable) {
_route->debug = enable;
return this;
}
QObject* RouteBuilderProxy::filterQml(const QJSValue& expression) {
if (expression.isCallable()) {
addFilter([=](float value) {

View file

@ -35,6 +35,7 @@ class RouteBuilderProxy : public QObject {
Q_INVOKABLE QObject* filterQml(const QJSValue& expression);
Q_INVOKABLE void to(const QScriptValue& destination);
Q_INVOKABLE QObject* debug(bool enable = true);
Q_INVOKABLE QObject* filter(const QScriptValue& expression);
Q_INVOKABLE QObject* clamp(float min, float max);
Q_INVOKABLE QObject* pulse(float interval);