mirror of
https://github.com/overte-org/overte.git
synced 2025-06-15 21:59:22 +02:00
Merge pull request #8240 from jherico/hand_controller
Menu & hand controller polish
This commit is contained in:
commit
7bb31fe075
15 changed files with 182 additions and 26 deletions
|
@ -3,9 +3,17 @@
|
||||||
"channels": [
|
"channels": [
|
||||||
{ "from": "Hydra.LY", "filters": "invert", "to": "Standard.LY" },
|
{ "from": "Hydra.LY", "filters": "invert", "to": "Standard.LY" },
|
||||||
{ "from": "Hydra.LX", "to": "Standard.LX" },
|
{ "from": "Hydra.LX", "to": "Standard.LX" },
|
||||||
|
{ "from": "Hydra.LT", "to": "Standard.LTClick",
|
||||||
|
"peek": true,
|
||||||
|
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
|
||||||
|
},
|
||||||
{ "from": "Hydra.LT", "to": "Standard.LT" },
|
{ "from": "Hydra.LT", "to": "Standard.LT" },
|
||||||
{ "from": "Hydra.RY", "filters": "invert", "to": "Standard.RY" },
|
{ "from": "Hydra.RY", "filters": "invert", "to": "Standard.RY" },
|
||||||
{ "from": "Hydra.RX", "to": "Standard.RX" },
|
{ "from": "Hydra.RX", "to": "Standard.RX" },
|
||||||
|
{ "from": "Hydra.RT", "to": "Standard.RTClick",
|
||||||
|
"peek": true,
|
||||||
|
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
|
||||||
|
},
|
||||||
{ "from": "Hydra.RT", "to": "Standard.RT" },
|
{ "from": "Hydra.RT", "to": "Standard.RT" },
|
||||||
|
|
||||||
{ "from": "Hydra.LB", "to": "Standard.LB" },
|
{ "from": "Hydra.LB", "to": "Standard.LB" },
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
|
|
||||||
{ "from": "OculusTouch.LY", "filters": "invert", "to": "Standard.LY" },
|
{ "from": "OculusTouch.LY", "filters": "invert", "to": "Standard.LY" },
|
||||||
{ "from": "OculusTouch.LX", "to": "Standard.LX" },
|
{ "from": "OculusTouch.LX", "to": "Standard.LX" },
|
||||||
|
{ "from": "OculusTouch.LT", "to": "Standard.LTClick",
|
||||||
|
"peek": true,
|
||||||
|
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
|
||||||
|
},
|
||||||
{ "from": "OculusTouch.LT", "to": "Standard.LT" },
|
{ "from": "OculusTouch.LT", "to": "Standard.LT" },
|
||||||
{ "from": "OculusTouch.LS", "to": "Standard.LS" },
|
{ "from": "OculusTouch.LS", "to": "Standard.LS" },
|
||||||
{ "from": "OculusTouch.LeftGrip", "to": "Standard.LeftGrip" },
|
{ "from": "OculusTouch.LeftGrip", "to": "Standard.LeftGrip" },
|
||||||
|
@ -15,6 +19,10 @@
|
||||||
|
|
||||||
{ "from": "OculusTouch.RY", "filters": "invert", "to": "Standard.RY" },
|
{ "from": "OculusTouch.RY", "filters": "invert", "to": "Standard.RY" },
|
||||||
{ "from": "OculusTouch.RX", "to": "Standard.RX" },
|
{ "from": "OculusTouch.RX", "to": "Standard.RX" },
|
||||||
|
{ "from": "OculusTouch.RT", "to": "Standard.RTClick",
|
||||||
|
"peek": true,
|
||||||
|
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
|
||||||
|
},
|
||||||
{ "from": "OculusTouch.RT", "to": "Standard.RT" },
|
{ "from": "OculusTouch.RT", "to": "Standard.RT" },
|
||||||
{ "from": "OculusTouch.RS", "to": "Standard.RS" },
|
{ "from": "OculusTouch.RS", "to": "Standard.RS" },
|
||||||
{ "from": "OculusTouch.RightGrip", "to": "Standard.RightGrip" },
|
{ "from": "OculusTouch.RightGrip", "to": "Standard.RightGrip" },
|
||||||
|
|
|
@ -10,14 +10,7 @@
|
||||||
{ "from": "Standard.RB", "to": "Actions.UiNavGroup" },
|
{ "from": "Standard.RB", "to": "Actions.UiNavGroup" },
|
||||||
{ "from": [ "Standard.A", "Standard.X" ], "to": "Actions.UiNavSelect" },
|
{ "from": [ "Standard.A", "Standard.X" ], "to": "Actions.UiNavSelect" },
|
||||||
{ "from": [ "Standard.B", "Standard.Y" ], "to": "Actions.UiNavBack" },
|
{ "from": [ "Standard.B", "Standard.Y" ], "to": "Actions.UiNavBack" },
|
||||||
{
|
{ "from": [ "Standard.RTClick", "Standard.LTClick" ], "to": "Actions.UiNavSelect" },
|
||||||
"from": [ "Standard.RT", "Standard.LT" ],
|
|
||||||
"to": "Actions.UiNavSelect",
|
|
||||||
"filters": [
|
|
||||||
{ "type": "deadZone", "min": 0.5 },
|
|
||||||
"constrainToInteger"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"from": "Standard.LX", "to": "Actions.UiNavLateral",
|
"from": "Standard.LX", "to": "Actions.UiNavLateral",
|
||||||
"filters": [
|
"filters": [
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
{ "type": "deadZone", "min": 0.05 }
|
{ "type": "deadZone", "min": 0.05 }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{ "from": "Vive.LTClick", "to": "Standard.LTClick" },
|
||||||
|
|
||||||
{ "from": "Vive.LeftGrip", "to": "Standard.LeftGrip" },
|
{ "from": "Vive.LeftGrip", "to": "Standard.LeftGrip" },
|
||||||
{ "from": "Vive.LS", "to": "Standard.LS" },
|
{ "from": "Vive.LS", "to": "Standard.LS" },
|
||||||
{ "from": "Vive.LSTouch", "to": "Standard.LSTouch" },
|
{ "from": "Vive.LSTouch", "to": "Standard.LSTouch" },
|
||||||
|
@ -21,6 +23,8 @@
|
||||||
{ "type": "deadZone", "min": 0.05 }
|
{ "type": "deadZone", "min": 0.05 }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{ "from": "Vive.RTClick", "to": "Standard.RTClick" },
|
||||||
|
|
||||||
{ "from": "Vive.RightGrip", "to": "Standard.RightGrip" },
|
{ "from": "Vive.RightGrip", "to": "Standard.RightGrip" },
|
||||||
{ "from": "Vive.RS", "to": "Standard.RS" },
|
{ "from": "Vive.RS", "to": "Standard.RS" },
|
||||||
{ "from": "Vive.RSTouch", "to": "Standard.RSTouch" },
|
{ "from": "Vive.RSTouch", "to": "Standard.RSTouch" },
|
||||||
|
|
|
@ -45,6 +45,7 @@ FocusScope {
|
||||||
onVisibleChanged: recalcSize();
|
onVisibleChanged: recalcSize();
|
||||||
onCountChanged: recalcSize();
|
onCountChanged: recalcSize();
|
||||||
focus: true
|
focus: true
|
||||||
|
highlightMoveDuration: 0
|
||||||
|
|
||||||
highlight: Rectangle {
|
highlight: Rectangle {
|
||||||
anchors {
|
anchors {
|
||||||
|
|
|
@ -4705,6 +4705,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
||||||
qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue,
|
qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue,
|
||||||
RayToOverlayIntersectionResultFromScriptValue);
|
RayToOverlayIntersectionResultFromScriptValue);
|
||||||
|
|
||||||
|
scriptEngine->registerGlobalObject("OffscreenFlags", DependencyManager::get<OffscreenUi>()->getFlags());
|
||||||
scriptEngine->registerGlobalObject("Desktop", DependencyManager::get<DesktopScriptingInterface>().data());
|
scriptEngine->registerGlobalObject("Desktop", DependencyManager::get<DesktopScriptingInterface>().data());
|
||||||
scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
|
scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,8 @@ Input::NamedVector StandardController::getAvailableInputs() const {
|
||||||
// Triggers
|
// Triggers
|
||||||
makePair(LT, "LT"),
|
makePair(LT, "LT"),
|
||||||
makePair(RT, "RT"),
|
makePair(RT, "RT"),
|
||||||
|
makePair(LT_CLICK, "LTClick"),
|
||||||
|
makePair(RT_CLICK, "RTClick"),
|
||||||
|
|
||||||
// Finger abstractions
|
// Finger abstractions
|
||||||
makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"),
|
makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"),
|
||||||
|
|
|
@ -46,6 +46,7 @@ namespace controller {
|
||||||
LS_CENTER,
|
LS_CENTER,
|
||||||
LS_X,
|
LS_X,
|
||||||
LS_Y,
|
LS_Y,
|
||||||
|
LT_CLICK,
|
||||||
|
|
||||||
RIGHT_PRIMARY_THUMB,
|
RIGHT_PRIMARY_THUMB,
|
||||||
RIGHT_SECONDARY_THUMB,
|
RIGHT_SECONDARY_THUMB,
|
||||||
|
@ -56,6 +57,7 @@ namespace controller {
|
||||||
RS_CENTER,
|
RS_CENTER,
|
||||||
RS_X,
|
RS_X,
|
||||||
RS_Y,
|
RS_Y,
|
||||||
|
RT_CLICK,
|
||||||
|
|
||||||
LEFT_PRIMARY_INDEX,
|
LEFT_PRIMARY_INDEX,
|
||||||
LEFT_SECONDARY_INDEX,
|
LEFT_SECONDARY_INDEX,
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "filters/InvertFilter.h"
|
#include "filters/InvertFilter.h"
|
||||||
#include "filters/PulseFilter.h"
|
#include "filters/PulseFilter.h"
|
||||||
#include "filters/ScaleFilter.h"
|
#include "filters/ScaleFilter.h"
|
||||||
|
#include "conditionals/AndConditional.h"
|
||||||
|
|
||||||
using namespace controller;
|
using namespace controller;
|
||||||
|
|
||||||
|
@ -58,12 +59,22 @@ QObject* RouteBuilderProxy::peek(bool enable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* RouteBuilderProxy::when(const QScriptValue& expression) {
|
QObject* RouteBuilderProxy::when(const QScriptValue& expression) {
|
||||||
_route->conditional = _parent.conditionalFor(expression);
|
auto newConditional = _parent.conditionalFor(expression);
|
||||||
|
if (_route->conditional) {
|
||||||
|
_route->conditional = ConditionalPointer(new AndConditional(_route->conditional, newConditional));
|
||||||
|
} else {
|
||||||
|
_route->conditional = newConditional;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* RouteBuilderProxy::whenQml(const QJSValue& expression) {
|
QObject* RouteBuilderProxy::whenQml(const QJSValue& expression) {
|
||||||
_route->conditional = _parent.conditionalFor(expression);
|
auto newConditional = _parent.conditionalFor(expression);
|
||||||
|
if (_route->conditional) {
|
||||||
|
_route->conditional = ConditionalPointer(new AndConditional(_route->conditional, newConditional));
|
||||||
|
} else {
|
||||||
|
_route->conditional = newConditional;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,9 @@ class OffscreenFlags : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool navigationFocused READ isNavigationFocused WRITE setNavigationFocused NOTIFY navigationFocusedChanged)
|
Q_PROPERTY(bool navigationFocused READ isNavigationFocused WRITE setNavigationFocused NOTIFY navigationFocusedChanged)
|
||||||
|
|
||||||
|
// Allow scripts that are doing their own navigation support to disable navigation focus (i.e. handControllerPointer.js)
|
||||||
|
Q_PROPERTY(bool navigationFocusDisabled READ isNavigationFocusDisabled WRITE setNavigationFocusDisabled NOTIFY navigationFocusDisabledChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
OffscreenFlags(QObject* parent = nullptr) : QObject(parent) {}
|
OffscreenFlags(QObject* parent = nullptr) : QObject(parent) {}
|
||||||
|
@ -40,11 +43,21 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isNavigationFocusDisabled() const { return _navigationFocusDisabled; }
|
||||||
|
void setNavigationFocusDisabled(bool disabled) {
|
||||||
|
if (_navigationFocusDisabled != disabled) {
|
||||||
|
_navigationFocusDisabled = disabled;
|
||||||
|
emit navigationFocusDisabledChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void navigationFocusedChanged();
|
void navigationFocusedChanged();
|
||||||
|
void navigationFocusDisabledChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _navigationFocused { false };
|
bool _navigationFocused { false };
|
||||||
|
bool _navigationFocusDisabled{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
QString fixupHifiUrl(const QString& urlString) {
|
QString fixupHifiUrl(const QString& urlString) {
|
||||||
|
@ -103,6 +116,10 @@ bool OffscreenUi::shouldSwallowShortcut(QEvent* event) {
|
||||||
OffscreenUi::OffscreenUi() {
|
OffscreenUi::OffscreenUi() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QObject* OffscreenUi::getFlags() {
|
||||||
|
return offscreenFlags;
|
||||||
|
}
|
||||||
|
|
||||||
void OffscreenUi::create(QOpenGLContext* context) {
|
void OffscreenUi::create(QOpenGLContext* context) {
|
||||||
OffscreenQmlSurface::create(context);
|
OffscreenQmlSurface::create(context);
|
||||||
auto rootContext = getRootContext();
|
auto rootContext = getRootContext();
|
||||||
|
@ -392,7 +409,7 @@ QVariant OffscreenUi::waitForInputDialogResult(QQuickItem* inputDialog) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OffscreenUi::navigationFocused() {
|
bool OffscreenUi::navigationFocused() {
|
||||||
return offscreenFlags->isNavigationFocused();
|
return !offscreenFlags->isNavigationFocusDisabled() && offscreenFlags->isNavigationFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenUi::setNavigationFocused(bool focused) {
|
void OffscreenUi::setNavigationFocused(bool focused) {
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
|
|
||||||
bool eventFilter(QObject* originalDestination, QEvent* event) override;
|
bool eventFilter(QObject* originalDestination, QEvent* event) override;
|
||||||
void addMenuInitializer(std::function<void(VrMenu*)> f);
|
void addMenuInitializer(std::function<void(VrMenu*)> f);
|
||||||
|
QObject* getFlags();
|
||||||
QQuickItem* getDesktop();
|
QQuickItem* getDesktop();
|
||||||
QQuickItem* getToolWindow();
|
QQuickItem* getToolWindow();
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <UserActivityLogger.h>
|
#include <UserActivityLogger.h>
|
||||||
#include <OffscreenUi.h>
|
#include <OffscreenUi.h>
|
||||||
|
|
||||||
|
|
||||||
#include <controllers/UserInputMapper.h>
|
#include <controllers/UserInputMapper.h>
|
||||||
|
|
||||||
#include <controllers/StandardControls.h>
|
#include <controllers/StandardControls.h>
|
||||||
|
@ -284,7 +285,6 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u
|
||||||
|
|
||||||
vr::VRControllerState_t controllerState = vr::VRControllerState_t();
|
vr::VRControllerState_t controllerState = vr::VRControllerState_t();
|
||||||
if (_system->GetControllerState(deviceIndex, &controllerState)) {
|
if (_system->GetControllerState(deviceIndex, &controllerState)) {
|
||||||
|
|
||||||
// process each button
|
// process each button
|
||||||
for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) {
|
for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) {
|
||||||
auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i);
|
auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i);
|
||||||
|
@ -342,6 +342,11 @@ void ViveControllerManager::InputDevice::handleAxisEvent(float deltaTime, uint32
|
||||||
_axisStateMap[isLeftHand ? LY : RY] = stick.y;
|
_axisStateMap[isLeftHand ? LY : RY] = stick.y;
|
||||||
} else if (axis == vr::k_EButton_SteamVR_Trigger) {
|
} else if (axis == vr::k_EButton_SteamVR_Trigger) {
|
||||||
_axisStateMap[isLeftHand ? LT : RT] = x;
|
_axisStateMap[isLeftHand ? LT : RT] = x;
|
||||||
|
// The click feeling on the Vive controller trigger represents a value of *precisely* 1.0,
|
||||||
|
// so we can expose that as an additional button
|
||||||
|
if (x >= 1.0f) {
|
||||||
|
_buttonPressedMap.insert(isLeftHand ? LT_CLICK : RT_CLICK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,10 +468,15 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI
|
||||||
makePair(RS_X, "RSX"),
|
makePair(RS_X, "RSX"),
|
||||||
makePair(RS_Y, "RSY"),
|
makePair(RS_Y, "RSY"),
|
||||||
|
|
||||||
|
|
||||||
// triggers
|
// triggers
|
||||||
makePair(LT, "LT"),
|
makePair(LT, "LT"),
|
||||||
makePair(RT, "RT"),
|
makePair(RT, "RT"),
|
||||||
|
|
||||||
|
// Trigger clicks
|
||||||
|
makePair(LT_CLICK, "LTClick"),
|
||||||
|
makePair(RT_CLICK, "RTClick"),
|
||||||
|
|
||||||
// low profile side grip button.
|
// low profile side grip button.
|
||||||
makePair(LEFT_GRIP, "LeftGrip"),
|
makePair(LEFT_GRIP, "LeftGrip"),
|
||||||
makePair(RIGHT_GRIP, "RightGrip"),
|
makePair(RIGHT_GRIP, "RightGrip"),
|
||||||
|
|
|
@ -29,9 +29,8 @@ var WANT_DEBUG_SEARCH_NAME = null;
|
||||||
var SPARK_MODEL_SCALE_FACTOR = 0.75;
|
var SPARK_MODEL_SCALE_FACTOR = 0.75;
|
||||||
|
|
||||||
var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing
|
var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing
|
||||||
var TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near grab
|
var TRIGGER_OFF_VALUE = 0.1;
|
||||||
var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab
|
var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab
|
||||||
var TRIGGER_OFF_VALUE = 0.15;
|
|
||||||
|
|
||||||
var COLLIDE_WITH_AV_AFTER_RELEASE_DELAY = 0.25; // seconds
|
var COLLIDE_WITH_AV_AFTER_RELEASE_DELAY = 0.25; // seconds
|
||||||
|
|
||||||
|
@ -393,6 +392,7 @@ function MyController(hand) {
|
||||||
this.entityActivated = false;
|
this.entityActivated = false;
|
||||||
|
|
||||||
this.triggerValue = 0; // rolling average of trigger value
|
this.triggerValue = 0; // rolling average of trigger value
|
||||||
|
this.triggerClicked = false;
|
||||||
this.rawTriggerValue = 0;
|
this.rawTriggerValue = 0;
|
||||||
this.rawSecondaryValue = 0;
|
this.rawSecondaryValue = 0;
|
||||||
this.rawThumbValue = 0;
|
this.rawThumbValue = 0;
|
||||||
|
@ -852,6 +852,10 @@ function MyController(hand) {
|
||||||
_this.rawTriggerValue = value;
|
_this.rawTriggerValue = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.triggerClick = function (value) {
|
||||||
|
_this.triggerClicked = value;
|
||||||
|
};
|
||||||
|
|
||||||
this.secondaryPress = function (value) {
|
this.secondaryPress = function (value) {
|
||||||
_this.rawSecondaryValue = value;
|
_this.rawSecondaryValue = value;
|
||||||
};
|
};
|
||||||
|
@ -864,7 +868,7 @@ function MyController(hand) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.triggerSmoothedGrab = function () {
|
this.triggerSmoothedGrab = function () {
|
||||||
return this.triggerValue > TRIGGER_GRAB_VALUE;
|
return this.triggerClicked;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.triggerSmoothedSqueezed = function () {
|
this.triggerSmoothedSqueezed = function () {
|
||||||
|
@ -2293,7 +2297,10 @@ var MAPPING_NAME = "com.highfidelity.handControllerGrab";
|
||||||
|
|
||||||
var mapping = Controller.newMapping(MAPPING_NAME);
|
var mapping = Controller.newMapping(MAPPING_NAME);
|
||||||
mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress);
|
mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress);
|
||||||
|
mapping.from([Controller.Standard.RTClick]).peek().to(rightController.triggerClick);
|
||||||
|
|
||||||
mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress);
|
mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress);
|
||||||
|
mapping.from([Controller.Standard.LTClick]).peek().to(leftController.triggerClick);
|
||||||
|
|
||||||
mapping.from([Controller.Standard.RB]).peek().to(rightController.secondaryPress);
|
mapping.from([Controller.Standard.RB]).peek().to(rightController.secondaryPress);
|
||||||
mapping.from([Controller.Standard.LB]).peek().to(leftController.secondaryPress);
|
mapping.from([Controller.Standard.LB]).peek().to(leftController.secondaryPress);
|
||||||
|
|
|
@ -49,23 +49,23 @@ function Trigger(label) {
|
||||||
var that = this;
|
var that = this;
|
||||||
that.label = label;
|
that.label = label;
|
||||||
that.TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing
|
that.TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing
|
||||||
that.TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near grab
|
that.TRIGGER_OFF_VALUE = 0.10;
|
||||||
that.TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab
|
that.TRIGGER_ON_VALUE = that.TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab
|
||||||
that.TRIGGER_OFF_VALUE = 0.15;
|
|
||||||
that.rawTriggerValue = 0;
|
that.rawTriggerValue = 0;
|
||||||
that.triggerValue = 0; // rolling average of trigger value
|
that.triggerValue = 0; // rolling average of trigger value
|
||||||
that.triggerPress = function (value) {
|
that.triggerClicked = false;
|
||||||
that.rawTriggerValue = value;
|
that.triggerClick = function (value) { that.triggerClicked = value; };
|
||||||
};
|
that.triggerPress = function (value) { that.rawTriggerValue = value; };
|
||||||
that.updateSmoothedTrigger = function () { // e.g., call once/update for effect
|
that.updateSmoothedTrigger = function () { // e.g., call once/update for effect
|
||||||
var triggerValue = that.rawTriggerValue;
|
var triggerValue = that.rawTriggerValue;
|
||||||
// smooth out trigger value
|
// smooth out trigger value
|
||||||
that.triggerValue = (that.triggerValue * that.TRIGGER_SMOOTH_RATIO) +
|
that.triggerValue = (that.triggerValue * that.TRIGGER_SMOOTH_RATIO) +
|
||||||
(triggerValue * (1.0 - that.TRIGGER_SMOOTH_RATIO));
|
(triggerValue * (1.0 - that.TRIGGER_SMOOTH_RATIO));
|
||||||
|
OffscreenFlags.navigationFocusDisabled = that.triggerValue != 0.0;
|
||||||
};
|
};
|
||||||
// Current smoothed state, without hysteresis. Answering booleans.
|
// Current smoothed state, without hysteresis. Answering booleans.
|
||||||
that.triggerSmoothedGrab = function () {
|
that.triggerSmoothedClick = function () {
|
||||||
return that.triggerValue > that.TRIGGER_GRAB_VALUE;
|
return that.triggerClicked;
|
||||||
};
|
};
|
||||||
that.triggerSmoothedSqueezed = function () {
|
that.triggerSmoothedSqueezed = function () {
|
||||||
return that.triggerValue > that.TRIGGER_ON_VALUE;
|
return that.triggerValue > that.TRIGGER_ON_VALUE;
|
||||||
|
@ -81,7 +81,7 @@ function Trigger(label) {
|
||||||
that.updateSmoothedTrigger();
|
that.updateSmoothedTrigger();
|
||||||
|
|
||||||
// The first two are independent of previous state:
|
// The first two are independent of previous state:
|
||||||
if (that.triggerSmoothedGrab()) {
|
if (that.triggerSmoothedClick()) {
|
||||||
state = 'full';
|
state = 'full';
|
||||||
} else if (that.triggerSmoothedReleased()) {
|
} else if (that.triggerSmoothedReleased()) {
|
||||||
state = null;
|
state = null;
|
||||||
|
@ -365,6 +365,8 @@ Script.scriptEnding.connect(clickMapping.disable);
|
||||||
// Gather the trigger data for smoothing.
|
// Gather the trigger data for smoothing.
|
||||||
clickMapping.from(Controller.Standard.RT).peek().to(rightTrigger.triggerPress);
|
clickMapping.from(Controller.Standard.RT).peek().to(rightTrigger.triggerPress);
|
||||||
clickMapping.from(Controller.Standard.LT).peek().to(leftTrigger.triggerPress);
|
clickMapping.from(Controller.Standard.LT).peek().to(leftTrigger.triggerPress);
|
||||||
|
clickMapping.from(Controller.Standard.RTClick).peek().to(rightTrigger.triggerClick);
|
||||||
|
clickMapping.from(Controller.Standard.LTClick).peek().to(leftTrigger.triggerClick);
|
||||||
// Full smoothed trigger is a click.
|
// Full smoothed trigger is a click.
|
||||||
function isPointingAtOverlayStartedNonFullTrigger(trigger) {
|
function isPointingAtOverlayStartedNonFullTrigger(trigger) {
|
||||||
// true if isPointingAtOverlay AND we were NOT full triggered when we became so.
|
// true if isPointingAtOverlay AND we were NOT full triggered when we became so.
|
||||||
|
@ -493,7 +495,10 @@ function checkSettings() {
|
||||||
updateRecommendedArea();
|
updateRecommendedArea();
|
||||||
}
|
}
|
||||||
checkSettings();
|
checkSettings();
|
||||||
|
|
||||||
var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL);
|
var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL);
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
Script.clearInterval(settingsChecker);
|
Script.clearInterval(settingsChecker);
|
||||||
|
OffscreenFlags.navigationFocusDisabled = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
87
scripts/system/libraries/Trigger.js
Normal file
87
scripts/system/libraries/Trigger.js
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*jslint vars: true, plusplus: true*/
|
||||||
|
/*globals Script, Overlays, Controller, Reticle, HMD, Camera, Entities, MyAvatar, Settings, Menu, ScriptDiscoveryService, Window, Vec3, Quat, print*/
|
||||||
|
|
||||||
|
Trigger = function(properties) {
|
||||||
|
properties = properties || {};
|
||||||
|
var that = this;
|
||||||
|
that.label = properties.label || Math.random();
|
||||||
|
that.SMOOTH_RATIO = properties.smooth || 0.1; // Time averaging of trigger - 0.0 disables smoothing
|
||||||
|
that.DEADZONE = properties.deadzone || 0.10; // Once pressed, a trigger must fall below the deadzone to be considered un-pressed once pressed.
|
||||||
|
that.HYSTERESIS = properties.hystersis || 0.05; // If not pressed, a trigger must go above DEADZONE + HYSTERSIS to be considered pressed
|
||||||
|
|
||||||
|
that.value = 0;
|
||||||
|
that.pressed = false;
|
||||||
|
that.clicked = false;
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
that.onPress = properties.onPress || function(){
|
||||||
|
print("Pressed trigger " + that.label)
|
||||||
|
};
|
||||||
|
that.onRelease = properties.onRelease || function(){
|
||||||
|
print("Released trigger " + that.label)
|
||||||
|
};
|
||||||
|
that.onClick = properties.onClick || function(){
|
||||||
|
print("Clicked trigger " + that.label)
|
||||||
|
};
|
||||||
|
that.onUnclick = properties.onUnclick || function(){
|
||||||
|
print("Unclicked trigger " + that.label)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
that.isPressed = function() {
|
||||||
|
return that.pressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
that.isClicked = function() {
|
||||||
|
return that.clicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
that.getValue = function() {
|
||||||
|
return that.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Private values
|
||||||
|
var controller = properties.controller || Controller.Standard.LT;
|
||||||
|
var controllerClick = properties.controllerClick || Controller.Standard.LTClick;
|
||||||
|
that.mapping = Controller.newMapping('com.highfidelity.controller.trigger.' + controller + '-' + controllerClick + '.' + that.label + Math.random());
|
||||||
|
Script.scriptEnding.connect(that.mapping.disable);
|
||||||
|
|
||||||
|
// Setup mapping,
|
||||||
|
that.mapping.from(controller).peek().to(function(value) {
|
||||||
|
that.value = (that.value * that.SMOOTH_RATIO) +
|
||||||
|
(value * (1.0 - that.SMOOTH_RATIO));
|
||||||
|
|
||||||
|
var oldPressed = that.pressed;
|
||||||
|
if (!that.pressed && that.value >= (that.DEADZONE + that.HYSTERESIS)) {
|
||||||
|
that.pressed = true;
|
||||||
|
that.onPress();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (that.pressed && that.value < that.HYSTERESIS) {
|
||||||
|
that.pressed = false;
|
||||||
|
that.onRelease();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
that.mapping.from(controllerClick).peek().to(function(value){
|
||||||
|
if (!that.clicked && value > 0.0) {
|
||||||
|
that.clicked = true;
|
||||||
|
that.onClick();
|
||||||
|
}
|
||||||
|
if (that.clicked && value == 0.0) {
|
||||||
|
that.clicked = false;
|
||||||
|
that.onUnclick();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
that.enable = function() {
|
||||||
|
that.mapping.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
that.disable = function() {
|
||||||
|
that.mapping.disable();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue