From 760d262a570ff22ff730c662a94248c1b145eefc Mon Sep 17 00:00:00 2001 From: Vasily Date: Wed, 20 Mar 2019 20:14:24 +0100 Subject: [PATCH] Add page to change desktop overlay translation The implementation is simple 3D vector scaling and addition. The HmdMatrix34_t consists of a 3x3 rotation matrix and a 3D vector for position. The overlay position is only updated whenever a new overlay is changed because we need the old overlay position in order to modify it. The openvr call to get the position is only updated whenever you open the menu. A new page was created due to lack of space on the utilities page. --- build_scripts/qt/resources.pri | 6 +- build_scripts/qt/sources.pri | 6 +- src/openvr/overlay_utils.cpp | 177 ++++++++++++++++++ src/openvr/overlay_utils.h | 64 +++++++ src/overlaycontroller.cpp | 12 ++ src/overlaycontroller.h | 2 + src/res/qml/RootPage.qml | 11 ++ src/res/qml/common/mainwidget.qml | 6 + .../DesktopOverlayPage.qml | 34 ++++ .../desktop_size/SteamDesktopGroupBox.qml | 12 +- .../SteamDesktopTranslationBackForwards.qml | 78 ++++++++ .../SteamDesktopTranslationLeftRight.qml | 80 ++++++++ .../SteamDesktopTranslationUpDown.qml | 78 ++++++++ src/res/qml/utilities_page/UtilitiesPage.qml | 4 - 14 files changed, 557 insertions(+), 13 deletions(-) create mode 100644 src/openvr/overlay_utils.cpp create mode 100644 src/openvr/overlay_utils.h create mode 100644 src/res/qml/desktop_overlay_page/DesktopOverlayPage.qml rename src/res/qml/{utilities_page => desktop_overlay_page}/desktop_size/SteamDesktopGroupBox.qml (98%) create mode 100644 src/res/qml/desktop_overlay_page/translation_back_forwards/SteamDesktopTranslationBackForwards.qml create mode 100644 src/res/qml/desktop_overlay_page/translation_left_right/SteamDesktopTranslationLeftRight.qml create mode 100644 src/res/qml/desktop_overlay_page/translation_up_down/SteamDesktopTranslationUpDown.qml diff --git a/build_scripts/qt/resources.pri b/build_scripts/qt/resources.pri index ab0e706..c1f669f 100644 --- a/build_scripts/qt/resources.pri +++ b/build_scripts/qt/resources.pri @@ -32,7 +32,7 @@ DISTFILES += \ src/res/qml/utilities_page/* \ src/res/qml/utilities_page/media_keys/* \ src/res/qml/utilities_page/keyboard_utils/* \ - src/res/qml/utilities_page/desktop_size/* \ + src/res/qml/desktop_overlay_page/desktop_size/* \ src/res/qml/utilities_page/alarm_clock/* \ src/res/qml/audio_page/dialog_boxes/* \ src/res/qml/audio_page/device_selector/* \ @@ -40,5 +40,9 @@ DISTFILES += \ src/res/qml/audio_page/push_to_talk/* \ src/res/qml/audio_page/profiles/* \ src/res/qml/common/* \ + src/res/qml/desktop_overlay_page/* \ + src/res/qml/desktop_overlay_page/translation_left_right/SteamDesktopTranslationLeftRight.qml \ + src/res/qml/desktop_overlay_page/translation_back_forwards/SteamDesktopTranslationBackForwards.qml \ + src/res/qml/desktop_overlay_page/translation_up_down/SteamDesktopTranslationUpDown.qml \ RC_FILE = src/res/icon.rc diff --git a/build_scripts/qt/sources.pri b/build_scripts/qt/sources.pri index 3cf35c7..9a3ea30 100644 --- a/build_scripts/qt/sources.pri +++ b/build_scripts/qt/sources.pri @@ -16,7 +16,8 @@ SOURCES += src/main.cpp\ src/openvr/openvr_init.cpp \ src/openvr/ivrinput.cpp \ src/utils/setup.cpp \ - src/utils/paths.cpp + src/utils/paths.cpp \ + src/openvr/overlay_utils.cpp HEADERS += src/overlaycontroller.h \ src/tabcontrollers/AudioTabController.h \ @@ -43,7 +44,8 @@ HEADERS += src/overlaycontroller.h \ src/openvr/ivrinput_input_source.h \ src/openvr/ivrinput.h \ src/utils/setup.h \ - src/utils/paths.h + src/utils/paths.h \ + src/openvr/overlay_utils.h win32 { SOURCES += src/tabcontrollers/audiomanager/AudioManagerWindows.cpp \ diff --git a/src/openvr/overlay_utils.cpp b/src/openvr/overlay_utils.cpp new file mode 100644 index 0000000..6f563ee --- /dev/null +++ b/src/openvr/overlay_utils.cpp @@ -0,0 +1,177 @@ +#include "overlay_utils.h" + +namespace overlay +{ +vr::VROverlayHandle_t getOverlayHandle() +{ + vr::VROverlayHandle_t pOverlayHandle; + vr::VROverlay()->FindOverlay( strings::overlaykey, &pOverlayHandle ); + return pOverlayHandle; +} + +vr::HmdMatrix34_t getDesktopOverlayPositions() +{ + vr::HmdMatrix34_t currentPosition = {}; + + const auto overlayHandle = getOverlayHandle(); + + vr::ETrackingUniverseOrigin origin + = vr::ETrackingUniverseOrigin::TrackingUniverseStanding; + + vr::VROverlay()->GetOverlayTransformAbsolute( + overlayHandle, &origin, ¤tPosition ); + + return currentPosition; +} + +void setDesktopOverlayPositions( vr::HmdMatrix34_t& positions ) +{ + const auto overlayHandle = getOverlayHandle(); + + // We need to make sure we get the same Universe Origin as before. + vr::HmdMatrix34_t currentPosition = {}; + vr::ETrackingUniverseOrigin origin + = vr::ETrackingUniverseOrigin::TrackingUniverseStanding; + vr::VROverlay()->GetOverlayTransformAbsolute( + overlayHandle, &origin, ¤tPosition ); + + vr::VROverlay()->SetOverlayTransformAbsolute( + overlayHandle, origin, &positions ); +} + +void setDesktopOverlayWidth( double width ) +{ + const auto overlayHandle = getOverlayHandle(); + auto error = vr::VROverlay()->SetOverlayWidthInMeters( + overlayHandle, static_cast( width ) ); + if ( error != vr::VROverlayError_None ) + { + LOG( ERROR ) << "Could not modify overlay width of \"" + << strings::overlaykey << "\": " + << vr::VROverlay()->GetOverlayErrorNameFromEnum( error ); + } +} + +void setSettingsToValue( const std::string setting, const double value ) +{ + QSettings settings; + settings.beginGroup( strings::settingsGroupName ); + settings.setValue( setting.c_str(), value ); + settings.endGroup(); +} + +overlay::DesktopOverlay::DesktopOverlay() +{ + QSettings settings; + settings.beginGroup( strings::settingsGroupName ); + m_width = settings.value( strings::widthSettingsName, defaultOverlayWidth ) + .toDouble(); + m_forwardsMovement + = settings.value( strings::forwardsSettingsName, defaultMovement ) + .toDouble(); + m_rightMovement + = settings.value( strings::rightMovementSettingsName, defaultMovement ) + .toDouble(); + settings.endGroup(); +} + +void DesktopOverlay::update() +{ + auto positionMatrix = getDesktopOverlayPositions(); + + auto position = QVector3D( positionMatrix.m[0][3], + positionMatrix.m[1][3], + positionMatrix.m[2][3] ); + + const auto screenRight = QVector3D( positionMatrix.m[0][0], + positionMatrix.m[1][0], + positionMatrix.m[2][0] ); + + const auto screenForwards = QVector3D( positionMatrix.m[0][2], + positionMatrix.m[1][2], + positionMatrix.m[2][2] ); + + const auto screenUp = QVector3D( positionMatrix.m[0][1], + positionMatrix.m[1][1], + positionMatrix.m[2][1] ); + + position += ( static_cast( m_rightMovement ) * screenRight ); + + position += ( static_cast( m_forwardsMovement ) * screenForwards ); + + position += ( static_cast( m_upMovement ) * screenUp ); + + positionMatrix.m[0][3] = position.x(); + positionMatrix.m[1][3] = position.y(); + positionMatrix.m[2][3] = position.z(); + + setDesktopOverlayPositions( positionMatrix ); + + setDesktopOverlayWidth( m_width ); +} + +bool DesktopOverlay::isAvailable() const +{ + vr::VROverlayHandle_t pOverlayHandle = 0; + auto error + = vr::VROverlay()->FindOverlay( strings::overlaykey, &pOverlayHandle ); + if ( error != vr::VROverlayError_None ) + { + LOG( INFO ) << "Could not find overlay \"" << strings::overlaykey + << "\": " + << vr::VROverlay()->GetOverlayErrorNameFromEnum( error ); + return false; + } + return true; +} + +void overlay::DesktopOverlay::setWidth( double width ) +{ + if ( width < 0.01 ) + { + width = 0.01; + } + + setSettingsToValue( strings::widthSettingsName, width ); + m_width = width; +} + +double DesktopOverlay::getCurrentWidth() const noexcept +{ + return m_width; +} + +void DesktopOverlay::setRightMovement( double distance ) +{ + setSettingsToValue( strings::rightMovementSettingsName, distance ); + m_rightMovement = distance; +} + +double DesktopOverlay::getCurrentRightMovement() const noexcept +{ + return m_rightMovement; +} + +void DesktopOverlay::setForwardsMovement( double distance ) +{ + setSettingsToValue( strings::forwardsSettingsName, distance ); + m_forwardsMovement = distance; +} + +double DesktopOverlay::getCurrentForwardsMovement() const noexcept +{ + return m_forwardsMovement; +} + +void DesktopOverlay::setHeight( double height ) +{ + setSettingsToValue( strings::upMovementSettingsName, height ); + m_upMovement = height; +} + +double DesktopOverlay::getCurrentHeight() const noexcept +{ + return m_upMovement; +} + +} // namespace overlay diff --git a/src/openvr/overlay_utils.h b/src/openvr/overlay_utils.h new file mode 100644 index 0000000..22875a9 --- /dev/null +++ b/src/openvr/overlay_utils.h @@ -0,0 +1,64 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +void outputMat(); +void transformMat(); + +namespace overlay +{ +namespace strings +{ + constexpr auto overlaykey = "valve.steam.desktop"; + constexpr auto settingsGroupName = "utilitiesSettings"; + constexpr auto widthSettingsName = "desktopWidth"; + constexpr auto forwardsSettingsName = "desktopForwardsMovement"; + constexpr auto rightMovementSettingsName = "desktopRightMovement"; + constexpr auto upMovementSettingsName = "desktopUpMovement"; + constexpr auto positionSettingsName = "desktopOverlayPosition"; +} // namespace strings + +constexpr auto defaultOverlayWidth = 4.0; +constexpr auto defaultMovement = 0.0; + +class DesktopOverlay : public QObject +{ + Q_OBJECT +public: + Q_PROPERTY( double rightMovement READ getCurrentRightMovement() + WRITE setRightMovement ) + Q_PROPERTY( double forwardsMovement READ getCurrentForwardsMovement WRITE + setForwardsMovement ) + Q_PROPERTY( double width READ getCurrentWidth WRITE setWidth ) + Q_PROPERTY( double height READ getCurrentHeight WRITE setHeight ) + + DesktopOverlay(); + + Q_INVOKABLE void update(); + + bool isAvailable() const; + + void setWidth( double width ); + double getCurrentWidth() const noexcept; + + void setRightMovement( double distance ); + double getCurrentRightMovement() const noexcept; + + void setForwardsMovement( double distance ); + double getCurrentForwardsMovement() const noexcept; + + void setHeight( double height ); + double getCurrentHeight() const noexcept; + +private: + double m_width = defaultOverlayWidth; + double m_forwardsMovement = defaultMovement; + double m_rightMovement = defaultMovement; + double m_upMovement = defaultMovement; +}; + +} // namespace overlay diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp index 263760d..d5ceeb8 100644 --- a/src/overlaycontroller.cpp +++ b/src/overlaycontroller.cpp @@ -20,6 +20,7 @@ #include #include #include "utils/Matrix.h" +#include "openvr/overlay_utils.h" // application namespace namespace advsettings @@ -251,6 +252,16 @@ OverlayController::OverlayController( bool desktopMode, QQmlEngine::setObjectOwnership( obj, QQmlEngine::CppOwnership ); return obj; } ); + qmlRegisterSingletonType( + qmlSingletonImportName, + 1, + 0, + "DesktopOverlay", + []( QQmlEngine*, QJSEngine* ) { + QObject* obj = &( objectAddress->m_desktopOverlay ); + QQmlEngine::setObjectOwnership( obj, QQmlEngine::CppOwnership ); + return obj; + } ); } OverlayController::~OverlayController() @@ -715,6 +726,7 @@ void OverlayController::mainEventLoop() case vr::VREvent_DashboardActivated: { LOG( DEBUG ) << "Dashboard activated"; + m_desktopOverlay.update(); m_dashboardVisible = true; } break; diff --git a/src/overlaycontroller.h b/src/overlaycontroller.h index f7c6190..d9427cc 100644 --- a/src/overlaycontroller.h +++ b/src/overlaycontroller.h @@ -39,6 +39,7 @@ #include "tabcontrollers/UtilitiesTabController.h" #include "openvr/ivrinput.h" +#include "openvr/overlay_utils.h" namespace application_strings { @@ -121,6 +122,7 @@ public: // I know it's an ugly hack to make them public to enable external SettingsTabController m_settingsTabController; ReviveTabController m_reviveTabController; UtilitiesTabController m_utilitiesTabController; + overlay::DesktopOverlay m_desktopOverlay; private: QPoint getMousePositionForEvent( vr::VREvent_Mouse_t mouse ); diff --git a/src/res/qml/RootPage.qml b/src/res/qml/RootPage.qml index c891262..6bcd0b8 100644 --- a/src/res/qml/RootPage.qml +++ b/src/res/qml/RootPage.qml @@ -114,6 +114,17 @@ MyStackViewPage { } } + MyPushButton { + id: desktopOverlayButton + activationSoundEnabled: false + text: "Desktop Overlay" + Layout.fillWidth: true + onClicked: { + MyResources.playFocusChangedSound() + mainView.push(desktopOverlayPage) + } + } + MyPushButton { id: statisticsButton activationSoundEnabled: false diff --git a/src/res/qml/common/mainwidget.qml b/src/res/qml/common/mainwidget.qml index a6b2fd2..cf81618 100644 --- a/src/res/qml/common/mainwidget.qml +++ b/src/res/qml/common/mainwidget.qml @@ -5,6 +5,7 @@ import ".." import "../utilities_page" import "../audio_page" import "../motion_page" +import "../desktop_overlay_page" Rectangle { id: root @@ -71,6 +72,11 @@ Rectangle { visible: false } + property DesktopOverlayPage desktopOverlayPage: DesktopOverlayPage { + stackView: mainView + visible: false + } + StackView { id: mainView anchors.fill: parent diff --git a/src/res/qml/desktop_overlay_page/DesktopOverlayPage.qml b/src/res/qml/desktop_overlay_page/DesktopOverlayPage.qml new file mode 100644 index 0000000..b8cff3e --- /dev/null +++ b/src/res/qml/desktop_overlay_page/DesktopOverlayPage.qml @@ -0,0 +1,34 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import ovras.advsettings 1.0 +import "translation_left_right" +import "translation_back_forwards" +import "translation_up_down" +import "desktop_size" +import "../common" + +MyStackViewPage { + headerText: "Desktop Overlay" + + content: ColumnLayout { + spacing: 18 + + SteamDesktopGroupBox { + } + + SteamDesktopTranslationUpDown { + } + + SteamDesktopTranslationBackForwards { + } + + SteamDesktopTranslationLeftRight { + } + + Item { + Layout.fillHeight: true + } + + } +} diff --git a/src/res/qml/utilities_page/desktop_size/SteamDesktopGroupBox.qml b/src/res/qml/desktop_overlay_page/desktop_size/SteamDesktopGroupBox.qml similarity index 98% rename from src/res/qml/utilities_page/desktop_size/SteamDesktopGroupBox.qml rename to src/res/qml/desktop_overlay_page/desktop_size/SteamDesktopGroupBox.qml index b811785..0bdf3ea 100644 --- a/src/res/qml/utilities_page/desktop_size/SteamDesktopGroupBox.qml +++ b/src/res/qml/desktop_overlay_page/desktop_size/SteamDesktopGroupBox.qml @@ -7,7 +7,7 @@ import "../../common" GroupBox { id: steamDesktopGroupBox Layout.fillWidth: true - + label: MyText { leftPadding: 10 text: "Steam Desktop Overlay Width" @@ -20,14 +20,14 @@ GroupBox { } ColumnLayout { anchors.fill: parent - + Rectangle { color: "#ffffff" height: 1 Layout.fillWidth: true Layout.bottomMargin: 5 } - + ColumnLayout { RowLayout { MyPushButton2 { @@ -38,7 +38,7 @@ GroupBox { steamDesktopWidthSlider.value -= 1.0 } } - + MySlider { id: steamDesktopWidthSlider from: 0.1 @@ -55,7 +55,7 @@ GroupBox { steamDesktopWidthText.text = value.toFixed(1) } } - + MyPushButton2 { id: steamDesktopWidthPlusButton Layout.preferredWidth: 40 @@ -64,7 +64,7 @@ GroupBox { steamDesktopWidthSlider.value += 1.0 } } - + MyTextField { id: steamDesktopWidthText text: "0.0" diff --git a/src/res/qml/desktop_overlay_page/translation_back_forwards/SteamDesktopTranslationBackForwards.qml b/src/res/qml/desktop_overlay_page/translation_back_forwards/SteamDesktopTranslationBackForwards.qml new file mode 100644 index 0000000..6596567 --- /dev/null +++ b/src/res/qml/desktop_overlay_page/translation_back_forwards/SteamDesktopTranslationBackForwards.qml @@ -0,0 +1,78 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import ovras.advsettings 1.0 +import "../../common" + +GroupBox { + id: steamDesktopGroupBox + Layout.fillWidth: true + + label: MyText { + leftPadding: 10 + text: "Backwards/Forwards Translation" + bottomPadding: -10 + } + background: Rectangle { + color: "transparent" + border.color: "#ffffff" + radius: 8 + } + property real sliderStepSize: 0.10 + property real rightLeftLimit: 4.0 + + ColumnLayout { + anchors.fill: parent + + LineSeparator { + } + + ColumnLayout { + RowLayout { + MyPushButton2 { + Layout.preferredWidth: 40 + text: "-" + onClicked: { + steamDesktopForwardSlider.value -= sliderStepSize + } + } + + MySlider { + id: steamDesktopForwardSlider + from: -rightLeftLimit + to: rightLeftLimit + stepSize: sliderStepSize + value: 0.0 + Layout.fillWidth: true + onValueChanged: { + DesktopOverlay.forwardsMovement = this.value + steamDesktopForwardText.text = this.value.toFixed(2) + } + } + + MyPushButton2 { + Layout.preferredWidth: 40 + text: "+" + onClicked: { + steamDesktopForwardSlider.value += sliderStepSize + } + } + + MyTextField { + id: steamDesktopForwardText + text: "0.0" + keyBoardUID: 611 + Layout.preferredWidth: 100 + Layout.leftMargin: 10 + horizontalAlignment: Text.AlignHCenter + onAcceptableInputChanged: { + steamDesktopForwardSlider.value = this.value + } + } + } + } + } + Component.onCompleted: { + steamDesktopForwardSlider.value = DesktopOverlay.forwardsMovement + } +} diff --git a/src/res/qml/desktop_overlay_page/translation_left_right/SteamDesktopTranslationLeftRight.qml b/src/res/qml/desktop_overlay_page/translation_left_right/SteamDesktopTranslationLeftRight.qml new file mode 100644 index 0000000..5b523bc --- /dev/null +++ b/src/res/qml/desktop_overlay_page/translation_left_right/SteamDesktopTranslationLeftRight.qml @@ -0,0 +1,80 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import ovras.advsettings 1.0 +import "../../common" + +GroupBox { + id: steamDesktopGroupBox + Layout.fillWidth: true + + label: MyText { + leftPadding: 10 + text: "Left/Right Translation" + bottomPadding: -10 + } + background: Rectangle { + color: "transparent" + border.color: "#ffffff" + radius: 8 + } + property real sliderStepSize: 0.10 + property real rightLeftLimit: 4.0 + + ColumnLayout { + anchors.fill: parent + + LineSeparator { + } + + ColumnLayout { + RowLayout { + MyPushButton2 { + id: steamDesktopWidthMinusButton + Layout.preferredWidth: 40 + text: "-" + onClicked: { + steamDesktopWidthSlider.value -= sliderStepSize + } + } + + MySlider { + id: steamDesktopWidthSlider + from: -rightLeftLimit + to: rightLeftLimit + stepSize: sliderStepSize + value: 0.0 + Layout.fillWidth: true + onValueChanged: { + DesktopOverlay.rightMovement = this.value + steamDesktopWidthText.text = this.value.toFixed(2) + } + } + + MyPushButton2 { + id: steamDesktopWidthPlusButton + Layout.preferredWidth: 40 + text: "+" + onClicked: { + steamDesktopWidthSlider.value += sliderStepSize + } + } + + MyTextField { + id: steamDesktopWidthText + text: "0.0" + keyBoardUID: 611 + Layout.preferredWidth: 100 + Layout.leftMargin: 10 + horizontalAlignment: Text.AlignHCenter + onAcceptableInputChanged: { + steamDesktopWidthSlider.value = this.value + } + } + } + } + } + Component.onCompleted: { + steamDesktopWidthSlider.value = DesktopOverlay.rightMovement + } +} diff --git a/src/res/qml/desktop_overlay_page/translation_up_down/SteamDesktopTranslationUpDown.qml b/src/res/qml/desktop_overlay_page/translation_up_down/SteamDesktopTranslationUpDown.qml new file mode 100644 index 0000000..91b3488 --- /dev/null +++ b/src/res/qml/desktop_overlay_page/translation_up_down/SteamDesktopTranslationUpDown.qml @@ -0,0 +1,78 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import ovras.advsettings 1.0 +import "../../common" + +GroupBox { + id: steamDesktopGroupBox + Layout.fillWidth: true + + label: MyText { + leftPadding: 10 + text: "Up/Down Translation" + bottomPadding: -10 + } + background: Rectangle { + color: "transparent" + border.color: "#ffffff" + radius: 8 + } + property real sliderStepSize: 0.10 + property real rightLeftLimit: 4.0 + + ColumnLayout { + anchors.fill: parent + + LineSeparator { + } + + ColumnLayout { + RowLayout { + MyPushButton2 { + Layout.preferredWidth: 40 + text: "-" + onClicked: { + steamDesktopUpSlider.value -= sliderStepSize + } + } + + MySlider { + id: steamDesktopUpSlider + from: -rightLeftLimit + to: rightLeftLimit + stepSize: sliderStepSize + value: 0.0 + Layout.fillWidth: true + onValueChanged: { + DesktopOverlay.height = this.value + steamDesktopUpText.text = this.value.toFixed(2) + } + } + + MyPushButton2 { + Layout.preferredWidth: 40 + text: "+" + onClicked: { + steamDesktopUpSlider.value += sliderStepSize + } + } + + MyTextField { + id: steamDesktopUpText + text: "0.0" + keyBoardUID: 611 + Layout.preferredWidth: 100 + Layout.leftMargin: 10 + horizontalAlignment: Text.AlignHCenter + onAcceptableInputChanged: { + steamDesktopUpSlider.value = this.value + } + } + } + } + } + Component.onCompleted: { + steamDesktopUpSlider.value = DesktopOverlay.height + } +} diff --git a/src/res/qml/utilities_page/UtilitiesPage.qml b/src/res/qml/utilities_page/UtilitiesPage.qml index f7ae438..2945d68 100644 --- a/src/res/qml/utilities_page/UtilitiesPage.qml +++ b/src/res/qml/utilities_page/UtilitiesPage.qml @@ -22,10 +22,6 @@ MyStackViewPage { id: alarmGroupBox } - SteamDesktopGroupBox { - id: steamDesktopGroupBox - } - MediaControllerKeys { id: mediaKeysGroupBox }