diff --git a/advancedSettings.pro b/advancedSettings.pro index 05d4ff1..67fd97b 100644 --- a/advancedSettings.pro +++ b/advancedSettings.pro @@ -22,6 +22,7 @@ SOURCES += src/main.cpp\ src/tabcontrollers/StatisticsTabController.cpp \ src/tabcontrollers/SteamVRTabController.cpp \ src/tabcontrollers/ReviveTabController.cpp \ + src/tabcontrollers/UtilitiesTabController.cpp \ src/tabcontrollers/audiomanager/AudioManagerWindows.cpp HEADERS += src/overlaycontroller.h \ @@ -34,6 +35,7 @@ HEADERS += src/overlaycontroller.h \ src/tabcontrollers/StatisticsTabController.h \ src/tabcontrollers/SteamVRTabController.h \ src/tabcontrollers/ReviveTabController.h \ + src/tabcontrollers/UtilitiesTabController.h \ src/tabcontrollers/AudioManager.h \ src/tabcontrollers/audiomanager/AudioManagerWindows.h diff --git a/bin/win64/res/qml/RootPage.qml b/bin/win64/res/qml/RootPage.qml index 2e33634..5f14195 100644 --- a/bin/win64/res/qml/RootPage.qml +++ b/bin/win64/res/qml/RootPage.qml @@ -89,6 +89,17 @@ MyStackViewPage { } } + MyPushButton { + id: utilitiesButton + activationSoundEnabled: false + text: "Utilities" + Layout.fillWidth: true + onClicked: { + MyResources.playFocusChangedSound() + mainView.push(utilitiesPage) + } + } + MyPushButton { id: statisticsButton activationSoundEnabled: false diff --git a/bin/win64/res/qml/UtilitiesPage.qml b/bin/win64/res/qml/UtilitiesPage.qml new file mode 100644 index 0000000..3eae765 --- /dev/null +++ b/bin/win64/res/qml/UtilitiesPage.qml @@ -0,0 +1,98 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import matzman666.advsettings 1.0 + + +MyStackViewPage { + headerText: "Utilities" + + content: ColumnLayout { + spacing: 18 + + + GroupBox { + Layout.fillWidth: true + + label: MyText { + leftPadding: 10 + text: "Keyboard Utilities" + bottomPadding: -10 + } + background: Rectangle { + color: "transparent" + border.color: "#ffffff" + radius: 8 + } + ColumnLayout { + anchors.fill: parent + + Rectangle { + color: "#ffffff" + height: 1 + Layout.fillWidth: true + Layout.bottomMargin: 5 + } + + + MyText { + text: "Send to active application: " + } + + RowLayout { + spacing: 18 + + MyPushButton { + text: "VR Keyboard Input" + Layout.preferredWidth: 260 + onClicked: { + OverlayController.showKeyboard("", 601) + } + Connections { + target: OverlayController + onKeyBoardInputSignal: { + if (userValue == 601) { + UtilitiesTabController.sendKeyboardInput(input) + } + } + } + } + + MyPushButton { + text: "Enter" + Layout.preferredWidth: 260 + onClicked: { + UtilitiesTabController.sendKeyboardEnter() + } + } + + MyPushButton { + text: "Backspace" + Layout.preferredWidth: 260 + onClicked: { + UtilitiesTabController.sendKeyboardBackspace(1) + } + } + + MyPushButton { + text: "10x Backspace" + Layout.preferredWidth: 260 + onClicked: { + UtilitiesTabController.sendKeyboardBackspace(10) + } + } + } + } + } + + Item { + Layout.fillHeight: true + } + + /*Component.onCompleted: { + } + + Connections { + }*/ + } +} diff --git a/bin/win64/res/qml/mainwidget.qml b/bin/win64/res/qml/mainwidget.qml index cf08376..d11067c 100644 --- a/bin/win64/res/qml/mainwidget.qml +++ b/bin/win64/res/qml/mainwidget.qml @@ -53,6 +53,11 @@ Rectangle { visible: false } + property UtilitiesPage utilitiesPage: UtilitiesPage { + stackView: mainView + visible: false + } + StackView { id: mainView anchors.fill: parent diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp index 446e880..d6c61ca 100644 --- a/src/overlaycontroller.cpp +++ b/src/overlaycontroller.cpp @@ -86,6 +86,7 @@ void OverlayController::Init(QQmlEngine* qmlEngine) { statisticsTabController.initStage1(); settingsTabController.initStage1(); reviveTabController.initStage1(); + utilitiesTabController.initStage1(); // Set qml context qmlEngine->rootContext()->setContextProperty("applicationVersion", getVersionString()); @@ -137,6 +138,11 @@ void OverlayController::Init(QQmlEngine* qmlEngine) { QQmlEngine::setObjectOwnership(obj, QQmlEngine::CppOwnership); return obj; }); + qmlRegisterSingletonType("matzman666.advsettings", 1, 0, "UtilitiesTabController", [](QQmlEngine*, QJSEngine*) { + QObject* obj = &getInstance()->utilitiesTabController; + QQmlEngine::setObjectOwnership(obj, QQmlEngine::CppOwnership); + return obj; + }); } void OverlayController::Shutdown() { @@ -221,6 +227,7 @@ void OverlayController::SetWidget(QQuickItem* quickItem, const std::string& name statisticsTabController.initStage2(this, m_pWindow.get()); settingsTabController.initStage2(this, m_pWindow.get()); reviveTabController.initStage2(this, m_pWindow.get()); + utilitiesTabController.initStage2(this, m_pWindow.get()); } diff --git a/src/overlaycontroller.h b/src/overlaycontroller.h index a30da8d..5b29745 100644 --- a/src/overlaycontroller.h +++ b/src/overlaycontroller.h @@ -30,6 +30,7 @@ #include "tabcontrollers/StatisticsTabController.h" #include "tabcontrollers/SettingsTabController.h" #include "tabcontrollers/ReviveTabController.h" +#include "tabcontrollers/UtilitiesTabController.h" @@ -76,6 +77,7 @@ public: // I know it's an ugly hack to make them public to enable external acces StatisticsTabController statisticsTabController; SettingsTabController settingsTabController; ReviveTabController reviveTabController; + UtilitiesTabController utilitiesTabController; private: OverlayController(bool desktopMode, bool noSound) : QObject(), desktopMode(desktopMode), noSound(noSound) {} diff --git a/src/tabcontrollers/UtilitiesTabController.cpp b/src/tabcontrollers/UtilitiesTabController.cpp new file mode 100644 index 0000000..3a40706 --- /dev/null +++ b/src/tabcontrollers/UtilitiesTabController.cpp @@ -0,0 +1,149 @@ +#include "UtilitiesTabController.h" +#include +#include "../overlaycontroller.h" +#include + +// application namespace +namespace advsettings { + + + void UtilitiesTabController::initStage1() { + } + + void UtilitiesTabController::initStage2(OverlayController * parent, QQuickWindow * widget) { + this->parent = parent; + this->widget = widget; + } + + void fillKiStruct(INPUT& ip, WORD scanCode, bool keyup) { + ip.type = INPUT_KEYBOARD; + ip.ki.wVk = scanCode; + if (keyup) { + ip.ki.dwFlags = KEYEVENTF_KEYUP; + } else { + ip.ki.dwFlags = 0; + } + ip.ki.wScan = 0; + ip.ki.dwExtraInfo = 0; + ip.ki.time = 0; + }; + + void UtilitiesTabController::sendKeyboardInput(QString input) { + int len = input.length(); + if (len > 0) { + LPINPUT ips = new INPUT[len * 5 + 3]; + unsigned ii = 0; + bool shiftPressed = false; + bool ctrlPressed = false; + bool altPressed = false; + for (int i = 0; i < len; i++) { + short tmp = VkKeyScan(input.at(i).toLatin1()); + WORD c = tmp & 0xFF; + short shiftState = tmp >> 8; + bool isShift = shiftState & 1; + bool isCtrl = shiftState & 2; + bool isAlt = shiftState & 4; + if (isShift && !shiftPressed) { + fillKiStruct(ips[ii++], VK_SHIFT, false); + shiftPressed = true; + } else if (!isShift && shiftPressed) { + fillKiStruct(ips[ii++], VK_SHIFT, true); + shiftPressed = false; + } + if (isCtrl && !ctrlPressed) { + fillKiStruct(ips[ii++], VK_CONTROL, false); + ctrlPressed = true; + } else if (!isCtrl && ctrlPressed) { + fillKiStruct(ips[ii++], VK_CONTROL, true); + ctrlPressed = false; + } + if (isAlt && !altPressed) { + fillKiStruct(ips[ii++], VK_MENU, false); + altPressed = true; + } else if (!isAlt && altPressed) { + fillKiStruct(ips[ii++], VK_MENU, true); + altPressed = false; + } + fillKiStruct(ips[ii++], c, false); + fillKiStruct(ips[ii++], c, true); + } + if (shiftPressed) { + fillKiStruct(ips[ii++], VK_SHIFT, true); + shiftPressed = false; + } + if (ctrlPressed) { + fillKiStruct(ips[ii++], VK_CONTROL, true); + ctrlPressed = false; + } + if (altPressed) { + fillKiStruct(ips[ii++], VK_MENU, true); + altPressed = false; + } + if (!SendInput(ii, ips, sizeof(INPUT))) { + char *err; + auto errCode = GetLastError(); + if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language + (LPTSTR)&err, + 0, + NULL)){ + LOG(ERROR) << "Error calling SendInput(): Could not get error message (" << errCode << ")"; + } else { + LOG(ERROR) << "Error calling SendInput(): " << err; + } + } + delete ips; + } + } + + void UtilitiesTabController::sendKeyboardEnter() { + LPINPUT ips = new INPUT[2]; + fillKiStruct(ips[0], VK_RETURN, false); + fillKiStruct(ips[1], VK_RETURN, true); + if (!SendInput(2, ips, sizeof(INPUT))) { + char *err; + auto errCode = GetLastError(); + if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language + (LPTSTR)&err, + 0, + NULL)) { + LOG(ERROR) << "Error calling SendInput(): Could not get error message (" << errCode << ")"; + } else { + LOG(ERROR) << "Error calling SendInput(): " << err; + } + } + delete ips; + } + + void UtilitiesTabController::sendKeyboardBackspace(int count) { + if (count > 0) { + LPINPUT ips = new INPUT[count * 2]; + for (int i = 0; i < count; i++) { + fillKiStruct(ips[2 * i], VK_BACK, false); + fillKiStruct(ips[2 * i + 1], VK_BACK, true); + } + if (!SendInput(2 * count, ips, sizeof(INPUT))) { + char *err; + auto errCode = GetLastError(); + if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language + (LPTSTR)&err, + 0, + NULL)) { + LOG(ERROR) << "Error calling SendInput(): Could not get error message (" << errCode << ")"; + } else { + LOG(ERROR) << "Error calling SendInput(): " << err; + } + } + delete ips; + } + } + +} // namespace advconfig diff --git a/src/tabcontrollers/UtilitiesTabController.h b/src/tabcontrollers/UtilitiesTabController.h new file mode 100644 index 0000000..fb83aba --- /dev/null +++ b/src/tabcontrollers/UtilitiesTabController.h @@ -0,0 +1,33 @@ + +#pragma once + +#include + +class QQuickWindow; +// application namespace +namespace advsettings { + + // forward declaration + class OverlayController; + + + class UtilitiesTabController : public QObject { + Q_OBJECT + + private: + OverlayController* parent; + QQuickWindow* widget; + + public: + void initStage1(); + void initStage2(OverlayController* parent, QQuickWindow* widget); + + public slots: + void sendKeyboardInput(QString input); + void sendKeyboardEnter(); + void sendKeyboardBackspace(int count); + + signals: + }; + +} // namespace advsettings