Merge branch 'master' into loginInitiative2

This commit is contained in:
Wayne Chen 2018-12-12 18:00:07 -08:00 committed by GitHub
commit 4116f6ca9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 536 additions and 129 deletions

View file

@ -110,6 +110,8 @@ public:
void setBaseDisplayName(const QString& baseDisplayName) { _baseDisplayName = baseDisplayName; }
bool getRequestsDomainListData() { return _requestsDomainListData; }
void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; }
bool getPrevRequestsDomainListData() { return _prevRequestsDomainListData; }
void setPrevRequestsDomainListData(bool requesting) { _prevRequestsDomainListData = requesting; }
const ConicalViewFrustums& getViewFrustums() const { return _currentViewFrustums; }
@ -176,6 +178,7 @@ private:
int _recentOtherAvatarsOutOfView { 0 };
QString _baseDisplayName{}; // The santized key used in determinging unique sessionDisplayName, so that we can remove from dictionary.
bool _requestsDomainListData { false };
bool _prevRequestsDomainListData{ false };
AvatarTraits::TraitVersions _lastReceivedTraitVersions;
TraitsCheckTimestamp _lastReceivedTraitsChange;

View file

@ -268,6 +268,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
// When this is true, the AvatarMixer will send Avatar data to a client
// about avatars they've ignored or that are out of view
bool PALIsOpen = nodeData->getRequestsDomainListData();
bool PALWasOpen = nodeData->getPrevRequestsDomainListData();
// When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them
bool getsAnyIgnored = PALIsOpen && destinationNode->getCanKick();
@ -392,6 +393,20 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
sortedAvatars.push(SortableAvatar(avatarNodeData, avatarNode, lastEncodeTime));
}
// If Avatar A's PAL WAS open but is no longer open, AND
// Avatar A should be ignoring Avatar B...
if (PALWasOpen && !PALIsOpen && shouldIgnore) {
// ...send a Kill Packet to Node A, instructing Node A to kill Avatar B,
// then have Node A cleanup the killed Node B.
auto packet = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason), true);
packet->write(avatarNode->getUUID().toRfc4122());
packet->writePrimitive(KillAvatarReason::AvatarIgnored);
nodeList->sendPacket(std::move(packet), *destinationNode);
nodeData->cleanupKilledNode(avatarNode->getUUID(), avatarNode->getLocalID());
}
nodeData->setPrevRequestsDomainListData(PALIsOpen);
}
// loop through our sorted avatars and allocate our bandwidth to them accordingly

View file

@ -1,4 +1,22 @@
{
"backPlate": {
"dimensions": {
"x": 0.723600000888109207,
"y": 0.022600000724196434,
"z": 0.2474999976158142
},
"position": {
"x": -0.3292800903320312,
"y": 0.004300000742077827,
"z": -0.055427663803100586
},
"rotation": {
"w": 1.000,
"x": 0.000,
"y": 0.000,
"z": 0.000
}
},
"anchor": {
"dimensions": {
"x": 0.023600000888109207,

View file

@ -70,6 +70,15 @@ ScrollingWindow {
}
}
var useKeyboardPreference = findPreference("User Interface", "Use Virtual Keyboard");
var keyboardInputPreference = findPreference("User Interface", "Keyboard laser / mallets");
if (useKeyboardPreference && keyboardInputPreference) {
keyboardInputPreference.visible = useKeyboardPreference.value;
useKeyboardPreference.valueChanged.connect(function() {
keyboardInputPreference.visible = useKeyboardPreference.value;
});
}
if (sections.length) {
// Default sections to expanded/collapsed as appropriate for dialog.
if (sections.length === 1) {
@ -112,4 +121,32 @@ ScrollingWindow {
onClicked: root.restoreAll()
}
}
function findPreference(category, name) {
var section = null;
var preference = null;
var i;
// Find category section.
i = 0;
while (!section && i < sections.length) {
if (sections[i].name === category) {
section = sections[i];
}
i++;
}
// Find named preference.
if (section) {
i = 0;
while (!preference && i < section.preferences.length) {
if (section.preferences[i].preference && section.preferences[i].preference.name === name) {
preference = section.preferences[i];
}
i++;
}
}
return preference;
}
}

View file

@ -19,6 +19,7 @@ Preference {
property bool value: false
Component.onCompleted: {
checkBox.checked = preference.value;
value = checkBox.checked;
preference.value = Qt.binding(function(){ return checkBox.checked; });
value = checkBox.checked;
}

View file

@ -20,6 +20,11 @@ Preference {
property int value: 0
readonly property int visibleBottomPadding: 3
readonly property int invisibleBottomPadding: 0
readonly property int indentLeftMargin: 20
readonly property int nonindentLeftMargin: 0
Component.onCompleted: {
value = preference.value;
repeater.itemAt(preference.value).checked = true;
@ -46,24 +51,24 @@ Preference {
preference.save();
}
RalewaySemiBold {
id: heading
size: hifi.fontSizes.inputLabel
text: preference.heading
color: hifi.colors.lightGrayText
visible: text !== ""
bottomPadding: heading.visible ? visibleBottomPadding : invisibleBottomPadding
}
Column {
id: control
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
top: heading.visible ? heading.bottom : heading.top
leftMargin: preference.indented ? indentLeftMargin : nonindentLeftMargin
}
spacing: 3
RalewaySemiBold {
id: heading
size: hifi.fontSizes.inputLabel
text: preference.heading
color: hifi.colors.lightGrayText
visible: text !== ""
bottomPadding: 3
}
Repeater {
id: repeater
model: preference.items.length

View file

@ -138,6 +138,15 @@ Item {
}
}
var useKeyboardPreference = findPreference("User Interface", "Use Virtual Keyboard");
var keyboardInputPreference = findPreference("User Interface", "Keyboard laser / mallets");
if (useKeyboardPreference && keyboardInputPreference) {
keyboardInputPreference.visible = useKeyboardPreference.value;
useKeyboardPreference.valueChanged.connect(function() {
keyboardInputPreference.visible = useKeyboardPreference.value;
});
}
if (sections.length) {
// Default sections to expanded/collapsed as appropriate for dialog.
if (sections.length === 1) {

Binary file not shown.

View file

@ -5746,7 +5746,44 @@ void Application::updateSecondaryCameraViewFrustum() {
}
ViewFrustum secondaryViewFrustum;
if (camera->mirrorProjection && !camera->attachedEntityId.isNull()) {
if (camera->portalProjection && !camera->attachedEntityId.isNull() && !camera->portalEntranceEntityId.isNull()) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
EntityItemPointer portalEntrance = qApp->getEntities()->getTree()->findEntityByID(camera->portalEntranceEntityId);
EntityItemPointer portalExit = qApp->getEntities()->getTree()->findEntityByID(camera->attachedEntityId);
glm::vec3 portalEntrancePropertiesPosition = portalEntrance->getWorldPosition();
glm::quat portalEntrancePropertiesRotation = portalEntrance->getWorldOrientation();
glm::mat4 worldFromPortalEntranceRotation = glm::mat4_cast(portalEntrancePropertiesRotation);
glm::mat4 worldFromPortalEntranceTranslation = glm::translate(portalEntrancePropertiesPosition);
glm::mat4 worldFromPortalEntrance = worldFromPortalEntranceTranslation * worldFromPortalEntranceRotation;
glm::mat4 portalEntranceFromWorld = glm::inverse(worldFromPortalEntrance);
glm::vec3 portalExitPropertiesPosition = portalExit->getWorldPosition();
glm::quat portalExitPropertiesRotation = portalExit->getWorldOrientation();
glm::vec3 portalExitPropertiesDimensions = portalExit->getScaledDimensions();
glm::vec3 halfPortalExitPropertiesDimensions = 0.5f * portalExitPropertiesDimensions;
glm::mat4 worldFromPortalExitRotation = glm::mat4_cast(portalExitPropertiesRotation);
glm::mat4 worldFromPortalExitTranslation = glm::translate(portalExitPropertiesPosition);
glm::mat4 worldFromPortalExit = worldFromPortalExitTranslation * worldFromPortalExitRotation;
glm::vec3 mainCameraPositionWorld = getCamera().getPosition();
glm::vec3 mainCameraPositionPortalEntrance = vec3(portalEntranceFromWorld * vec4(mainCameraPositionWorld, 1.0f));
mainCameraPositionPortalEntrance = vec3(-mainCameraPositionPortalEntrance.x, mainCameraPositionPortalEntrance.y,
-mainCameraPositionPortalEntrance.z);
glm::vec3 portalExitCameraPositionWorld = vec3(worldFromPortalExit * vec4(mainCameraPositionPortalEntrance, 1.0f));
secondaryViewFrustum.setPosition(portalExitCameraPositionWorld);
secondaryViewFrustum.setOrientation(portalExitPropertiesRotation);
float nearClip = mainCameraPositionPortalEntrance.z + portalExitPropertiesDimensions.z * 2.0f;
// `mainCameraPositionPortalEntrance` should technically be `mainCameraPositionPortalExit`,
// but the values are the same.
glm::vec3 upperRight = halfPortalExitPropertiesDimensions - mainCameraPositionPortalEntrance;
glm::vec3 bottomLeft = -halfPortalExitPropertiesDimensions - mainCameraPositionPortalEntrance;
glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance);
secondaryViewFrustum.setProjection(frustum);
} else if (camera->mirrorProjection && !camera->attachedEntityId.isNull()) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId);
glm::vec3 mirrorPropertiesPosition = entityProperties.getPosition();

View file

@ -33,6 +33,7 @@ public:
void configure(const Config& config) {
_attachedEntityId = config.attachedEntityId;
_portalEntranceEntityId = config.portalEntranceEntityId;
_position = config.position;
_orientation = config.orientation;
_vFoV = config.vFoV;
@ -40,7 +41,60 @@ public:
_farClipPlaneDistance = config.farClipPlaneDistance;
_textureWidth = config.textureWidth;
_textureHeight = config.textureHeight;
_mirrorProjection = config.mirrorProjection;
_mirrorProjection = config.mirrorProjection;
_portalProjection = config.portalProjection;
}
void setPortalProjection(ViewFrustum& srcViewFrustum) {
if (_portalEntranceEntityId.isNull() || _attachedEntityId.isNull()) {
qWarning() << "ERROR: Cannot set portal projection for SecondaryCamera without an attachedEntityId AND portalEntranceEntityId set.";
return;
}
EntityItemPointer portalEntrance = qApp->getEntities()->getTree()->findEntityByID(_portalEntranceEntityId);
if (!portalEntrance) {
qWarning() << "ERROR: Cannot get EntityItemPointer for portalEntrance.";
return;
}
EntityItemPointer portalExit = qApp->getEntities()->getTree()->findEntityByID(_attachedEntityId);
if (!portalExit) {
qWarning() << "ERROR: Cannot get EntityItemPointer for portalExit.";
return;
}
glm::vec3 portalEntrancePropertiesPosition = portalEntrance->getWorldPosition();
glm::quat portalEntrancePropertiesRotation = portalEntrance->getWorldOrientation();
glm::mat4 worldFromPortalEntranceRotation = glm::mat4_cast(portalEntrancePropertiesRotation);
glm::mat4 worldFromPortalEntranceTranslation = glm::translate(portalEntrancePropertiesPosition);
glm::mat4 worldFromPortalEntrance = worldFromPortalEntranceTranslation * worldFromPortalEntranceRotation;
glm::mat4 portalEntranceFromWorld = glm::inverse(worldFromPortalEntrance);
glm::vec3 portalExitPropertiesPosition = portalExit->getWorldPosition();
glm::quat portalExitPropertiesRotation = portalExit->getWorldOrientation();
glm::vec3 portalExitPropertiesDimensions = portalExit->getScaledDimensions();
glm::vec3 halfPortalExitPropertiesDimensions = 0.5f * portalExitPropertiesDimensions;
glm::mat4 worldFromPortalExitRotation = glm::mat4_cast(portalExitPropertiesRotation);
glm::mat4 worldFromPortalExitTranslation = glm::translate(portalExitPropertiesPosition);
glm::mat4 worldFromPortalExit = worldFromPortalExitTranslation * worldFromPortalExitRotation;
glm::vec3 mainCameraPositionWorld = qApp->getCamera().getPosition();
glm::vec3 mainCameraPositionPortalEntrance = vec3(portalEntranceFromWorld * vec4(mainCameraPositionWorld, 1.0f));
mainCameraPositionPortalEntrance = vec3(-mainCameraPositionPortalEntrance.x, mainCameraPositionPortalEntrance.y,
-mainCameraPositionPortalEntrance.z);
glm::vec3 portalExitCameraPositionWorld = vec3(worldFromPortalExit * vec4(mainCameraPositionPortalEntrance, 1.0f));
srcViewFrustum.setPosition(portalExitCameraPositionWorld);
srcViewFrustum.setOrientation(portalExitPropertiesRotation);
float nearClip = mainCameraPositionPortalEntrance.z + portalExitPropertiesDimensions.z * 2.0f;
// `mainCameraPositionPortalEntrance` should technically be `mainCameraPositionPortalExit`,
// but the values are the same.
glm::vec3 upperRight = halfPortalExitPropertiesDimensions - mainCameraPositionPortalEntrance;
glm::vec3 bottomLeft = -halfPortalExitPropertiesDimensions - mainCameraPositionPortalEntrance;
glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, _farClipPlaneDistance);
srcViewFrustum.setProjection(frustum);
}
void setMirrorProjection(ViewFrustum& srcViewFrustum) {
@ -109,7 +163,17 @@ public:
auto srcViewFrustum = args->getViewFrustum();
if (_mirrorProjection) {
setMirrorProjection(srcViewFrustum);
if (_portalProjection) {
qWarning() << "ERROR: You can't set both _portalProjection and _mirrorProjection";
} else {
setMirrorProjection(srcViewFrustum);
}
} else if (_portalProjection) {
if (_mirrorProjection) {
qWarning() << "ERROR: You can't set both _portalProjection and _mirrorProjection";
} else {
setPortalProjection(srcViewFrustum);
}
} else {
if (!_attachedEntityId.isNull()) {
EntityItemPointer attachedEntity = qApp->getEntities()->getTree()->findEntityByID(_attachedEntityId);
@ -141,6 +205,7 @@ protected:
private:
QUuid _attachedEntityId;
QUuid _portalEntranceEntityId;
glm::vec3 _position;
glm::quat _orientation;
float _vFoV;
@ -149,6 +214,7 @@ private:
int _textureWidth;
int _textureHeight;
bool _mirrorProjection;
bool _portalProjection;
EntityPropertyFlags _attachedEntityPropertyFlags;
};

View file

@ -20,14 +20,17 @@
class SecondaryCameraJobConfig : public render::Task::Config { // Exposes secondary camera parameters to JavaScript.
Q_OBJECT
Q_PROPERTY(QUuid attachedEntityId MEMBER attachedEntityId NOTIFY dirty) // entity whose properties define camera position and orientation
Q_PROPERTY(QUuid portalEntranceEntityId MEMBER portalEntranceEntityId NOTIFY dirty) // entity whose properties define a portal's entrance position and orientation
Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) // of viewpoint to render from
Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation) // of viewpoint to render from
Q_PROPERTY(float vFoV MEMBER vFoV NOTIFY dirty) // Secondary camera's vertical field of view. In degrees.
Q_PROPERTY(float nearClipPlaneDistance MEMBER nearClipPlaneDistance NOTIFY dirty) // Secondary camera's near clip plane distance. In meters.
Q_PROPERTY(float farClipPlaneDistance MEMBER farClipPlaneDistance NOTIFY dirty) // Secondary camera's far clip plane distance. In meters.
Q_PROPERTY(bool mirrorProjection MEMBER mirrorProjection NOTIFY dirty) // Flag to use attached mirror entity to build frustum for the mirror and set mirrored camera position/orientation.
Q_PROPERTY(bool portalProjection MEMBER portalProjection NOTIFY dirty) // Flag to use attached portal entity to build frustum for the portal and set portal camera position/orientation.
public:
QUuid attachedEntityId;
QUuid portalEntranceEntityId;
glm::vec3 position;
glm::quat orientation;
float vFoV { DEFAULT_FIELD_OF_VIEW_DEGREES };
@ -36,6 +39,7 @@ public:
int textureWidth { TextureCache::DEFAULT_SPECTATOR_CAM_WIDTH };
int textureHeight { TextureCache::DEFAULT_SPECTATOR_CAM_HEIGHT };
bool mirrorProjection { false };
bool portalProjection { false };
SecondaryCameraJobConfig() : render::Task::Config(false) {}
signals:

View file

@ -12,7 +12,7 @@
#include "KeyboardScriptingInterface.h"
#include "ui/Keyboard.h"
bool KeyboardScriptingInterface::isRaised() {
bool KeyboardScriptingInterface::isRaised() const {
return DependencyManager::get<Keyboard>()->isRaised();
}
@ -20,8 +20,7 @@ void KeyboardScriptingInterface::setRaised(bool raised) {
DependencyManager::get<Keyboard>()->setRaised(raised);
}
bool KeyboardScriptingInterface::isPassword() {
bool KeyboardScriptingInterface::isPassword() const {
return DependencyManager::get<Keyboard>()->isPassword();
}
@ -33,6 +32,38 @@ void KeyboardScriptingInterface::loadKeyboardFile(const QString& keyboardFile) {
DependencyManager::get<Keyboard>()->loadKeyboardFile(keyboardFile);
}
bool KeyboardScriptingInterface::getUse3DKeyboard() {
bool KeyboardScriptingInterface::getUse3DKeyboard() const {
return DependencyManager::get<Keyboard>()->getUse3DKeyboard();
}
void KeyboardScriptingInterface::disableRightMallet() {
DependencyManager::get<Keyboard>()->disableRightMallet();
}
void KeyboardScriptingInterface::disableLeftMallet() {
DependencyManager::get<Keyboard>()->disableLeftMallet();
}
void KeyboardScriptingInterface::enableRightMallet() {
DependencyManager::get<Keyboard>()->enableRightMallet();
}
void KeyboardScriptingInterface::enableLeftMallet() {
DependencyManager::get<Keyboard>()->enableLeftMallet();
}
void KeyboardScriptingInterface::setLeftHandLaser(unsigned int leftHandLaser) {
DependencyManager::get<Keyboard>()->setLeftHandLaser(leftHandLaser);
}
void KeyboardScriptingInterface::setRightHandLaser(unsigned int rightHandLaser) {
DependencyManager::get<Keyboard>()->setRightHandLaser(rightHandLaser);
}
bool KeyboardScriptingInterface::getPreferMalletsOverLasers() const {
return DependencyManager::get<Keyboard>()->getPreferMalletsOverLasers();
}
bool KeyboardScriptingInterface::containsID(OverlayID overlayID) const {
return DependencyManager::get<Keyboard>()->containsID(overlayID);
}

View file

@ -16,6 +16,7 @@
#include <QtCore/QUuid>
#include "DependencyManager.h"
#include "ui/overlays/Overlay.h"
/**jsdoc
* The Keyboard API provides facilities to use 3D Physical keyboard.
@ -27,22 +28,33 @@
* @property {bool} raised - <code>true</code> If the keyboard is visible <code>false</code> otherwise
* @property {bool} password - <code>true</code> Will show * instead of characters in the text display <code>false</code> otherwise
*/
class KeyboardScriptingInterface : public QObject, public Dependency {
Q_OBJECT
Q_PROPERTY(bool raised READ isRaised WRITE setRaised)
Q_PROPERTY(bool password READ isPassword WRITE setPassword)
Q_PROPERTY(bool use3DKeyboard READ getUse3DKeyboard);
Q_PROPERTY(bool use3DKeyboard READ getUse3DKeyboard CONSTANT);
Q_PROPERTY(bool preferMalletsOverLasers READ getPreferMalletsOverLasers CONSTANT)
public:
KeyboardScriptingInterface() = default;
~KeyboardScriptingInterface() = default;
Q_INVOKABLE void loadKeyboardFile(const QString& string);
Q_INVOKABLE void enableLeftMallet();
Q_INVOKABLE void enableRightMallet();
Q_INVOKABLE void disableLeftMallet();
Q_INVOKABLE void disableRightMallet();
Q_INVOKABLE void setLeftHandLaser(unsigned int leftHandLaser);
Q_INVOKABLE void setRightHandLaser(unsigned int rightHandLaser);
Q_INVOKABLE bool containsID(OverlayID overlayID) const;
private:
bool isRaised();
bool getPreferMalletsOverLasers() const;
bool isRaised() const;
void setRaised(bool raised);
bool isPassword();
bool isPassword() const;
void setPassword(bool password);
bool getUse3DKeyboard();
bool getUse3DKeyboard() const;
};
#endif

View file

@ -351,6 +351,12 @@ void Keyboard::raiseKeyboardAnchor(bool raise) const {
};
overlays.editOverlay(_textDisplay.overlayID, textDisplayProperties);
auto backPlateOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(_backPlate.overlayID));
if (backPlateOverlay) {
backPlateOverlay->setVisible(raise);
}
}
}
@ -382,6 +388,17 @@ void Keyboard::scaleKeyboard(float sensorToWorldScale) {
};
overlays.editOverlay(_textDisplay.overlayID, textDisplayProperties);
glm::vec3 backPlateScaledDimensions = _backPlate.dimensions * sensorToWorldScale;
glm::vec3 backPlateScaledLocalPosition = _backPlate.localPosition * sensorToWorldScale;
QVariantMap backPlateProperties {
{ "localPosition", vec3toVariant(backPlateScaledLocalPosition) },
{ "dimensions", vec3toVariant(backPlateScaledDimensions) }
};
overlays.editOverlay(_backPlate.overlayID, backPlateProperties);
}
void Keyboard::startLayerSwitchTimer() {
@ -391,7 +408,7 @@ void Keyboard::startLayerSwitchTimer() {
}
}
bool Keyboard::isLayerSwitchTimerFinished() {
bool Keyboard::isLayerSwitchTimerFinished() const {
if (_layerSwitchTimer) {
return (_layerSwitchTimer->remainingTime() <= 0);
}
@ -433,6 +450,16 @@ void Keyboard::setResetKeyboardPositionOnRaise(bool reset) {
_resetKeyboardPositionOnRaise = reset;
});
}
void Keyboard::setPreferMalletsOverLasers(bool preferMalletsOverLasers) {
_preferMalletsOverLasersSettingLock.withWriteLock([&] {
_preferMalletsOverLasers.set(preferMalletsOverLasers);
});
}
bool Keyboard::getPreferMalletsOverLasers() const {
return _preferMalletsOverLasersSettingLock.resultWithReadLock<bool>([&] {
return _preferMalletsOverLasers.get();
});
}
void Keyboard::switchToLayer(int layerIndex) {
@ -469,15 +496,21 @@ void Keyboard::switchToLayer(int layerIndex) {
}
}
bool Keyboard::shouldProcessOverlayAndPointerEvent(const PointerEvent& event, const OverlayID& overlayID) const {
return (shouldProcessPointerEvent(event) && shouldProcessOverlay(overlayID));
}
bool Keyboard::shouldProcessPointerEvent(const PointerEvent& event) const {
bool preferMalletsOverLasers = getPreferMalletsOverLasers();
unsigned int pointerID = event.getID();
bool isStylusEvent = (pointerID == _leftHandStylus || pointerID == _rightHandStylus);
bool isLaserEvent = (pointerID == _leftHandLaser || pointerID == _rightHandLaser);
return ((isStylusEvent && preferMalletsOverLasers) || (isLaserEvent && !preferMalletsOverLasers));
}
void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent& event) {
if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) {
return;
}
auto pointerID = event.getID();
auto buttonType = event.getButton();
if ((pointerID != _leftHandStylus && pointerID != _rightHandStylus) || buttonType != PointerEvent::PrimaryButton) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID) || buttonType != PointerEvent::PrimaryButton) {
return;
}
@ -491,8 +524,10 @@ void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent
Key& key = search.value();
if (key.timerFinished()) {
unsigned int pointerID = event.getID();
auto handIndex = (pointerID == _leftHandStylus || pointerID == _leftHandLaser)
? controller::Hand::LEFT : controller::Hand::RIGHT;
auto handIndex = (pointerID == _leftHandStylus) ? controller::Hand::LEFT : controller::Hand::RIGHT;
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->triggerHapticPulse(PULSE_STRENGTH, PULSE_DURATION, handIndex);
@ -560,19 +595,28 @@ void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent
QCoreApplication::postEvent(QCoreApplication::instance(), pressEvent);
QCoreApplication::postEvent(QCoreApplication::instance(), releaseEvent);
key.startTimer(KEY_PRESS_TIMEOUT_MS);
if (!getPreferMalletsOverLasers()) {
key.startTimer(KEY_PRESS_TIMEOUT_MS);
}
auto selection = DependencyManager::get<SelectionScriptingInterface>();
selection->addToSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "overlay", overlayID);
}
}
void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent& event) {
if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) {
return;
}
void Keyboard::setLeftHandLaser(unsigned int leftHandLaser) {
_handLaserLock.withWriteLock([&] {
_leftHandLaser = leftHandLaser;
});
}
auto pointerID = event.getID();
if (pointerID != _leftHandStylus && pointerID != _rightHandStylus) {
void Keyboard::setRightHandLaser(unsigned int rightHandLaser) {
_handLaserLock.withWriteLock([&] {
_rightHandLaser = rightHandLaser;
});
}
void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent& event) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
return;
}
@ -592,7 +636,7 @@ void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent&
}
key.setIsPressed(false);
if (key.timerFinished()) {
if (key.timerFinished() && getPreferMalletsOverLasers()) {
key.startTimer(KEY_PRESS_TIMEOUT_MS);
}
@ -601,13 +645,7 @@ void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent&
}
void Keyboard::handleTriggerContinue(const OverlayID& overlayID, const PointerEvent& event) {
if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) {
return;
}
auto pointerID = event.getID();
if (pointerID != _leftHandStylus && pointerID != _rightHandStylus) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
return;
}
@ -621,10 +659,11 @@ void Keyboard::handleTriggerContinue(const OverlayID& overlayID, const PointerEv
Key& key = search.value();
Overlays& overlays = qApp->getOverlays();
if (!key.isPressed()) {
if (!key.isPressed() && getPreferMalletsOverLasers()) {
auto base3DOverlay = std::dynamic_pointer_cast<Base3DOverlay>(overlays.getOverlay(overlayID));
if (base3DOverlay) {
unsigned int pointerID = event.getID();
auto pointerManager = DependencyManager::get<PointerManager>();
auto pickResult = pointerManager->getPrevPickResult(pointerID);
auto stylusPickResult = std::dynamic_pointer_cast<StylusPickResult>(pickResult);
@ -645,13 +684,7 @@ void Keyboard::handleTriggerContinue(const OverlayID& overlayID, const PointerEv
}
void Keyboard::handleHoverBegin(const OverlayID& overlayID, const PointerEvent& event) {
if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) {
return;
}
auto pointerID = event.getID();
if (pointerID != _leftHandStylus && pointerID != _rightHandStylus) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
return;
}
@ -667,13 +700,7 @@ void Keyboard::handleHoverBegin(const OverlayID& overlayID, const PointerEvent&
}
void Keyboard::handleHoverEnd(const OverlayID& overlayID, const PointerEvent& event) {
if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) {
return;
}
auto pointerID = event.getID();
if (pointerID != _leftHandStylus && pointerID != _rightHandStylus) {
if (!shouldProcessOverlayAndPointerEvent(event, overlayID)) {
return;
}
@ -765,6 +792,27 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
anchor.originalDimensions = dimensions;
_anchor = anchor;
QJsonObject backPlateObject = jsonObject["backPlate"].toObject();
QVariantMap backPlateProperties {
{ "name", "backPlate"},
{ "isSolid", true },
{ "visible", true },
{ "grabbable", false },
{ "alpha", 0.0 },
{ "ignoreRayIntersection", false},
{ "dimensions", backPlateObject["dimensions"].toVariant() },
{ "position", backPlateObject["position"].toVariant() },
{ "orientation", backPlateObject["rotation"].toVariant() },
{ "parentID", _anchor.overlayID }
};
BackPlate backPlate;
backPlate.overlayID = overlays.addOverlay("cube", backPlateProperties);
backPlate.dimensions = vec3FromVariant(backPlateObject["dimensions"].toVariant());
backPlate.localPosition = vec3FromVariant(overlays.getProperty(backPlate.overlayID, "localPosition").value);
_backPlate = backPlate;
const QJsonArray& keyboardLayers = jsonObject["layers"].toArray();
int keyboardLayerCount = keyboardLayers.size();
_keyboardLayers.reserve(keyboardLayerCount);
@ -871,12 +919,17 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
request->send();
}
OverlayID Keyboard::getAnchorID() {
return _ignoreItemsLock.resultWithReadLock<OverlayID>([&] {
return _anchor.overlayID;
});
}
bool Keyboard::shouldProcessOverlay(const OverlayID& overlayID) const {
return (!_keyboardLayers.empty() && isLayerSwitchTimerFinished() && overlayID != _backPlate.overlayID);
}
QVector<OverlayID> Keyboard::getKeysID() {
return _ignoreItemsLock.resultWithReadLock<QVector<OverlayID>>([&] {
return _itemsToIgnore;
@ -894,6 +947,7 @@ void Keyboard::clearKeyboardKeys() {
overlays.deleteOverlay(_anchor.overlayID);
overlays.deleteOverlay(_textDisplay.overlayID);
overlays.deleteOverlay(_backPlate.overlayID);
_keyboardLayers.clear();
@ -903,10 +957,38 @@ void Keyboard::clearKeyboardKeys() {
}
void Keyboard::enableStylus() {
if (getPreferMalletsOverLasers()) {
enableRightMallet();
enableLeftMallet();
}
}
void Keyboard::enableRightMallet() {
auto pointerManager = DependencyManager::get<PointerManager>();
pointerManager->setRenderState(_leftHandStylus, "events on");
pointerManager->enablePointer(_leftHandStylus);
pointerManager->setRenderState(_rightHandStylus, "events on");
pointerManager->enablePointer(_rightHandStylus);
}
void Keyboard::enableLeftMallet() {
auto pointerManager = DependencyManager::get<PointerManager>();
pointerManager->setRenderState(_leftHandStylus, "events on");
pointerManager->enablePointer(_leftHandStylus);
}
void Keyboard::disableLeftMallet() {
auto pointerManager = DependencyManager::get<PointerManager>();
pointerManager->setRenderState(_leftHandStylus, "events off");
pointerManager->disablePointer(_leftHandStylus);
}
void Keyboard::disableRightMallet() {
auto pointerManager = DependencyManager::get<PointerManager>();
pointerManager->setRenderState(_rightHandStylus, "events off");
pointerManager->disablePointer(_rightHandStylus);
}
bool Keyboard::containsID(OverlayID overlayID) const {
return resultWithReadLock<bool>([&] {
return _itemsToIgnore.contains(overlayID) || _backPlate.overlayID == overlayID;
});
}

View file

@ -87,7 +87,8 @@ private:
std::shared_ptr<QTimer> _timer { std::make_shared<QTimer>() };
};
class Keyboard : public Dependency, public QObject, public ReadWriteLockable {
class Keyboard : public QObject, public Dependency, public ReadWriteLockable {
Q_OBJECT
public:
Keyboard();
void createKeyboard();
@ -97,9 +98,20 @@ public:
void setResetKeyboardPositionOnRaise(bool reset);
bool isPassword() const;
void setPassword(bool password);
void enableRightMallet();
void enableLeftMallet();
void disableRightMallet();
void disableLeftMallet();
void setLeftHandLaser(unsigned int leftHandLaser);
void setRightHandLaser(unsigned int rightHandLaser);
void setPreferMalletsOverLasers(bool preferMalletsOverLasers);
bool getPreferMalletsOverLasers() const;
bool getUse3DKeyboard() const;
void setUse3DKeyboard(bool use);
bool containsID(OverlayID overlayID) const;
void loadKeyboardFile(const QString& keyboardFile);
QVector<OverlayID> getKeysID();
@ -119,6 +131,12 @@ private:
glm::vec3 originalDimensions;
};
struct BackPlate {
OverlayID overlayID;
glm::vec3 dimensions;
glm::vec3 localPosition;
};
struct TextDisplay {
float lineHeight;
OverlayID overlayID;
@ -128,35 +146,44 @@ private:
void raiseKeyboard(bool raise) const;
void raiseKeyboardAnchor(bool raise) const;
void setLayerIndex(int layerIndex);
void enableStylus();
void disableStylus();
void setLayerIndex(int layerIndex);
void clearKeyboardKeys();
void switchToLayer(int layerIndex);
void updateTextDisplay();
bool shouldProcessOverlayAndPointerEvent(const PointerEvent& event, const OverlayID& overlayID) const;
bool shouldProcessPointerEvent(const PointerEvent& event) const;
bool shouldProcessOverlay(const OverlayID& overlayID) const;
void startLayerSwitchTimer();
bool isLayerSwitchTimerFinished();
bool isLayerSwitchTimerFinished() const;
bool _raised { false };
bool _resetKeyboardPositionOnRaise { true };
bool _password { false };
bool _capsEnabled { false };
int _layerIndex { 0 };
Setting::Handle<bool> _preferMalletsOverLasers { "preferMalletsOverLaser", true };
unsigned int _leftHandStylus { 0 };
unsigned int _rightHandStylus { 0 };
unsigned int _leftHandLaser { 0 };
unsigned int _rightHandLaser { 0 };
SharedSoundPointer _keySound { nullptr };
std::shared_ptr<QTimer> _layerSwitchTimer { std::make_shared<QTimer>() };
mutable ReadWriteLockable _use3DKeyboardLock;
mutable ReadWriteLockable _handLaserLock;
mutable ReadWriteLockable _preferMalletsOverLasersSettingLock;
mutable ReadWriteLockable _ignoreItemsLock;
Setting::Handle<bool> _use3DKeyboard { "use3DKeyboard", true };
QString _typedCharacters;
TextDisplay _textDisplay;
Anchor _anchor;
BackPlate _backPlate;
mutable ReadWriteLockable _ignoreItemsLock;
QVector<OverlayID> _itemsToIgnore;
std::vector<QHash<OverlayID, Key>> _keyboardLayers;
};

View file

@ -107,12 +107,6 @@ void setupPreferences() {
preferences->addPreference(preference);
}
{
auto getter = []()->bool { return qApp->getPreferStylusOverLaser(); };
auto setter = [](bool value) { qApp->setPreferStylusOverLaser(value); };
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Stylus Over Laser", getter, setter));
}
{
static const QString RETICLE_ICON_NAME = { Cursor::Manager::getIconName(Cursor::Icon::RETICLE) };
auto getter = []()->bool { return qApp->getPreferredCursor() == RETICLE_ICON_NAME; };
@ -121,15 +115,38 @@ void setupPreferences() {
}
{
auto getter = []()->bool { return DependencyManager::get<Keyboard>()->getUse3DKeyboard(); };
auto setter = [](bool value) { DependencyManager::get<Keyboard>()->setUse3DKeyboard(value); };
auto getter = []()->bool { return qApp->getMiniTabletEnabled(); };
auto setter = [](bool value) { qApp->setMiniTabletEnabled(value); };
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use mini tablet", getter, setter));
}
{
auto getter = []()->int { return DependencyManager::get<Keyboard>()->getUse3DKeyboard(); };
auto setter = [](int value) { DependencyManager::get<Keyboard>()->setUse3DKeyboard(value); };
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use Virtual Keyboard", getter, setter));
}
{
auto getter = []()->bool { return qApp->getMiniTabletEnabled(); };
auto setter = [](bool value) { qApp->setMiniTabletEnabled(value); };
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use mini tablet", getter, setter));
auto getter = []()->bool { return DependencyManager::get<Keyboard>()->getPreferMalletsOverLasers() ? 1 : 0; };
auto setter = [](bool value) { return DependencyManager::get<Keyboard>()->setPreferMalletsOverLasers((bool)value); };
auto preference = new RadioButtonsPreference(UI_CATEGORY, "Keyboard laser / mallets", getter, setter);
QStringList items;
items << "Lasers" << "Mallets";
preference->setItems(items);
preference->setIndented(true);
preferences->addPreference(preference);
}
{
auto getter = []()->int { return qApp->getPreferStylusOverLaser() ? 1 : 0; };
auto setter = [](int value) { qApp->setPreferStylusOverLaser((bool)value); };
auto preference = new RadioButtonsPreference(UI_CATEGORY, "Tablet stylys / laser", getter, setter);
QStringList items;
items << "Lasers" << "Stylus";
preference->setHeading("Tablet Input Mechanism");
preference->setItems(items);
preferences->addPreference(preference);
}
static const QString VIEW_CATEGORY{ "View" };
@ -151,15 +168,14 @@ void setupPreferences() {
preferences->addPreference(preference);
}
// FIXME: Remove setting completely or make available through JavaScript API?
/*
// FIXME: Remove setting completely or make available through JavaScript API?
{
auto getter = []()->bool { return qApp->getPreferAvatarFingerOverStylus(); };
auto setter = [](bool value) { qApp->setPreferAvatarFingerOverStylus(value); };
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Avatar Finger Over Stylus", getter, setter));
}
*/
}*/
// Snapshots
static const QString SNAPSHOTS { "Snapshots" };
{

View file

@ -556,6 +556,7 @@ void ModelOverlay::locationChanged(bool tellPhysics) {
if (_model && _model->isActive()) {
_model->setRotation(getWorldOrientation());
_model->setTranslation(getWorldPosition());
_updateModel = true;
}
}

View file

@ -539,7 +539,7 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay
bool bestIsFront = false;
bool bestIsTablet = false;
auto tabletIDs = qApp->getTabletIDs();
const QVector<OverlayID> keyboardKeysToDiscard = DependencyManager::get<Keyboard>()->getKeysID();
QMutexLocker locker(&_mutex);
RayToOverlayIntersectionResult result;
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
@ -549,8 +549,7 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay
auto thisOverlay = std::dynamic_pointer_cast<Base3DOverlay>(i.value());
if ((overlaysToDiscard.size() > 0 && overlaysToDiscard.contains(thisID)) ||
(overlaysToInclude.size() > 0 && !overlaysToInclude.contains(thisID)) ||
(keyboardKeysToDiscard.size() > 0 && keyboardKeysToDiscard.contains(thisID))) {
(overlaysToInclude.size() > 0 && !overlaysToInclude.contains(thisID))) {
continue;
}

View file

@ -364,6 +364,7 @@ class RadioButtonsPreference : public IntPreference {
Q_OBJECT
Q_PROPERTY(QString heading READ getHeading CONSTANT)
Q_PROPERTY(QStringList items READ getItems CONSTANT)
Q_PROPERTY(bool indented READ getIndented CONSTANT)
public:
RadioButtonsPreference(const QString& category, const QString& name, Getter getter, Setter setter)
: IntPreference(category, name, getter, setter) { }
@ -373,10 +374,13 @@ public:
const QStringList& getItems() { return _items; }
void setHeading(const QString& heading) { _heading = heading; }
void setItems(const QStringList& items) { _items = items; }
bool getIndented() const { return _indented; }
void setIndented(const bool indented) { _indented = indented; }
protected:
QString _heading;
QStringList _items;
bool _indented { false };
};
#endif

View file

@ -12,7 +12,7 @@
LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES,
getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers,
PointerManager, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers,
PointerManager, print, Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE
PointerManager, print, Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE, Keyboard
*/
controllerDispatcherPlugins = {};
@ -463,6 +463,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
distanceScaleEnd: true,
hand: LEFT_HAND
});
Keyboard.setLeftHandLaser(this.leftPointer);
this.rightPointer = this.pointerManager.createPointer(false, PickType.Ray, {
joint: "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND",
filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE,
@ -473,6 +474,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
distanceScaleEnd: true,
hand: RIGHT_HAND
});
Keyboard.setRightHandLaser(this.rightPointer);
this.leftHudPointer = this.pointerManager.createPointer(true, PickType.Ray, {
joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
filter: Picks.PICK_HUD,

View file

@ -128,7 +128,7 @@ Script.include("/~/system/libraries/controllers.js");
}
}
var WEB_DISPLAY_STYLUS_DISTANCE = 0.5;
const WEB_DISPLAY_STYLUS_DISTANCE = (Keyboard.raised && Keyboard.preferMalletsOverLasers) ? 0.2 : 0.5;
var nearStylusTarget = isNearStylusTarget(stylusTargets, WEB_DISPLAY_STYLUS_DISTANCE * sensorScaleFactor);
if (nearStylusTarget.length !== 0) {
@ -152,9 +152,13 @@ Script.include("/~/system/libraries/controllers.js");
if (isUsingStylus && this.processStylus(controllerData)) {
Pointers.enablePointer(this.pointer);
this.hand === RIGHT_HAND ? Keyboard.disableRightMallet() : Keyboard.disableLeftMallet();
return makeRunningValues(true, [], []);
} else {
Pointers.disablePointer(this.pointer);
if (Keyboard.raised && Keyboard.preferMalletsOverLasers) {
this.hand === RIGHT_HAND ? Keyboard.enableRightMallet() : Keyboard.enableLeftMallet();
}
return makeRunningValues(false, [], []);
}
};

View file

@ -14,11 +14,21 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Script.include("/~/system/libraries/controllers.js");
(function() {
const intersectionType = {
None: 0,
WebOverlay: 1,
WebEntity: 2,
HifiKeyboard: 3,
Overlay: 4,
HifiTablet: 5,
};
function WebSurfaceLaserInput(hand) {
this.hand = hand;
this.otherHand = this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND;
this.running = false;
this.ignoredObjects = [];
this.intersectedType = intersectionType["None"];
this.parameters = makeDispatcherModuleParameters(
160,
@ -115,7 +125,7 @@ Script.include("/~/system/libraries/controllers.js");
this.ignoredObjects = [];
};
this.isPointingAtTriggerable = function(controllerData, triggerPressed, checkEntitiesOnly) {
this.getInteractableType = function(controllerData, triggerPressed, checkEntitiesOnly) {
// allow pointing at tablet, unlocked web entities, or web overlays automatically without pressing trigger,
// but for pointing at locked web entities or non-web overlays user must be pressing trigger
var intersection = controllerData.rayPicks[this.hand];
@ -124,18 +134,29 @@ Script.include("/~/system/libraries/controllers.js");
if ((HMD.tabletID && objectID === HMD.tabletID) ||
(HMD.tabletScreenID && objectID === HMD.tabletScreenID) ||
(HMD.homeButtonID && objectID === HMD.homeButtonID)) {
return true;
return intersectionType["HifiTablet"];
} else {
var overlayType = Overlays.getOverlayType(objectID);
return overlayType === "web3d" || triggerPressed;
var type = intersectionType["None"];
if (Keyboard.containsID(objectID) && !Keyboard.preferMalletsOverLasers) {
type = intersectionType["HifiKeyboard"];
} else if (overlayType === "web3d") {
type = intersectionType["WebOverlay"];
} else if (triggerPressed) {
type = intersectionType["Overlay"];
}
return type;
}
} else if (intersection.type === Picks.INTERSECTED_ENTITY) {
var entityProperties = Entities.getEntityProperties(objectID, DISPATCHER_PROPERTIES);
var entityType = entityProperties.type;
var isLocked = entityProperties.locked;
return entityType === "Web" && (!isLocked || triggerPressed);
if (entityType === "Web" && (!isLocked || triggerPressed)) {
return intersectionType["WebEntity"];
}
}
return false;
return intersectionType["None"];
};
this.deleteContextOverlay = function() {
@ -152,9 +173,9 @@ Script.include("/~/system/libraries/controllers.js");
}
};
this.updateAllwaysOn = function() {
this.updateAlwaysOn = function(type) {
var PREFER_STYLUS_OVER_LASER = "preferStylusOverLaser";
this.parameters.handLaser.allwaysOn = !Settings.getValue(PREFER_STYLUS_OVER_LASER, false);
this.parameters.handLaser.alwaysOn = (!Settings.getValue(PREFER_STYLUS_OVER_LASER, false) || type === intersectionType["HifiKeyboard"]);
};
this.getDominantHand = function() {
@ -164,19 +185,28 @@ Script.include("/~/system/libraries/controllers.js");
this.dominantHandOverride = false;
this.isReady = function(controllerData) {
var otherModuleRunning = this.getOtherModule().running;
otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand.
var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE &&
controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE;
var allowThisModule = !otherModuleRunning || isTriggerPressed;
var type = this.getInteractableType(controllerData, isTriggerPressed, false);
if ((allowThisModule && this.isPointingAtTriggerable(controllerData, isTriggerPressed, false)) && !this.grabModuleWantsNearbyOverlay(controllerData)) {
this.updateAllwaysOn();
if (isTriggerPressed) {
this.dominantHandOverride = true; // Override dominant hand.
this.getOtherModule().dominantHandOverride = false;
if (type !== intersectionType["None"] && !this.grabModuleWantsNearbyOverlay(controllerData)) {
if (type === intersectionType["WebOverlay"] || type === intersectionType["WebEntity"] || type === intersectionType["HifiTablet"]) {
var otherModuleRunning = this.getOtherModule().running;
otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand.
var allowThisModule = !otherModuleRunning || isTriggerPressed;
if (!allowThisModule) {
return makeRunningValues(true, [], []);
}
if (isTriggerPressed) {
this.dominantHandOverride = true; // Override dominant hand.
this.getOtherModule().dominantHandOverride = false;
}
}
if (this.parameters.handLaser.allwaysOn || isTriggerPressed) {
this.updateAlwaysOn(type);
if (this.parameters.handLaser.alwaysOn || isTriggerPressed) {
return makeRunningValues(true, [], []);
}
}
@ -187,33 +217,37 @@ Script.include("/~/system/libraries/controllers.js");
return makeRunningValues(false, [], []);
};
this.run = function(controllerData, deltaTime) {
this.shouldThisModuleRun = function(controllerData) {
var otherModuleRunning = this.getOtherModule().running;
otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand.
otherModuleRunning = otherModuleRunning || this.getOtherModule().dominantHandOverride; // Override dominant hand.
var grabModuleNeedsToRun = this.grabModuleWantsNearbyOverlay(controllerData);
// only allow for non-near grab
var allowThisModule = !otherModuleRunning && !grabModuleNeedsToRun;
var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE;
var laserOn = isTriggerPressed || this.parameters.handLaser.allwaysOn;
return !otherModuleRunning && !grabModuleNeedsToRun;
};
this.run = function(controllerData, deltaTime) {
this.addObjectToIgnoreList(controllerData);
if (allowThisModule) {
if (isTriggerPressed && !this.isPointingAtTriggerable(controllerData, isTriggerPressed, true)) {
// if trigger is down + not pointing at a web entity, keep running web surface laser
var type = this.getInteractableType(controllerData, isTriggerPressed, false);
var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE;
var laserOn = isTriggerPressed || this.parameters.handLaser.alwaysOn;
this.addObjectToIgnoreList(controllerData);
if (type === intersectionType["HifiTablet"] && laserOn) {
if (this.shouldThisModuleRun(controllerData)) {
this.running = true;
return makeRunningValues(true, [], []);
} else if (laserOn && this.isPointingAtTriggerable(controllerData, isTriggerPressed, false)) {
// if trigger is down + pointing at a web entity/overlay, keep running web surface laser
this.running = true;
return makeRunningValues(true, [], []);
} else {
this.deleteContextOverlay();
this.running = false;
this.dominantHandOverride = false;
return makeRunningValues(false, [], []);
}
} else if ((type === intersectionType["WebOverlay"] || type === intersectionType["WebEntity"]) && laserOn) { // auto laser on WebEntities andWebOverlays
if (this.shouldThisModuleRun(controllerData)) {
this.running = true;
return makeRunningValues(true, [], []);
}
} else if ((type === intersectionType["HifiKeyboard"] && laserOn) || type === intersectionType["Overlay"]) {
this.running = true;
return makeRunningValues(true, [], []);
}
// if module needs to stop from near grabs or other modules are running, stop it.
this.deleteContextOverlay();
this.running = false;
this.dominantHandOverride = false;

View file

@ -181,14 +181,14 @@ makeLaserLockInfo = function(targetID, isOverlay, hand, offset) {
};
};
makeLaserParams = function(hand, allwaysOn) {
if (allwaysOn === undefined) {
allwaysOn = false;
makeLaserParams = function(hand, alwaysOn) {
if (alwaysOn === undefined) {
alwaysOn = false;
}
return {
hand: hand,
allwaysOn: allwaysOn
alwaysOn: alwaysOn
};
};

View file

@ -145,7 +145,7 @@ Pointer = function(hudLayer, pickType, pointerData) {
mode = "hold";
} else if (triggerClicks[this.hand]) {
mode = "full";
} else if (triggerValues[this.hand] > TRIGGER_ON_VALUE || this.allwaysOn) {
} else if (triggerValues[this.hand] > TRIGGER_ON_VALUE || this.alwaysOn) {
mode = "half";
}
}
@ -171,7 +171,7 @@ PointerManager = function() {
var index = laserParams.hand;
if (index < this.pointers.length && index >= 0) {
this.pointers[index].makeVisible();
this.pointers[index].allwaysOn = laserParams.allwaysOn;
this.pointers[index].alwaysOn = laserParams.alwaysOn;
}
};