From c2aa9e7f61f71fd3fd53acf3f9ecdec94d34ce06 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 6 Jun 2016 15:14:10 -0700 Subject: [PATCH] Update SteamVR keyboard behavior --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 27 +------ plugins/openvr/src/OpenVrHelpers.cpp | 85 ++++++++++++++++++++ plugins/openvr/src/OpenVrHelpers.h | 3 + plugins/openvr/src/ViveControllerManager.cpp | 37 +-------- 4 files changed, 95 insertions(+), 57 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index fa9cb62b7c..14518ac37a 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -751,30 +751,9 @@ void OffscreenQmlSurface::onFocusObjectChanged(QObject* object) { return; } - QVariant result; -#if 1 - auto invokeResult = QMetaObject::invokeMethod(object, "inputMethodQuery", Q_RETURN_ARG(QVariant, result), - Q_ARG(Qt::InputMethodQuery, Qt::ImEnabled), - Q_ARG(QVariant, QVariant())); -#else - - //static const char* INPUT_METHOD_QUERY_METHOD_NAME = "inputMethodQuery(Qt::InputMethodQuery, QVariant)"; - static const char* INPUT_METHOD_QUERY_METHOD_NAME = "inputMethodQuery"; - auto meta = object->metaObject(); - qDebug() << "new focus " << object; - auto index = meta->indexOfMethod(INPUT_METHOD_QUERY_METHOD_NAME); - if (index < 0 || index >= meta->methodCount()) { - setFocusText(false); - return; - } - - auto method = meta->method(index); - auto invokeResult = method.invoke(object, - Q_RETURN_ARG(QVariant, result), - Q_ARG(Qt::InputMethodQuery, Qt::ImEnabled), - Q_ARG(QVariant, QVariant())); -#endif - setFocusText(invokeResult && result.toBool()); + QInputMethodQueryEvent query(Qt::ImEnabled); + qApp->sendEvent(object, &query); + setFocusText(query.value(Qt::ImEnabled).toBool()); } void OffscreenQmlSurface::setFocusText(bool newFocusText) { diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index 155bc9f079..b13a60d388 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -14,9 +14,13 @@ #include #include #include +#include +#include #include +#include + Q_DECLARE_LOGGING_CATEGORY(displayplugins) Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display") @@ -90,6 +94,82 @@ void releaseOpenVrSystem() { } } +static char textArray[8192]; + +static QMetaObject::Connection _focusConnection, _focusTextConnection; +extern bool _openVrDisplayActive; +static vr::IVROverlay* _overlay { nullptr }; +static QObject* _focusObject { nullptr }; +static QString _existingText; +static Qt::InputMethodHints _currentHints; + +void showOpenVrKeyboard(bool show = true) { + if (_overlay) { + if (show) { + auto offscreenUi = DependencyManager::get(); + _focusObject = offscreenUi->getWindow()->focusObject(); + + QInputMethodQueryEvent query(Qt::ImQueryInput | Qt::ImHints); + qApp->sendEvent(_focusObject, &query); + _currentHints = Qt::InputMethodHints(query.value(Qt::ImHints).toUInt()); + vr::EGamepadTextInputMode inputMode = vr::k_EGamepadTextInputModeNormal; + if (_currentHints & Qt::ImhHiddenText) { + inputMode = vr::k_EGamepadTextInputModePassword; + } + vr::EGamepadTextInputLineMode lineMode = vr::k_EGamepadTextInputLineModeSingleLine; + if (_currentHints & Qt::ImhMultiLine) { + lineMode = vr::k_EGamepadTextInputLineModeMultipleLines; + } + _existingText = query.value(Qt::ImSurroundingText).toString(); + _overlay->ShowKeyboard(inputMode, lineMode, "Keyboard", 1024, _existingText.toLocal8Bit().toStdString().c_str(), false, (uint64_t)(void*)_focusObject); + } else { + _focusObject = nullptr; + _overlay->HideKeyboard(); + } + } +} + +void finishOpenVrKeyboardInput() { + auto offscreenUi = DependencyManager::get(); + auto chars = _overlay->GetKeyboardText(textArray, 8192); + auto newText = QString(QByteArray(textArray, chars)); + // TODO modify the new text to match the possible input hints: + // ImhDigitsOnly ImhFormattedNumbersOnly ImhUppercaseOnly ImhLowercaseOnly + // ImhDialableCharactersOnly ImhEmailCharactersOnly ImhUrlCharactersOnly ImhLatinOnly + QInputMethodEvent event(_existingText, QList()); + event.setCommitString(newText, 0, _existingText.size()); + qApp->sendEvent(_focusObject, &event); + // Simulate an enter press on the top level window to trigger the action + if (0 == (_currentHints & Qt::ImhMultiLine)) { + qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n"))); + qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers())); + } +} + +void enableOpenVrKeyboard() { + auto offscreenUi = DependencyManager::get(); + _overlay = vr::VROverlay(); + + _focusConnection = QObject::connect(offscreenUi->getWindow(), &QQuickWindow::focusObjectChanged, [](QObject* object) { + if (object != _focusObject && _overlay) { + showOpenVrKeyboard(false); + } + }); + + _focusTextConnection = QObject::connect(offscreenUi.data(), &OffscreenUi::focusTextChanged, [](bool focusText) { + if (_openVrDisplayActive) { + showOpenVrKeyboard(focusText); + } + }); +} + + +void disableOpenVrKeyboard() { + QObject::disconnect(_focusTextConnection); + QObject::disconnect(_focusConnection); +} + + void handleOpenVrEvents() { if (!activeHmd) { return; @@ -107,6 +187,10 @@ void handleOpenVrEvents() { activeHmd->AcknowledgeQuit_Exiting(); break; + case vr::VREvent_KeyboardDone: + finishOpenVrKeyboardInput(); + break; + default: break; } @@ -114,3 +198,4 @@ void handleOpenVrEvents() { } } + diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h index 1e5914844c..41e7dcb27d 100644 --- a/plugins/openvr/src/OpenVrHelpers.h +++ b/plugins/openvr/src/OpenVrHelpers.h @@ -18,6 +18,9 @@ vr::IVRSystem* acquireOpenVrSystem(); void releaseOpenVrSystem(); void handleOpenVrEvents(); bool openVrQuitRequested(); +void enableOpenVrKeyboard(); +void disableOpenVrKeyboard(); + template void openvr_for_each_eye(F f) { diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 8d6c661ae6..6d3ce46e82 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -11,9 +11,6 @@ #include "ViveControllerManager.h" -#include -#include - #include #include #include @@ -57,9 +54,6 @@ bool ViveControllerManager::isSupported() const { return openVrSupported(); } -QMetaObject::Connection _focusConnection; -extern bool _openVrDisplayActive; - bool ViveControllerManager::activate() { InputPlugin::activate(); @@ -72,20 +66,9 @@ bool ViveControllerManager::activate() { _system = acquireOpenVrSystem(); } Q_ASSERT(_system); - auto offscreenUi = DependencyManager::get(); - _focusConnection = connect(offscreenUi.data(), &OffscreenUi::focusTextChanged, [this](bool focusText) { - if (_openVrDisplayActive) { - auto overlay = vr::VROverlay(); - if (overlay) { - if (focusText) { - //virtual EVROverlayError ShowKeyboard( eInputMode, EGamepadTextInputLineMode eLineInputMode, const char *pchDescription, uint32_t unCharMax, const char *pchExistingText, bool bUseMinimalMode, uint64_t uUserValue) = 0; - overlay->ShowKeyboard(vr::EGamepadTextInputMode::k_EGamepadTextInputModeNormal, vr::k_EGamepadTextInputLineModeSingleLine, "Test", 1024, "", false, 0); - } else { - overlay->HideKeyboard(); - } - } - } - }); + + enableOpenVrKeyboard(); + // OpenVR provides 3d mesh representations of the controllers // Disabled controller rendering code /* @@ -150,7 +133,7 @@ bool ViveControllerManager::activate() { void ViveControllerManager::deactivate() { InputPlugin::deactivate(); - disconnect(_focusConnection); + disableOpenVrKeyboard(); _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS); _container->removeMenu(MENU_PATH); @@ -240,18 +223,6 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu return; } - vr::VREvent_t vrEvent; - static char textArray[8192]; - while (vr::VRSystem()->PollNextEvent(&vrEvent, sizeof(vrEvent))) { - if (vrEvent.eventType == vr::VREvent_KeyboardDone) { - auto chars = vr::VROverlay()->GetKeyboardText(textArray, 8192); - QInputMethodEvent* event = new QInputMethodEvent(); - event->setCommitString(QString(QByteArray(textArray, chars)), 0, 0); - auto focusObject = DependencyManager::get()->getWindow()->focusObject(); - qApp->postEvent(focusObject, event); - } - } - // because update mutates the internal state we need to lock userInputMapper->withLock([&, this]() { _inputDevice->update(deltaTime, inputCalibrationData);