From 51bdf1bf78682b4f78d79fcedae71fd713f34316 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 10 Dec 2018 15:07:08 -0800 Subject: [PATCH] adding keyboards settings --- interface/resources/config/keyboard.json | 18 ++ .../qml/dialogs/PreferencesDialog.qml | 37 +++++ .../preferences/CheckBoxPreference.qml | 4 +- .../preferences/RadioButtonsPreference.qml | 27 +-- .../tabletWindows/TabletPreferencesDialog.qml | 9 + interface/resources/sounds/keySound.mp3 | Bin 0 -> 11493 bytes .../scripting/KeyboardScriptingInterface.cpp | 39 ++++- .../scripting/KeyboardScriptingInterface.h | 21 ++- interface/src/ui/Keyboard.cpp | 156 ++++++++++++++---- interface/src/ui/Keyboard.h | 34 +++- interface/src/ui/PreferencesDialog.cpp | 46 ++++-- interface/src/ui/overlays/ModelOverlay.cpp | 1 + interface/src/ui/overlays/Overlays.cpp | 5 +- libraries/shared/src/Preferences.h | 4 + .../controllers/controllerDispatcher.js | 5 +- .../controllerModules/stylusInput.js | 6 +- .../controllerModules/webSurfaceLaserInput.js | 99 +++++++---- 17 files changed, 409 insertions(+), 102 deletions(-) create mode 100644 interface/resources/sounds/keySound.mp3 diff --git a/interface/resources/config/keyboard.json b/interface/resources/config/keyboard.json index b3688ef06e..e16c6156ab 100644 --- a/interface/resources/config/keyboard.json +++ b/interface/resources/config/keyboard.json @@ -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, diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index 9df1d0b963..63fde5ec64 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -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; + } } diff --git a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml index f6f840bbe8..0791a491ff 100644 --- a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml @@ -16,9 +16,10 @@ import controlsUit 1.0 Preference { id: root height: spacer.height + Math.max(hifi.dimensions.controlLineHeight, checkBox.implicitHeight) - + property bool value: false Component.onCompleted: { checkBox.checked = preference.value; + value = checkBox.checked; preference.value = Qt.binding(function(){ return checkBox.checked; }); } @@ -47,6 +48,7 @@ Preference { onClicked: { Tablet.playSound(TabletEnums.ButtonClick); + value = checked; } anchors { diff --git a/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml b/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml index 0a09d8d609..1e7d92a138 100644 --- a/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml +++ b/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml @@ -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 diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml index a5d7b23df6..d526c9a3cd 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml @@ -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) { diff --git a/interface/resources/sounds/keySound.mp3 b/interface/resources/sounds/keySound.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..87c7b008079690d2c6faa91ba85caecf549c2851 GIT binary patch literal 11493 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 literal 0 HcmV?d00001 diff --git a/interface/src/scripting/KeyboardScriptingInterface.cpp b/interface/src/scripting/KeyboardScriptingInterface.cpp index d86bb56e64..ccf123efed 100644 --- a/interface/src/scripting/KeyboardScriptingInterface.cpp +++ b/interface/src/scripting/KeyboardScriptingInterface.cpp @@ -12,7 +12,7 @@ #include "KeyboardScriptingInterface.h" #include "ui/Keyboard.h" -bool KeyboardScriptingInterface::isRaised() { +bool KeyboardScriptingInterface::isRaised() const { return DependencyManager::get()->isRaised(); } @@ -20,8 +20,7 @@ void KeyboardScriptingInterface::setRaised(bool raised) { DependencyManager::get()->setRaised(raised); } - -bool KeyboardScriptingInterface::isPassword() { +bool KeyboardScriptingInterface::isPassword() const { return DependencyManager::get()->isPassword(); } @@ -33,6 +32,38 @@ void KeyboardScriptingInterface::loadKeyboardFile(const QString& keyboardFile) { DependencyManager::get()->loadKeyboardFile(keyboardFile); } -bool KeyboardScriptingInterface::getUse3DKeyboard() { +bool KeyboardScriptingInterface::getUse3DKeyboard() const { return DependencyManager::get()->getUse3DKeyboard(); } + +void KeyboardScriptingInterface::disableRightMallet() { + DependencyManager::get()->disableRightMallet(); +} + +void KeyboardScriptingInterface::disableLeftMallet() { + DependencyManager::get()->disableLeftMallet(); +} + +void KeyboardScriptingInterface::enableRightMallet() { + DependencyManager::get()->enableRightMallet(); +} + +void KeyboardScriptingInterface::enableLeftMallet() { + DependencyManager::get()->enableLeftMallet(); +} + +void KeyboardScriptingInterface::setLeftHandLaser(unsigned int leftHandLaser) { + DependencyManager::get()->setLeftHandLaser(leftHandLaser); +} + +void KeyboardScriptingInterface::setRightHandLaser(unsigned int rightHandLaser) { + DependencyManager::get()->setRightHandLaser(rightHandLaser); +} + +bool KeyboardScriptingInterface::getPreferMalletsOverLasers() const { + return DependencyManager::get()->getPreferMalletsOverLasers(); +} + +bool KeyboardScriptingInterface::containsID(OverlayID overlayID) const { + return DependencyManager::get()->containsID(overlayID); +} diff --git a/interface/src/scripting/KeyboardScriptingInterface.h b/interface/src/scripting/KeyboardScriptingInterface.h index 709dfe01de..52d9e821bb 100644 --- a/interface/src/scripting/KeyboardScriptingInterface.h +++ b/interface/src/scripting/KeyboardScriptingInterface.h @@ -15,6 +15,7 @@ #include #include "DependencyManager.h" +#include "ui/overlays/Overlay.h" /**jsdoc * The Keyboard API provides facilities to use 3D Physical keyboard. @@ -26,21 +27,33 @@ * @property {bool} raised - true If the keyboard is visible false otherwise * @property {bool} password - true Will show * instead of characters in the text display false 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 diff --git a/interface/src/ui/Keyboard.cpp b/interface/src/ui/Keyboard.cpp index d647851a80..40894f1121 100644 --- a/interface/src/ui/Keyboard.cpp +++ b/interface/src/ui/Keyboard.cpp @@ -349,6 +349,12 @@ void Keyboard::raiseKeyboardAnchor(bool raise) const { }; overlays.editOverlay(_textDisplay.overlayID, textDisplayProperties); + + auto backPlateOverlay = std::dynamic_pointer_cast(overlays.getOverlay(_backPlate.overlayID)); + + if (backPlateOverlay) { + backPlateOverlay->setVisible(raise); + } } } @@ -380,6 +386,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() { @@ -425,6 +442,18 @@ void Keyboard::setPassword(bool password) { updateTextDisplay(); } +void Keyboard::setPreferMalletsOverLasers(bool preferMalletsOverLasers) { + _preferMalletsOverLasersSettingLock.withWriteLock([&] { + _preferMalletsOverLasers.set(preferMalletsOverLasers); + }); +} + +bool Keyboard::getPreferMalletsOverLasers() const { + return _preferMalletsOverLasersSettingLock.resultWithReadLock([&] { + return _preferMalletsOverLasers.get(); + }); +} + void Keyboard::switchToLayer(int layerIndex) { if (layerIndex >= 0 && layerIndex < (int)_keyboardLayers.size()) { Overlays& overlays = qApp->getOverlays(); @@ -459,15 +488,22 @@ void Keyboard::switchToLayer(int layerIndex) { } } +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); + qDebug() << isLaserEvent; + return ((isStylusEvent && preferMalletsOverLasers) || (isLaserEvent && !preferMalletsOverLasers)); +} + void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent& event) { - if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) { + if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished() || overlayID == _backPlate.overlayID) { return; } - auto pointerID = event.getID(); auto buttonType = event.getButton(); - - if ((pointerID != _leftHandStylus && pointerID != _rightHandStylus) || buttonType != PointerEvent::PrimaryButton) { + if (!shouldProcessPointerEvent(event) || buttonType != PointerEvent::PrimaryButton) { return; } @@ -481,8 +517,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->triggerHapticPulse(PULSE_STRENGTH, PULSE_DURATION, handIndex); @@ -550,19 +588,32 @@ 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(); selection->addToSelectedItemsList(KEY_PRESSED_HIGHLIGHT, "overlay", overlayID); } } +void Keyboard::setLeftHandLaser(unsigned int leftHandLaser) { + _handLaserLock.withWriteLock([&] { + _leftHandLaser = leftHandLaser; + }); +} + +void Keyboard::setRightHandLaser(unsigned int rightHandLaser) { + _handLaserLock.withWriteLock([&] { + _rightHandLaser = rightHandLaser; + }); +} + void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent& event) { - if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) { + if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished() || overlayID == _backPlate.overlayID) { return; } - auto pointerID = event.getID(); - if (pointerID != _leftHandStylus && pointerID != _rightHandStylus) { + if (!shouldProcessPointerEvent(event)) { return; } @@ -582,7 +633,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); } @@ -591,13 +642,11 @@ void Keyboard::handleTriggerEnd(const OverlayID& overlayID, const PointerEvent& } void Keyboard::handleTriggerContinue(const OverlayID& overlayID, const PointerEvent& event) { - if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) { + if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished() || overlayID == _backPlate.overlayID) { return; } - auto pointerID = event.getID(); - - if (pointerID != _leftHandStylus && pointerID != _rightHandStylus) { + if (!shouldProcessPointerEvent(event)) { return; } @@ -611,10 +660,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(overlays.getOverlay(overlayID)); if (base3DOverlay) { + unsigned int pointerID = event.getID(); auto pointerManager = DependencyManager::get(); auto pickResult = pointerManager->getPrevPickResult(pointerID); auto stylusPickResult = std::dynamic_pointer_cast(pickResult); @@ -635,13 +685,11 @@ void Keyboard::handleTriggerContinue(const OverlayID& overlayID, const PointerEv } void Keyboard::handleHoverBegin(const OverlayID& overlayID, const PointerEvent& event) { - if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) { + if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished() || overlayID == _backPlate.overlayID) { return; } - auto pointerID = event.getID(); - - if (pointerID != _leftHandStylus && pointerID != _rightHandStylus) { + if (!shouldProcessPointerEvent(event)) { return; } @@ -657,13 +705,11 @@ void Keyboard::handleHoverBegin(const OverlayID& overlayID, const PointerEvent& } void Keyboard::handleHoverEnd(const OverlayID& overlayID, const PointerEvent& event) { - if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished()) { + if (_keyboardLayers.empty() || !isLayerSwitchTimerFinished() || overlayID == _backPlate.overlayID) { return; } - auto pointerID = event.getID(); - - if (pointerID != _leftHandStylus && pointerID != _rightHandStylus) { + if (!shouldProcessPointerEvent(event)) { return; } @@ -755,6 +801,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); @@ -878,6 +945,7 @@ void Keyboard::clearKeyboardKeys() { overlays.deleteOverlay(_anchor.overlayID); overlays.deleteOverlay(_textDisplay.overlayID); + overlays.deleteOverlay(_backPlate.overlayID); _keyboardLayers.clear(); @@ -887,10 +955,42 @@ void Keyboard::clearKeyboardKeys() { } void Keyboard::enableStylus() { - auto pointerManager = DependencyManager::get(); - pointerManager->setRenderState(_leftHandStylus, "events on"); - pointerManager->enablePointer(_leftHandStylus); - pointerManager->setRenderState(_rightHandStylus, "events on"); - pointerManager->enablePointer(_rightHandStylus); + if (getPreferMalletsOverLasers()) { + auto pointerManager = DependencyManager::get(); + pointerManager->setRenderState(_leftHandStylus, "events on"); + pointerManager->enablePointer(_leftHandStylus); + pointerManager->setRenderState(_rightHandStylus, "events on"); + pointerManager->enablePointer(_rightHandStylus); + } } + +void Keyboard::enableRightMallet() { + auto pointerManager = DependencyManager::get(); + pointerManager->setRenderState(_rightHandStylus, "events on"); + pointerManager->enablePointer(_rightHandStylus); +} + +void Keyboard::enableLeftMallet() { + auto pointerManager = DependencyManager::get(); + pointerManager->setRenderState(_leftHandStylus, "events on"); + pointerManager->enablePointer(_leftHandStylus); +} + +void Keyboard::disableLeftMallet() { + auto pointerManager = DependencyManager::get(); + pointerManager->setRenderState(_leftHandStylus, "events off"); + pointerManager->disablePointer(_leftHandStylus); +} + +void Keyboard::disableRightMallet() { + auto pointerManager = DependencyManager::get(); + pointerManager->setRenderState(_rightHandStylus, "events off"); + pointerManager->disablePointer(_rightHandStylus); +} + +bool Keyboard::containsID(OverlayID overlayID) const { + return resultWithReadLock([&] { + return _itemsToIgnore.contains(overlayID) || _backPlate.overlayID == overlayID; + }); +} diff --git a/interface/src/ui/Keyboard.h b/interface/src/ui/Keyboard.h index 9c0c8c40f2..b917b60eb4 100644 --- a/interface/src/ui/Keyboard.h +++ b/interface/src/ui/Keyboard.h @@ -87,7 +87,8 @@ private: std::shared_ptr _timer { std::make_shared() }; }; -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: 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 getKeysID(); @@ -118,6 +130,12 @@ private: glm::vec3 originalDimensions; }; + struct BackPlate { + OverlayID overlayID; + glm::vec3 dimensions; + glm::vec3 localPosition; + }; + struct TextDisplay { float lineHeight; OverlayID overlayID; @@ -127,10 +145,10 @@ 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(); @@ -138,23 +156,31 @@ private: void startLayerSwitchTimer(); bool isLayerSwitchTimerFinished(); + bool shouldProcessPointerEvent(const PointerEvent& event) const; + bool _raised { false }; bool _password { false }; bool _capsEnabled { false }; int _layerIndex { 0 }; + Setting::Handle _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 _layerSwitchTimer { std::make_shared() }; mutable ReadWriteLockable _use3DKeyboardLock; + mutable ReadWriteLockable _handLaserLock; + mutable ReadWriteLockable _preferMalletsOverLasersSettingLock; + mutable ReadWriteLockable _ignoreItemsLock; Setting::Handle _use3DKeyboard { "use3DKeyboard", true }; QString _typedCharacters; TextDisplay _textDisplay; Anchor _anchor; + BackPlate _backPlate; - mutable ReadWriteLockable _ignoreItemsLock; QVector _itemsToIgnore; std::vector> _keyboardLayers; }; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index d1fbe02759..5bb1945c64 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -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()->getUse3DKeyboard(); }; - auto setter = [](bool value) { DependencyManager::get()->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()->getUse3DKeyboard(); }; + auto setter = [](int value) { DependencyManager::get()->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()->getPreferMalletsOverLasers() ? 1 : 0; }; + auto setter = [](bool value) { return DependencyManager::get()->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" }; { diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 19bdfce2b3..805832760e 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -556,6 +556,7 @@ void ModelOverlay::locationChanged(bool tellPhysics) { if (_model && _model->isActive()) { _model->setRotation(getWorldOrientation()); _model->setTranslation(getWorldPosition()); + _updateModel = true; } } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 17b0895f47..754c8d26a9 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -539,7 +539,7 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay bool bestIsFront = false; bool bestIsTablet = false; auto tabletIDs = qApp->getTabletIDs(); - const QVector keyboardKeysToDiscard = DependencyManager::get()->getKeysID(); + QMutexLocker locker(&_mutex); RayToOverlayIntersectionResult result; QMapIterator i(_overlaysWorld); @@ -549,8 +549,7 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay auto thisOverlay = std::dynamic_pointer_cast(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; } diff --git a/libraries/shared/src/Preferences.h b/libraries/shared/src/Preferences.h index 4a58d71c54..0fec8708e8 100644 --- a/libraries/shared/src/Preferences.h +++ b/libraries/shared/src/Preferences.h @@ -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() { return _indented; } + void setIndented(const bool indented) { _indented = indented; } protected: QString _heading; QStringList _items; + bool _indented { false }; }; #endif diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 2658f11989..a579fee0d9 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -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 = {}; @@ -453,6 +453,8 @@ 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, @@ -463,6 +465,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, diff --git a/scripts/system/controllers/controllerModules/stylusInput.js b/scripts/system/controllers/controllerModules/stylusInput.js index 57066fb2dd..c4aa9efd50 100644 --- a/scripts/system/controllers/controllerModules/stylusInput.js +++ b/scripts/system/controllers/controllerModules/stylusInput.js @@ -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, [], []); } }; diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index d2cb7fffd1..c1b0658af2 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -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, @@ -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.allwaysOn = (!Settings.getValue(PREFER_STYLUS_OVER_LASER, false) || type === intersectionType["HifiKeyboard"]); }; this.getDominantHand = function() { @@ -164,18 +185,27 @@ 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; + controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE; + var type = this.isPointingAtTriggerable(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; + } } + + this.updateAlwaysOn(type); if (this.parameters.handLaser.allwaysOn || isTriggerPressed) { return makeRunningValues(true, [], []); } @@ -187,33 +217,42 @@ 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; + return !otherModuleRunning && !grabModuleNeedsToRun; + }; + + this.run = function(controllerData, deltaTime) { + this.addObjectToIgnoreList(controllerData); + var type = this.isPointingAtTriggerable(controllerData, isTriggerPressed, false); var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE; var laserOn = isTriggerPressed || this.parameters.handLaser.allwaysOn; 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 + + 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, [], []); + } else if (isTriggerPressed && !this.isPointingAtTriggerable(controllerData, isTriggerPressed, true)) { + // if trigger is down + not pointing at a web entity, keep running web surface laser + 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;