diff --git a/GlosSIConfig/.clang-format b/GlosSIConfig/.clang-format
index dc813fd..7cc5c0d 100644
--- a/GlosSIConfig/.clang-format
+++ b/GlosSIConfig/.clang-format
@@ -1,4 +1,5 @@
UseTab: false
+BasedOnStyle: LLVM
IndentWidth: 4
BreakBeforeBraces: "Stroustrup"
AllowShortIfStatementsOnASingleLine: false
diff --git a/GlosSIConfig/GlosSIConfig.vcxproj b/GlosSIConfig/GlosSIConfig.vcxproj
index 2033835..025235d 100644
--- a/GlosSIConfig/GlosSIConfig.vcxproj
+++ b/GlosSIConfig/GlosSIConfig.vcxproj
@@ -137,6 +137,8 @@
+
+
@@ -144,6 +146,7 @@
+
diff --git a/GlosSIConfig/GlosSIConfig.vcxproj.filters b/GlosSIConfig/GlosSIConfig.vcxproj.filters
index e1d59d1..4b2ed94 100644
--- a/GlosSIConfig/GlosSIConfig.vcxproj.filters
+++ b/GlosSIConfig/GlosSIConfig.vcxproj.filters
@@ -65,6 +65,15 @@
+
+ qml
+
+
+ qml
+
+
+ qml
+
diff --git a/GlosSIConfig/Resource.rc b/GlosSIConfig/Resource.rc
index ee15a05..315c1a0 100644
--- a/GlosSIConfig/Resource.rc
+++ b/GlosSIConfig/Resource.rc
@@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,0,8,003002880001
- PRODUCTVERSION 0,0,8,003002880001
+ FILEVERSION 0,0,8,1023005406006
+ PRODUCTVERSION 0,0,8,1023005406006
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -69,12 +69,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Peter Repukat - FlatspotSoftware"
VALUE "FileDescription", "GlosSI - Config"
- VALUE "FileVersion", "0.0.8.0-3-g288bba1"
+ VALUE "FileVersion", "0.0.8.1-23-g54e6bf6"
VALUE "InternalName", "GlosSIConfig"
VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware"
VALUE "OriginalFilename", "GlosSIConfig.exe"
VALUE "ProductName", "GlosSI"
- VALUE "ProductVersion", "0.0.8.0-3-g288bba1"
+ VALUE "ProductVersion", "0.0.8.1-23-g54e6bf6"
END
END
BLOCK "VarFileInfo"
@@ -756,6 +756,342 @@ IDI_ICON1 ICON "..\GloSC_Icon.ico"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GlosSIConfig/UIModel.cpp b/GlosSIConfig/UIModel.cpp
index a1c2451..f75ac62 100644
--- a/GlosSIConfig/UIModel.cpp
+++ b/GlosSIConfig/UIModel.cpp
@@ -39,16 +39,16 @@ UIModel::UIModel() : QObject(nullptr)
std::filesystem::create_directories(path);
config_path_ = path;
- config_dir_name_ = QString::fromStdWString((path /= "Targets").wstring().data());
+ config_dir_name_ = QString::fromStdWString((path /= "Targets").wstring());
if (!std::filesystem::exists(path))
std::filesystem::create_directories(path);
parseShortcutVDF();
- readConfigs();
+ readTargetConfigs();
}
-void UIModel::readConfigs()
+void UIModel::readTargetConfigs()
{
QDir dir(config_dir_name_);
auto entries = dir.entryList(QDir::Files, QDir::SortFlag::Name);
@@ -68,29 +68,13 @@ void UIModel::readConfigs()
const auto data = file.readAll();
file.close();
const auto jsondoc = QJsonDocument::fromJson(data);
- const auto filejson = jsondoc.object();
-
- QJsonObject json;
- json["version"] = filejson["version"];
- json["icon"] = filejson["icon"];
- json["launch"] = filejson["launch"]["launch"];
- json["launchPath"] = filejson["launch"]["launchPath"];
- json["launchAppArgs"] = filejson["launch"]["launchAppArgs"];
- json["closeOnExit"] = filejson["launch"]["closeOnExit"];
- json["waitForChildProcs"] = filejson["launch"]["waitForChildProcs"];
- json["hideDevices"] = filejson["devices"]["hideDevices"];
- json["realDeviceIds"] = filejson["devices"]["realDeviceIds"];
- json["windowMode"] = filejson["window"]["windowMode"];
- json["maxFps"] = filejson["window"]["maxFps"];
- json["scale"] = filejson["window"]["scale"];
- json["disableOverlay"] = filejson["window"]["disableOverlay"];
- json["maxControllers"] = filejson["controller"]["maxControllers"];
- json["allowDesktopConfig"] = filejson["controller"]["allowDesktopConfig"];
- json["emulateDS4"] = filejson["controller"]["emulateDS4"];
-
- json["name"] = filejson.contains("name") ? filejson["name"] : QString(name).replace(QRegularExpression("\\.json"), "");
-
- targets_.append(json.toVariantMap());
+ auto filejson = jsondoc.object();
+
+ filejson["name"] = filejson.contains("name")
+ ? filejson["name"].toString()
+ : QString(name).replace(QRegularExpression("\\.json"), "");
+
+ targets_.append(filejson.toVariantMap());
});
emit targetListChanged();
@@ -237,6 +221,46 @@ QVariantMap UIModel::manualProps(QVariant shortcut)
return res;
}
+void UIModel::enableSteamInputXboxSupport()
+{
+ if (foundSteam()) {
+ const std::filesystem::path config_path = std::wstring(getSteamPath()) + user_data_path_.toStdWString() + getSteamUserId() + user_config_file_.toStdWString();
+ if (!std::filesystem::exists(config_path)) {
+ qDebug() << "localconfig.vdf does not exist.";
+ }
+ QFile file(config_path);
+ if (file.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ QTextStream in(&file);
+ QStringList lines;
+ QString line = in.readLine();
+ // simple approach is enough...
+ while (!in.atEnd()) {
+ if (line.contains("SteamController_XBoxSupport")) {
+ if (line.contains("1")) {
+ qDebug() << "\"SteamController_XBoxSupport\" is already enabled! aborting write...";
+ file.close();
+ return;
+ }
+ qDebug() << "found \"SteamController_XBoxSupport\" line, replacing value...";
+ line.replace("0", "1");
+ }
+ lines.push_back(line);
+ line = in.readLine();
+ }
+ file.close();
+ QFile updatedFile(config_path);
+ if (updatedFile.open(QFile::WriteOnly | QFile::Truncate | QFile::Text)) {
+ qDebug() << "writing localconfig.vdf...";
+ QTextStream out(&updatedFile);
+ for (const auto& l : lines) {
+ out << l << "\n";
+ }
+ }
+ updatedFile.close();
+ }
+ }
+}
+
#ifdef _WIN32
QVariantList UIModel::uwpApps()
{
@@ -319,60 +343,41 @@ void UIModel::setAcrylicEffect(bool has_acrylic_affect)
emit acrylicChanged();
}
-void UIModel::writeTarget(const QJsonObject& json, const QString& name)
+void UIModel::writeTarget(const QJsonObject& json, const QString& name) const
{
auto path = config_path_;
path /= config_dir_name_.toStdWString();
path /= (QString(name).replace(QRegularExpression("[\\\\/:*?\"<>|]"), "") + ".json").toStdWString();
QFile file(path);
if (!file.open(QIODevice::Text | QIODevice::ReadWrite)) {
- // meh
+ qDebug() << "Couldn't open file for writing: " << path;
return;
}
- QJsonObject fileJson;
- fileJson["version"] = json["version"];
- fileJson["icon"] = json["icon"];
- fileJson["name"] = json["name"];
-
- QJsonObject launchObject;
- launchObject["launch"] = json["launch"];
- launchObject["launchPath"] = json["launchPath"];
- launchObject["launchAppArgs"] = json["launchAppArgs"];
- launchObject["closeOnExit"] = json["closeOnExit"];
- launchObject["waitForChildProcs"] = json["waitForChildProcs"];
- fileJson["launch"] = launchObject;
-
- QJsonObject devicesObject;
- devicesObject["hideDevices"] = json["hideDevices"];
- devicesObject["realDeviceIds"] = json["realDeviceIds"];
- fileJson["devices"] = devicesObject;
-
- QJsonObject windowObject;
- windowObject["windowMode"] = json["windowMode"];
- windowObject["maxFps"] = json["maxFps"];
- windowObject["scale"] = json["scale"];
- windowObject["disableOverlay"] = json["disableOverlay"];
- fileJson["window"] = windowObject;
-
- QJsonObject controllerObject;
- controllerObject["maxControllers"] = json["maxControllers"];
- controllerObject["allowDesktopConfig"] = json["allowDesktopConfig"];
- controllerObject["emulateDS4"] = json["emulateDS4"];
- fileJson["controller"] = controllerObject;
-
- auto wtf = QString(QJsonDocument(fileJson).toJson(QJsonDocument::Indented)).toStdString();
- file.write(wtf.data());
+
+ file.write(
+ QString(QJsonDocument(json).toJson(QJsonDocument::Indented))
+ .toStdString()
+ .data()
+ );
file.close();
}
std::filesystem::path UIModel::getSteamPath() const
{
+ try {
#ifdef _WIN32
- // TODO: check if keys/value exist
- // steam should always be open and have written reg values...
- winreg::RegKey key{HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam"};
- const auto res = key.GetStringValue(L"SteamPath");
- return res;
+ // TODO: check if keys/value exist
+ // steam should always be open and have written reg values...
+ winreg::RegKey key{HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam"};
+ if (!key.IsValid()) {
+ return "";
+ }
+ const auto res = key.GetStringValue(L"SteamPath");
+ return res;
+ }
+ catch (...) {
+ return "";
+ }
#else
return L""; // TODO LINUX
#endif
@@ -381,22 +386,46 @@ std::filesystem::path UIModel::getSteamPath() const
std::wstring UIModel::getSteamUserId() const
{
#ifdef _WIN32
- // TODO: check if keys/value exist
- // steam should always be open and have written reg values...
- winreg::RegKey key{HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam\\ActiveProcess"};
- const auto res = std::to_wstring(key.GetDwordValue(L"ActiveUser"));
- if (res == L"0") {
- qDebug() << "Steam not open?";
+ try {
+ // TODO: check if keys/value exist
+ // steam should always be open and have written reg values...
+ winreg::RegKey key{HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam\\ActiveProcess"};
+ if (!key.IsValid()) {
+ return L"0";
+ }
+ const auto res = std::to_wstring(key.GetDwordValue(L"ActiveUser"));
+ if (res == L"0") {
+ qDebug() << "Steam not open?";
+ }
+ return res;
+ } catch(...) {
+ return L"0";
}
- return res;
#else
return L""; // TODO LINUX
#endif
}
+bool UIModel::foundSteam() const
+{
+ if (getSteamPath() == "" || getSteamUserId() == L"0") {
+ return false;
+ }
+ const std::filesystem::path user_config_dir = std::wstring(getSteamPath()) + user_data_path_.toStdWString() + getSteamUserId();
+ if (!std::filesystem::exists(user_config_dir)) {
+ return false;
+ }
+ return true;
+}
+
void UIModel::parseShortcutVDF()
{
const std::filesystem::path config_path = std::wstring(getSteamPath()) + user_data_path_.toStdWString() + getSteamUserId() + shortcutsfile_.toStdWString();
+ if (!std::filesystem::exists(config_path)) {
+ qDebug() << "Shortcuts file does not exist.";
+ return;
+ }
+
try {
shortcuts_vdf_ = VDFParser::Parser::parseShortcuts(config_path, qDebug());
}
@@ -404,3 +433,39 @@ void UIModel::parseShortcutVDF()
qDebug() << "Error parsing VDF: " << e.what();
}
}
+
+bool UIModel::isSteamInputXboxSupportEnabled() const
+{
+ // return true as default to not bug the user in error cases.
+ if (foundSteam()) {
+ const std::filesystem::path config_path = std::wstring(getSteamPath()) + user_data_path_.toStdWString() + getSteamUserId() + user_config_file_.toStdWString();
+ if (!std::filesystem::exists(config_path)) {
+ qDebug() << "localconfig.vdf does not exist.";
+ return true;
+ }
+ QFile file(config_path);
+ if (file.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ QTextStream in(&file);
+ QString line = in.readLine();
+ // simple, regex approach should be enough...
+ while (!in.atEnd()) {
+ if (line.contains("SteamController_XBoxSupport")) {
+ file.close();
+ if (line.contains("1")) {
+ qDebug() << "\"SteamController_XBoxSupport\" is enabled!";
+ return true;
+ }
+ qDebug() << "\"SteamController_XBoxSupport\" is disabled!";
+ return false;
+ }
+ line = in.readLine();
+ }
+ qDebug() << "couldn't find \"SteamController_XBoxSupport\" in localconfig.vdf";
+ file.close();
+ }
+ else {
+ qDebug() << "could not open localconfig.vdf";
+ }
+ }
+ return true;
+}
diff --git a/GlosSIConfig/UIModel.h b/GlosSIConfig/UIModel.h
index d9c1595..4ec241a 100644
--- a/GlosSIConfig/UIModel.h
+++ b/GlosSIConfig/UIModel.h
@@ -27,11 +27,13 @@ class UIModel : public QObject {
Q_PROPERTY(bool hasAcrlyicEffect READ hasAcrylicEffect NOTIFY acrylicChanged)
Q_PROPERTY(QVariantList targetList READ getTargetList NOTIFY targetListChanged)
Q_PROPERTY(QVariantList uwpList READ uwpApps CONSTANT)
+ Q_PROPERTY(bool foundSteam READ foundSteam CONSTANT)
+ Q_PROPERTY(bool steamInputXboxSupportEnabled READ isSteamInputXboxSupportEnabled CONSTANT)
public:
UIModel();
- Q_INVOKABLE void readConfigs();
+ Q_INVOKABLE void readTargetConfigs();
Q_INVOKABLE QVariantList getTargetList() const;
Q_INVOKABLE void addTarget(QVariant shortcut);
Q_INVOKABLE void updateTarget(int index, QVariant shortcut);
@@ -41,6 +43,7 @@ class UIModel : public QObject {
bool addToSteam(const QString& name, const QString& shortcutspath, bool from_cmd = false);
Q_INVOKABLE bool removeFromSteam(const QString& name, const QString& shortcutspath, bool from_cmd = false);
Q_INVOKABLE QVariantMap manualProps(QVariant shortcut);
+ Q_INVOKABLE void enableSteamInputXboxSupport();
#ifdef _WIN32
Q_INVOKABLE QVariantList uwpApps();
#endif
@@ -61,25 +64,30 @@ class UIModel : public QObject {
void targetListChanged();
private:
+#ifdef _WIN32
+ bool is_windows_ = true;
+#else
+ bool is_windows_ = false;
+#endif
+ bool has_acrylic_affect_ = false;
+
std::filesystem::path config_path_;
QString config_dir_name_;
-
- void writeTarget(const QJsonObject& json, const QString& name);
- std::filesystem::path getSteamPath() const;
- std::wstring getSteamUserId() const;
- void parseShortcutVDF();
QString shortcutsfile_ = "/config/shortcuts.vdf";
+ QString user_config_file_ = "/config/localconfig.vdf";
QString user_data_path_ = "/userdata/";
QVariantList targets_;
std::vector shortcuts_vdf_;
+
+ void writeTarget(const QJsonObject& json, const QString& name) const;
-#ifdef _WIN32
- bool is_windows_ = true;
-#else
- bool is_windows_ = false;
-#endif
- bool has_acrylic_affect_ = false;
+ std::filesystem::path getSteamPath() const;
+ std::wstring getSteamUserId() const;
+ bool foundSteam() const;
+ void parseShortcutVDF();
+
+ bool isSteamInputXboxSupportEnabled() const;
};
diff --git a/GlosSIConfig/qml.qrc b/GlosSIConfig/qml.qrc
index 80ff2b9..b273ad9 100644
--- a/GlosSIConfig/qml.qrc
+++ b/GlosSIConfig/qml.qrc
@@ -15,5 +15,9 @@
noise.png
GloSC_Icon_small.png
svg/help_outline_white_24dp.svg
+ qml/SteamNotFoundDialog.qml
+ qml/SteamInputXboxDisabledDialog.qml
+ qml/CollapsiblePane.qml
+ svg/expand_more_white_24dp.svg
diff --git a/GlosSIConfig/qml/CollapsiblePane.qml b/GlosSIConfig/qml/CollapsiblePane.qml
new file mode 100644
index 0000000..6dea9e0
--- /dev/null
+++ b/GlosSIConfig/qml/CollapsiblePane.qml
@@ -0,0 +1,97 @@
+/*
+Copyright 2021-2022 Peter Repukat - FlatspotSoftware
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+import QtQuick 2.9
+import QtQuick.Controls 2.9
+import QtQuick.Controls.Material 2.9
+import QtQuick.Controls.Material.impl 2.9
+
+
+RPane {
+ property alias title: paneTitle.text
+ width: parent.width
+
+ property alias content: ldr.sourceComponent
+ clip: true
+ height: paneHeader.height + collapseColumn.spacing
+ property bool collapsed: true
+ id: collapsePane
+
+ Behavior on height {
+ NumberAnimation {
+ duration: 300
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ Column {
+ id: collapseColumn
+ width: parent.width
+ spacing: 16
+ Item {
+ id: paneHeader
+ width: parent.width
+ height: paneTitle.height + 32
+ Label {
+ id: paneTitle
+ anchors.left: parent.left
+ anchors.leftMargin: 4
+ font.bold: true
+ font.pixelSize: 24
+ anchors.top: parent.top
+ anchors.topMargin: 14
+ }
+ RoundButton {
+ width: 48
+ height: 48
+ Material.elevation: 0
+ anchors.rightMargin: 0
+ anchors.top: parent.top
+ anchors.topMargin: 0
+ onClicked: function(){
+ collapsed = !collapsed;
+ if (collapsed) {
+ collapsePane.height = paneHeader.height + collapseColumn.spacing
+ } else {
+ collapsePane.height = paneHeader.height + collapseColumn.spacing * 3 + ldr.item.height
+ }
+ }
+ Image {
+ id: arrowImg
+ anchors.centerIn: parent
+ source: "qrc:/svg/expand_more_white_24dp.svg"
+ width: 24
+ height: 24
+ transform: Rotation{
+ angle: collapsed ? 0 : 180
+ origin.x: arrowImg.width/2
+ origin.y: arrowImg.height/2
+ Behavior on angle {
+ NumberAnimation {
+ duration: 125
+ easing.type: Easing.InOutQuad
+ }
+ }
+ }
+ }
+ anchors.right: parent.right
+ }
+ }
+ Loader {
+ id: ldr
+ width: parent.width
+ }
+ }
+}
diff --git a/GlosSIConfig/qml/ShortcutProps.qml b/GlosSIConfig/qml/ShortcutProps.qml
index 14ba84c..8d2a7da 100644
--- a/GlosSIConfig/qml/ShortcutProps.qml
+++ b/GlosSIConfig/qml/ShortcutProps.qml
@@ -29,62 +29,62 @@ Item {
signal cancel()
signal done(var shortcut)
- property var shortcutInfo: ({
- version: 1,
- name: null,
- launch: false,
- launchPath: null,
- launchAppArgs: null,
- closeOnExit: true,
- waitForChildProcs: true,
- hideDevices: true,
- windowMode: false,
- maxFps: null,
- scale: null,
- icon: null,
- maxControllers: 4,
- disableOverlay: false,
- realDeviceIds: false,
- allowDesktopConfig: false,
- emulateDS4: false,
- })
+ property var shortcutInfo: ({})
function resetInfo() {
shortcutInfo = ({
- version: 1,
- name: null,
- launch: false,
- launchPath: null,
- launchAppArgs: null,
- closeOnExit: true,
- waitForChildProcs: true,
- hideDevices: true,
- windowMode: false,
- maxFps: null,
- scale: null,
- icon: null,
- maxControllers: 4,
- disableOverlay: false,
- realDeviceIds: false,
- allowDesktopConfig: false,
- emulateDS4: false,
+ "controller": {
+ "maxControllers": 1,
+ "emulateDS4": false,
+ "allowDesktopConfig": false
+ },
+ "devices": {
+ "hideDevices": true,
+ "realDeviceIds": false
+ },
+ "icon": null,
+ "launch": {
+ "closeOnExit": true,
+ "launch": false,
+ "launchAppArgs": null,
+ "launchPath": null,
+ "waitForChildProcs": true
+ },
+ "name": null,
+ "version": 1,
+ "window": {
+ "disableOverlay": false,
+ "maxFps": null,
+ "scale": null,
+ "windowMode": false
+ },
+ "extendedLogging": false
})
}
+
+ Component.onCompleted: function() {
+ resetInfo()
+ }
onShortcutInfoChanged: function() {
nameInput.text = shortcutInfo.name || ""
- launchApp.checked = shortcutInfo.launch || false
- pathInput.text = shortcutInfo.launchPath || ""
- argsInput.text = shortcutInfo.launchAppArgs || ""
- closeOnExit.checked = shortcutInfo.closeOnExit || false
- waitForChildren.checked = shortcutInfo.waitForChildProcs
- hideDevices.checked = shortcutInfo.hideDevices || false
- windowMode.checked = shortcutInfo.windowMode || false
- maxControllersSpinBox.value = shortcutInfo.maxControllers
- disableOverlayCheckbox.checked = shortcutInfo.disableOverlay || false
- realDeviceIds.checked = shortcutInfo.realDeviceIds || false
- allowDesktopConfig.checked = shortcutInfo.allowDesktopConfig || false
- emulateDS4.checked = shortcutInfo.emulateDS4 || false
+ if (extendedLogging) {
+ extendedLogging.checked = shortcutInfo.extendedLogging || false
+ }
+ launchApp.checked = shortcutInfo.launch.launch
+ pathInput.text = shortcutInfo.launch.launchPath || ""
+ argsInput.text = shortcutInfo.launch.launchAppArgs || ""
+ closeOnExit.checked = shortcutInfo.launch.closeOnExit
+ waitForChildren.checked = shortcutInfo.launch.waitForChildProcs
+ hideDevices.checked = shortcutInfo.devices.hideDevices
+ realDeviceIds.checked = shortcutInfo.devices.realDeviceIds
+ windowMode.checked = shortcutInfo.window.windowMode
+ disableOverlayCheckbox.checked = shortcutInfo.window.disableOverlay
+ scaleSpinBox.value = shortcutInfo.window.scale
+ maxFPSSpinBox.value = shortcutInfo.window.maxFps
+ maxControllersSpinBox.value = shortcutInfo.controller.maxControllers
+ allowDesktopConfig.checked = shortcutInfo.controller.allowDesktopConfig
+ emulateDS4.checked = shortcutInfo.controller.emulateDS4
}
Flickable {
@@ -144,7 +144,6 @@ Item {
}
RPane {
width: parent.width
- height: 248
radius: 4
Material.elevation: 32
bgOpacity: 0.97
@@ -155,17 +154,18 @@ Item {
Row {
spacing: 32
width: parent.width
- height: closeOnExitCol.height
CheckBox {
id: launchApp
text: qsTr("Launch app")
- checked: shortcutInfo.launch
+ checked: shortcutInfo.launch.launch
onCheckedChanged: function() {
- shortcutInfo.launch = checked
+ shortcutInfo.launch.launch = checked
if (checked) {
- closeOnExit.enabled = true;
- if (closeOnExit.checked) {
- waitForChildren.enabled = true;
+ if (closeOnExit) {
+ closeOnExit.enabled = true;
+ if (closeOnExit.checked) {
+ waitForChildren.enabled = true;
+ }
}
allowDesktopConfig.enabled = true;
} else {
@@ -175,54 +175,6 @@ Item {
}
}
}
- Column {
- id: closeOnExitCol
- spacing: 2
- CheckBox {
- id: closeOnExit
- text: qsTr("Close when launched app quits")
- checked: shortcutInfo.closeOnExit
- onCheckedChanged: function() {
- shortcutInfo.closeOnExit = checked
- if (checked) {
- waitForChildren.enabled = true;
- } else {
- waitForChildren.enabled = false;
- }
- }
- }
- Label {
- text: qsTr("Recommended to disable for launcher-games")
- wrapMode: Text.WordWrap
- width: parent.width
- leftPadding: 32
- topPadding: -8
- }
- CheckBox {
- id: waitForChildren
- text: qsTr("Wait for child processes")
- checked: shortcutInfo.waitForChildProcs
- onCheckedChanged: function(){
- shortcutInfo.waitForChildProcs = checked
- }
- }
- }
- Column {
- spacing: 2
- CheckBox {
- id: allowDesktopConfig
- text: qsTr("Allow desktop-config")
- checked: shortcutInfo.allowDesktopConfig
- onCheckedChanged: function(){
- shortcutInfo.allowDesktopConfig = checked
- }
- }
- Label {
- text: qsTr("Use desktop-config if launched application is not focused")
- leftPadding: 32
- topPadding: -8
- }
- }
}
Item {
width: 1
@@ -231,14 +183,17 @@ Item {
RowLayout {
id: launchlayout
spacing: 4
- width: parent.width
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 32
+ anchors.rightMargin: 32
Image {
id: maybeIcon
source: shortcutInfo.icon
? shortcutInfo.icon.endsWith(".exe")
? "image://exe/" + shortcutInfo.icon
: "file:///" + shortcutInfo.icon
- : null
+ : ''
Layout.preferredWidth: 48
Layout.preferredHeight: 48
visible: shortcutInfo.icon
@@ -267,8 +222,8 @@ Item {
id: pathInput
placeholderText: qsTr("...")
enabled: launchApp.checked
- text: shortcutInfo.launchPath || ""
- onTextChanged: shortcutInfo.launchPath = text
+ text: shortcutInfo.launch.launchPath || ""
+ onTextChanged: shortcutInfo.launch.launchPath = text
}
}
Button {
@@ -304,8 +259,8 @@ Item {
anchors.topMargin: 4
id: argsInput
enabled: launchApp.checked
- text: shortcutInfo.launchAppArgs
- onTextChanged: shortcutInfo.launchAppArgs = text
+ text: shortcutInfo.launch.launchAppArgs
+ onTextChanged: shortcutInfo.launch.launchAppArgs = text
}
}
}
@@ -315,183 +270,467 @@ Item {
width: 1
height: 8
}
- Row {
- spacing: 16
- width: parent.width
- RPane {
- width: parent.width / 2 - 8
- height: 264
- radius: 4
- Material.elevation: 32
- bgOpacity: 0.97
+ CollapsiblePane {
+ radius: 4
+ Material.elevation: 32
+ bgOpacity: 0.97
+ title: qsTr("Advanced")
+ content:
+ Column {
+ spacing: 16
- Column {
- spacing: 2
+ RPane {
width: parent.width
- Row {
- CheckBox {
- id: hideDevices
- text: qsTr("Hide (Real) Controllers")
- checked: shortcutInfo.hideDevices
- onCheckedChanged: shortcutInfo.hideDevices = checked
- }
- RoundButton {
- onClicked: () => {
- helpInfoDialog.titleText = qsTr("Hide (Real) Controllers")
- helpInfoDialog.text =
- qsTr("Hides real game controllers from the system\nThis may prevent doubled inputs")
- + "\n"
- + qsTr("You can change this setting and which devices are hidden in the GlosSI overlay")
-
- helpInfoDialog.open()
+ radius: 4
+ Material.elevation: 32
+ bgOpacity: 0.97
+ height: advancedLaunchCol.height + 24
+ Column {
+ id: advancedLaunchCol
+ spacing: 4
+ height: advancedLaunchedRow.height
+ Row {
+ id: advancedLaunchedRow
+ spacing: 32
+ width: parent.width
+ height: closeOnExitCol.height
+ Column {
+ id: closeOnExitCol
+ spacing: 2
+ CheckBox {
+ id: closeOnExit
+ text: qsTr("Close when launched app quits")
+ checked: shortcutInfo.launch.closeOnExit
+ onCheckedChanged: function() {
+ shortcutInfo.launch.closeOnExit = checked
+ if (checked) {
+ waitForChildren.enabled = true;
+ } else {
+ waitForChildren.enabled = false;
+ }
+ }
+ }
+ Label {
+ text: qsTr("Recommended to disable for launcher-games")
+ wrapMode: Text.WordWrap
+ width: parent.width
+ leftPadding: 32
+ topPadding: -8
+ }
+ CheckBox {
+ id: waitForChildren
+ text: qsTr("Wait for child processes")
+ checked: shortcutInfo.launch.waitForChildProcs
+ onCheckedChanged: function(){
+ shortcutInfo.launch.waitForChildProcs = checked
+ }
+ }
}
- width: 48
- height: 48
- Material.elevation: 0
- anchors.topMargin: 16
- Image {
- anchors.centerIn: parent
- source: "qrc:/svg/help_outline_white_24dp.svg"
- width: 24
- height: 24
+ Column {
+ spacing: 2
+ CheckBox {
+ id: allowDesktopConfig
+ text: qsTr("Allow desktop-config")
+ checked: shortcutInfo.controller.allowDesktopConfig
+ onCheckedChanged: function(){
+ shortcutInfo.controller.allowDesktopConfig = checked
+ }
+ }
+ Label {
+ text: qsTr("Allow desktop-config if launched application is not focused")
+ leftPadding: 32
+ topPadding: -8
+ }
}
}
}
- Item {
- width: 1
- height: 4
- }
- Row {
- CheckBox {
- id: realDeviceIds
- text: qsTr("Use real device (USB)-IDs")
- checked: shortcutInfo.realDeviceIds
- onCheckedChanged: shortcutInfo.realDeviceIds = checked
- }
- RoundButton {
- onClicked: () => {
- helpInfoDialog.titleText = qsTr("Use real device (USB)-IDs")
- helpInfoDialog.text =
- qsTr("Only enable if input's are not recognized by the game")
- + "\n"
- + qsTr("If enabled, device-hiding won't work.\nUse the \"Max. Controller count\" setting!")
-
- helpInfoDialog.open()
+ }
+
+ Row {
+ spacing: 16
+ width: parent.width
+
+ RPane {
+ width: parent.width / 2 - 8
+ height: 248
+ radius: 4
+ Material.elevation: 32
+ bgOpacity: 0.97
+
+ Column {
+ spacing: 0
+ width: parent.width
+ Row {
+ CheckBox {
+ id: hideDevices
+ text: qsTr("Hide (Real) Controllers")
+ checked: shortcutInfo.devices.hideDevices
+ onCheckedChanged: shortcutInfo.devices.hideDevices = checked
+ }
+ RoundButton {
+ onClicked: () => {
+ helpInfoDialog.titleText = qsTr("Hide (Real) Controllers")
+ helpInfoDialog.text =
+ qsTr("Hides real game controllers from the system\nThis may prevent doubled inputs")
+ + "\n"
+ + qsTr("You can change this setting and which devices are hidden in the GlosSI overlay")
+
+ helpInfoDialog.open()
+ }
+ width: 48
+ height: 48
+ Material.elevation: 0
+ anchors.topMargin: 16
+ Image {
+ anchors.centerIn: parent
+ source: "qrc:/svg/help_outline_white_24dp.svg"
+ width: 24
+ height: 24
+ }
+ }
}
- width: 48
- height: 48
- Material.elevation: 0
- anchors.topMargin: 16
- Image {
- anchors.centerIn: parent
- source: "qrc:/svg/help_outline_white_24dp.svg"
- width: 24
- height: 24
+ Item {
+ width: 1
+ height: 4
}
- }
- }
- Item {
- width: 1
- height: 4
- }
- Row {
- CheckBox {
- id: emulateDS4
- text: qsTr("Emulate DS4")
- checked: shortcutInfo.emulateDS4
- onCheckedChanged: shortcutInfo.emulateDS4 = checked
- }
- RoundButton {
- onClicked: () => {
- helpInfoDialog.titleText = qsTr("Emulate DS4")
- helpInfoDialog.text =
- qsTr("Instead of X360 Pad")
- + "\n"
- + qsTr("Disable \"Playstation Configuration support\" in Steam")
- helpInfoDialog.open()
+ Row {
+ CheckBox {
+ id: realDeviceIds
+ text: qsTr("Use real device (USB)-IDs")
+ checked: shortcutInfo.devices.realDeviceIds
+ onCheckedChanged: shortcutInfo.devices.realDeviceIds = checked
+ }
+ RoundButton {
+ onClicked: () => {
+ helpInfoDialog.titleText = qsTr("Use real device (USB)-IDs")
+ helpInfoDialog.text =
+ qsTr("Only enable if input's are not recognized by the game")
+ + "\n"
+ + qsTr("If enabled, device-hiding won't work.\nUse the \"Max. Controller count\" setting!")
+
+ helpInfoDialog.open()
+ }
+ width: 48
+ height: 48
+ Material.elevation: 0
+ anchors.topMargin: 16
+ Image {
+ anchors.centerIn: parent
+ source: "qrc:/svg/help_outline_white_24dp.svg"
+ width: 24
+ height: 24
+ }
+ }
+ }
+ Item {
+ width: 1
+ height: 4
+ }
+ Row {
+ CheckBox {
+ id: emulateDS4
+ text: qsTr("Emulate DS4")
+ checked: shortcutInfo.controller.emulateDS4 || false
+ onCheckedChanged: shortcutInfo.controller.emulateDS4 = checked
+ }
+ RoundButton {
+ onClicked: () => {
+ helpInfoDialog.titleText = qsTr("Emulate DS4")
+ helpInfoDialog.text =
+ qsTr("Emulates a DS4 instead of X360 Pad")
+ + "\n"
+ qsTr("for usage with, for example, PSNow")
+ + "\n"
+ + qsTr("If enabled you have to disable \"Playstation Configuration support\" in Steam")
+ helpInfoDialog.open()
+ }
+ width: 48
+ height: 48
+ Material.elevation: 0
+ anchors.topMargin: 16
+ Image {
+ anchors.centerIn: parent
+ source: "qrc:/svg/help_outline_white_24dp.svg"
+ width: 24
+ height: 24
+ }
+ }
}
- width: 48
- height: 48
- Material.elevation: 0
- anchors.topMargin: 16
- Image {
- anchors.centerIn: parent
- source: "qrc:/svg/help_outline_white_24dp.svg"
- width: 24
- height: 24
+ Item {
+ width: 1
+ height: 4
+ }
+ Row {
+ leftPadding: 16
+ Label {
+ text: qsTr("Max. emulated controllers")
+ topPadding: 16
+ }
+ SpinBox {
+ id: maxControllersSpinBox
+ width: 128
+ editable: true
+ value: shortcutInfo.controller.maxControllers
+ from: 0
+ to: 4
+ onValueChanged: shortcutInfo.controller.maxControllers = value
+ }
+ RoundButton {
+ onClicked: () => {
+ helpInfoDialog.titleText = qsTr("Max. emulated controllers")
+ helpInfoDialog.text =
+ qsTr("GlosSI will only provide [NUMBER] of controllers")
+ + "\n"
+ + qsTr("Required to set to actually connected controller count when using \"real device IDs\" ")
+ helpInfoDialog.open()
+ }
+ width: 48
+ height: 48
+ Material.elevation: 0
+ anchors.topMargin: 16
+ Image {
+ anchors.centerIn: parent
+ source: "qrc:/svg/help_outline_white_24dp.svg"
+ width: 24
+ height: 24
+ }
+ }
}
}
}
- Item {
- width: 1
- height: 4
- }
- Row {
- leftPadding: 16
- Label {
- text: qsTr("Max. emulated controllers")
- topPadding: 16
- }
- SpinBox {
- id: maxControllersSpinBox
- width: 128
- value: 4
- from: 0
- to: 4
- onValueChanged: shortcutInfo.maxControllers = value
+ RPane {
+ width: parent.width / 2 - 8
+ height: 248
+ radius: 4
+ Material.elevation: 32
+ bgOpacity: 0.97
+ Column {
+ spacing: 0
+ width: parent.width
+ Row {
+ CheckBox {
+ id: windowMode
+ text: qsTr("Steam/GlosSI overlay as separate window")
+ checked: shortcutInfo.window.windowMode
+ onCheckedChanged: shortcutInfo.window.windowMode = checked
+ }
+ RoundButton {
+ onClicked: () => {
+ helpInfoDialog.titleText = qsTr("Steam/GlosSI overlay as separate window")
+ helpInfoDialog.text =
+ qsTr("Doesn't show overlay on top, but as separate window")
+ + "\n"
+ + qsTr("Use if blackscreen-issues are encountered.")
+
+ helpInfoDialog.open()
+ }
+ width: 48
+ height: 48
+ Material.elevation: 0
+ anchors.topMargin: 16
+ Image {
+ anchors.centerIn: parent
+ source: "qrc:/svg/help_outline_white_24dp.svg"
+ width: 24
+ height: 24
+ }
+ }
+ }
+ Item {
+ width: 1
+ height: 4
+ }
+
+ Row {
+ CheckBox {
+ id: disableOverlayCheckbox
+ text: qsTr("Disable Steam/GlosSI overlay")
+ checked: shortcutInfo.window.disableOverlay
+ onCheckedChanged: shortcutInfo.window.disableOverlay = checked
+ }
+ RoundButton {
+ onClicked: () => {
+ helpInfoDialog.titleText = qsTr("Disable Steam/GlosSI overlay")
+ helpInfoDialog.text =
+ qsTr("Only controller emulation - No extra window")
+ + "\n"
+ + qsTr("Might help with Steam remote play.")
+
+ helpInfoDialog.open()
+ }
+ width: 48
+ height: 48
+ Material.elevation: 0
+ anchors.topMargin: 16
+ Image {
+ anchors.centerIn: parent
+ source: "qrc:/svg/help_outline_white_24dp.svg"
+ width: 24
+ height: 24
+ }
+ }
+ }
+ Item {
+ width: 1
+ height: 4
+ }
+ Row {
+ leftPadding: 16
+ Label {
+ text: qsTr("GlosSI-Overlay scale")
+ topPadding: 16
+ }
+ SpinBox {
+ id: scaleSpinBox
+ width: 172
+ from: -100
+ value: shortcutInfo.window.scale * 100 || 0
+ to: 350
+ stepSize: 10
+ editable: true
+
+ property int decimals: 2
+ property real realValue: value / 100
+
+ validator: DoubleValidator {
+ bottom: Math.min(scaleSpinBox.from, scaleSpinBox.to)
+ top: Math.max(scaleSpinBox.from, scaleSpinBox.to)
+ }
+
+ textFromValue: function(value, locale) {
+ return Number(value / 100).toLocaleString(locale, 'f', scaleSpinBox.decimals)
+ }
+
+ valueFromText: function(text, locale) {
+ return Number.fromLocaleString(locale, text) * 100
+ }
+ onValueChanged: function() {
+ if (value <= 0) {
+ shortcutInfo.window.scale = null
+ return
+ }
+ shortcutInfo.window.scale = value / 100
+ }
+ }
+ RoundButton {
+ onClicked: () => {
+ helpInfoDialog.titleText = qsTr("GloSI-Overlay scaling")
+ helpInfoDialog.text =
+ qsTr("Scales the elements of the GlosSI-Overlay (not Steam Overlay)")
+ + "\n"
+ + qsTr(" <= 0.0 to use auto-detection")
+
+ helpInfoDialog.open()
+ }
+ width: 48
+ height: 48
+ Material.elevation: 0
+ anchors.topMargin: 16
+ Image {
+ anchors.centerIn: parent
+ source: "qrc:/svg/help_outline_white_24dp.svg"
+ width: 24
+ height: 24
+ }
+ }
+ }
+ Item {
+ width: 1
+ height: 4
+ }
+ Row {
+ leftPadding: 16
+ Label {
+ text: qsTr("Max. Overlay FPS")
+ topPadding: 16
+ }
+ SpinBox {
+ id: maxFPSSpinBox
+ width: 172
+ from: -1
+ value: shortcutInfo.window.maxFps || 0
+ to: 244
+ stepSize: 5
+ editable: true
+
+ onValueChanged: function() {
+ if (value <= 0) {
+ shortcutInfo.window.maxFps = null
+ return
+ }
+ shortcutInfo.window.maxFps = value
+ }
+ }
+ RoundButton {
+ onClicked: () => {
+ helpInfoDialog.titleText = qsTr("Max. Overlay FPS")
+ helpInfoDialog.text =
+ qsTr("Restricts the FPS of the overlay to the given value")
+ + "\n"
+ + qsTr(" <= 0.0 to use screen refresh rate")
+
+ helpInfoDialog.open()
+ }
+ width: 48
+ height: 48
+ Material.elevation: 0
+ anchors.topMargin: 16
+ Image {
+ anchors.centerIn: parent
+ source: "qrc:/svg/help_outline_white_24dp.svg"
+ width: 24
+ height: 24
+ }
+ }
+ }
}
}
}
- }
- RPane {
- width: parent.width / 2 - 8
- height: 264
- radius: 4
- Material.elevation: 32
- bgOpacity: 0.97
- Column {
- spacing: 2
+
+ RPane {
width: parent.width
- CheckBox {
- id: windowMode
- text: qsTr("Steam/GlosSI overlay as separate window")
- checked: shortcutInfo.windowMode
- onCheckedChanged: shortcutInfo.windowMode = checked
- }
- Label {
- text: qsTr("Doesn't show overlay on top, but as separate window")
- wrapMode: Text.WordWrap
- width: parent.width
- leftPadding: 32
- topPadding: -8
- }
- Label {
- text: qsTr("Use if blackscreen-issues are encountered.")
- wrapMode: Text.WordWrap
- width: parent.width
- leftPadding: 32
- }
- Item {
- width: 1
- height: 4
- }
- CheckBox {
- id: disableOverlayCheckbox
- text: qsTr("Disable Steam/GlosSI overlay")
- checked: shortcutInfo.disableOverlay
- onCheckedChanged: shortcutInfo.disableOverlay = checked
- }
- Label {
- text: qsTr("Only controller emulation - No extra window")
- wrapMode: Text.WordWrap
- width: parent.width
- leftPadding: 32
- topPadding: -8
+ radius: 4
+ Material.elevation: 32
+ bgOpacity: 0.97
+ Column {
+ spacing: 4
+ Row {
+ Row {
+ CheckBox {
+ id: extendedLogging
+ text: qsTr("Extended Logging")
+ checked: shortcutInfo.extendedLogging
+ onCheckedChanged: shortcutInfo.extendedLogging = checked
+ }
+ // RoundButton {
+ // onClicked: () => {
+ // helpInfoDialog.titleText = qsTr("Hide (Real) Controllers")
+ // helpInfoDialog.text =
+ // qsTr("Hides real game controllers from the system\nThis may prevent doubled inputs")
+ // + "\n"
+ // + qsTr("You can change this setting and which devices are hidden in the GlosSI overlay")
+
+ // helpInfoDialog.open()
+ // }
+ // width: 48
+ // height: 48
+ // Material.elevation: 0
+ // anchors.topMargin: 16
+ // Image {
+ // anchors.centerIn: parent
+ // source: "qrc:/svg/help_outline_white_24dp.svg"
+ // width: 24
+ // height: 24
+ // }
+ // }
+ }
+ }
}
}
}
}
+
Item {
id: bottomspacing
width: 1
diff --git a/GlosSIConfig/qml/SteamInputXboxDisabledDialog.qml b/GlosSIConfig/qml/SteamInputXboxDisabledDialog.qml
new file mode 100644
index 0000000..7e2350c
--- /dev/null
+++ b/GlosSIConfig/qml/SteamInputXboxDisabledDialog.qml
@@ -0,0 +1,111 @@
+/*
+Copyright 2021-2022 Peter Repukat - FlatspotSoftware
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+import QtQuick 6.2
+import QtQuick.Controls 6.2
+import QtQuick.Layouts 6.2
+import QtQuick.Controls.Material 6.2
+
+Dialog {
+ id: dlg
+ anchors.centerIn: parent
+
+ signal confirmed(var param)
+
+ visible: false
+ modal: true
+ dim: true
+ parent: Overlay.overlay
+ Overlay.modal: Rectangle {
+ color: Qt.rgba(0,0,0,0.4)
+ opacity: backdropOpacity
+ Behavior on opacity {
+ NumberAnimation {
+ duration: 300
+ }
+ }
+ }
+ property real backdropOpacity: 1.0
+
+ enter: Transition {
+ NumberAnimation{target: content; property: "y"; from: parent.height; to: 16; duration: 300; easing.type: Easing.OutQuad }
+ NumberAnimation{target: background; property: "y"; from: parent.height; to: 0; duration: 300; easing.type: Easing.OutQuad }
+ NumberAnimation{target: dlg; property: "backdropOpacity"; from: 0; to: 1; duration: 300; easing.type: Easing.OutQuad }
+ }
+
+ exit: Transition {
+ NumberAnimation{target: content; property: "y"; from: 16; to: parent.height; duration: 300; easing.type: Easing.InQuad }
+ NumberAnimation{target: background; property: "y"; from: 0; to: parent.height; duration: 300; easing.type: Easing.InQuad }
+ NumberAnimation{target: dlg; property: "backdropOpacity"; from: 1; to: 0; duration: 300; easing.type: Easing.InQuad }
+ }
+
+ background: RPane {
+ id: background
+ radius: 4
+ Material.elevation: 64
+ bgOpacity: 0.97
+ }
+
+ contentItem: Item {
+ id: content
+ clip: true
+ Column {
+ spacing: 4
+ bottomPadding: 96
+ Label {
+ id: titlelabel
+ text: qsTr("Steam Input Xbox support disabled")
+ font.pixelSize: 24
+ font.bold: true
+ }
+ Item {
+ height: 32
+ }
+ Label {
+ text: qsTr("Please enable \"Xbox configuration support\" in Steams controller settings.\n\nGlosSI cannot function properly with this setting disabled\n\nEnable now?")
+ wrapMode: Text.WordWrap
+ width: parent.width
+ }
+ Row {
+ anchors.right: parent.right
+ anchors.topMargin: 16
+ anchors.rightMargin: 2
+ spacing: 8
+ Button {
+ id: noBtn
+ text: qsTr("No")
+ onClicked: dlg.close()
+ }
+ Button {
+ id: yesBtn
+ text: qsTr("Yes")
+ onClicked: function() {
+ uiModel.enableSteamInputXboxSupport();
+ dlg.close();
+ steamChangedDialog2.open();
+ }
+ }
+ }
+ }
+ InfoDialog {
+ id: steamChangedDialog2
+ titleText: qsTr("Steam config changed!")
+ text: qsTr("Please restart Steam to reload your changes!")
+ onConfirmed: function (callback) {
+ callback();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/GlosSIConfig/qml/SteamNotFoundDialog.qml b/GlosSIConfig/qml/SteamNotFoundDialog.qml
new file mode 100644
index 0000000..3b254e6
--- /dev/null
+++ b/GlosSIConfig/qml/SteamNotFoundDialog.qml
@@ -0,0 +1,92 @@
+/*
+Copyright 2021-2022 Peter Repukat - FlatspotSoftware
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+import QtQuick 6.2
+import QtQuick.Controls 6.2
+import QtQuick.Layouts 6.2
+import QtQuick.Controls.Material 6.2
+
+Dialog {
+ id: dlg
+ anchors.centerIn: parent
+
+ signal confirmed(var param)
+
+ visible: false
+ modal: true
+ dim: true
+ parent: Overlay.overlay
+ Overlay.modal: Rectangle {
+ color: Qt.rgba(0,0,0,0.4)
+ opacity: backdropOpacity
+ Behavior on opacity {
+ NumberAnimation {
+ duration: 300
+ }
+ }
+ }
+ property real backdropOpacity: 1.0
+
+ enter: Transition {
+ NumberAnimation{target: content; property: "y"; from: parent.height; to: 16; duration: 300; easing.type: Easing.OutQuad }
+ NumberAnimation{target: background; property: "y"; from: parent.height; to: 0; duration: 300; easing.type: Easing.OutQuad }
+ NumberAnimation{target: dlg; property: "backdropOpacity"; from: 0; to: 1; duration: 300; easing.type: Easing.OutQuad }
+ }
+
+ exit: Transition {
+ NumberAnimation{target: content; property: "y"; from: 16; to: parent.height; duration: 300; easing.type: Easing.InQuad }
+ NumberAnimation{target: background; property: "y"; from: 0; to: parent.height; duration: 300; easing.type: Easing.InQuad }
+ NumberAnimation{target: dlg; property: "backdropOpacity"; from: 1; to: 0; duration: 300; easing.type: Easing.InQuad }
+ }
+
+ background: RPane {
+ id: background
+ radius: 4
+ Material.elevation: 64
+ bgOpacity: 0.97
+ }
+
+ contentItem: Item {
+ id: content
+ clip: true
+ Column {
+ spacing: 4
+ bottomPadding: 24
+ Label {
+ id: titlelabel
+ text: qsTr("Could not detect Steam")
+ font.pixelSize: 24
+ font.bold: true
+ }
+ Item {
+ height: 24
+ }
+ Label {
+ text: qsTr("Please make sure that Steam is running and you are logged in.")
+ wrapMode: Text.WordWrap
+ width: parent.width
+ }
+
+ Button {
+ anchors.right: parent.right
+ anchors.top: listview.bottom
+ anchors.topMargin: 16
+ anchors.rightMargin: 2
+ text: qsTr("Ok")
+ onClicked: dlg.close()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/GlosSIConfig/qml/main.qml b/GlosSIConfig/qml/main.qml
index 3322295..3be4d08 100644
--- a/GlosSIConfig/qml/main.qml
+++ b/GlosSIConfig/qml/main.qml
@@ -45,6 +45,16 @@ Window {
property bool steamShortcutsChanged: false
+ Component.onCompleted: function() {
+ if (!uiModel.foundSteam) {
+ steamNotFoundDialog.open();
+ return;
+ }
+ if (!uiModel.steamInputXboxSupportEnabled) {
+ steamXboxDisabledDialog.open();
+ }
+ }
+
Image {
anchors.top: parent.top
anchors.left: parent.left
@@ -55,10 +65,18 @@ Window {
opacity: 0.033
}
+ SteamNotFoundDialog {
+ id: steamNotFoundDialog
+ }
+ SteamInputXboxDisabledDialog {
+ id: steamXboxDisabledDialog
+ }
+
+
InfoDialog {
id: steamChangedDialog
- titleText: qsTr("Attention!")
- text: qsTr("Please restart Steam to reload your changes!")
+ titleText: qsTr("Steam shortcuts changed!")
+ text: qsTr("Please restart Steam to reload your changes")
onConfirmed: function (callback) {
callback();
}
diff --git a/GlosSIConfig/svg/expand_more_white_24dp.svg b/GlosSIConfig/svg/expand_more_white_24dp.svg
new file mode 100644
index 0000000..9c420ca
--- /dev/null
+++ b/GlosSIConfig/svg/expand_more_white_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/GlosSITarget/.clang-format b/GlosSITarget/.clang-format
index b5e5b98..1c78926 100644
--- a/GlosSITarget/.clang-format
+++ b/GlosSITarget/.clang-format
@@ -1,3 +1,4 @@
+BasedOnStyle: LLVM
UseTab: false
IndentWidth: 4
BreakBeforeBraces: "Stroustrup"
diff --git a/GlosSITarget/AppLauncher.cpp b/GlosSITarget/AppLauncher.cpp
index 7bc3f25..e660331 100644
--- a/GlosSITarget/AppLauncher.cpp
+++ b/GlosSITarget/AppLauncher.cpp
@@ -77,6 +77,9 @@ void AppLauncher::update()
}
if (Settings::launch.waitForChildProcs) {
std::erase_if(pids_, [](auto pid) {
+ if (pid == 0) {
+ return true;
+ }
const auto running = IsProcessRunning(pid);
if (!running)
spdlog::trace("Child process with PID \"{}\" died", pid);
diff --git a/GlosSITarget/HidHide.cpp b/GlosSITarget/HidHide.cpp
index 52bf1bf..1655e32 100644
--- a/GlosSITarget/HidHide.cpp
+++ b/GlosSITarget/HidHide.cpp
@@ -102,9 +102,19 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path)
whitelist.push_back(path);
}
}
+ if (Settings::extendedLogging) {
+ std::ranges::for_each(whitelist, [](const auto& exe) {
+ spdlog::trace(L"Whitelisted executable: {}", exe);
+ });
+ }
setAppWhiteList(whitelist);
avail_devices_ = GetHidDeviceList();
+ if (Settings::extendedLogging) {
+ std::ranges::for_each(avail_devices_, [](const auto& dev) {
+ spdlog::trace(L"AvailDevice device: {}", dev.name);
+ });
+ }
blacklisted_devices_ = getBlackListDevices();
for (const auto& dev : avail_devices_) {
@@ -112,11 +122,11 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path)
return blackdev == dev.device_instance_path || blackdev == dev.base_container_device_instance_path;
})) {
// Valve emulated gamepad PID/VID; mirrord by ViGEm
- if (!(dev.vendor_id == 0x28de && dev.product_id == 0x11FF)) {
+ if (!(dev.vendor_id == 0x28de && (dev.product_id == 0x11FF || dev.product_id == 0x028E))) {
if (!dev.device_instance_path.empty()) {
blacklisted_devices_.push_back(dev.device_instance_path);
}
- if (!dev.device_instance_path.empty()) {
+ if (!dev.base_container_device_instance_path.empty()) {
blacklisted_devices_.push_back(dev.base_container_device_instance_path);
}
}
@@ -127,6 +137,11 @@ void HidHide::hideDevices(const std::filesystem::path& steam_path)
setBlacklistDevices(blacklisted_devices_);
setActive(true);
spdlog::info("Hid Gaming Devices; Enabling Overlay element...");
+ if (Settings::extendedLogging) {
+ std::ranges::for_each(blacklisted_devices_, [](const auto& dev) {
+ spdlog::trace(L"Blacklisted device: {}", dev);
+ });
+ }
enableOverlayElement();
}
closeCtrlDevice();
@@ -148,7 +163,7 @@ void HidHide::UnPatchValveHooks()
// need to load addresses that way.. Otherwise we land before some jumps...
if (const auto setupapidll = GetModuleHandle(L"setupapi.dll")) {
UnPatchHook("SetupDiEnumDeviceInfo", setupapidll);
- //UnPatchHook("SetupDiGetClassDevsW", setupapidll);
+ UnPatchHook("SetupDiGetClassDevsW", setupapidll);
}
if (const auto hiddll = GetModuleHandle(L"hid.dll")) {
for (const auto& name : ORIGINAL_BYTES | std::views::keys) {
@@ -182,56 +197,70 @@ void HidHide::UnPatchHook(const std::string& name, HMODULE module)
void HidHide::enableOverlayElement()
{
- Overlay::AddOverlayElem([this](bool window_has_focus) {
- if (window_has_focus && (overlay_elem_clock_.getElapsedTime().asSeconds() > OVERLAY_ELEM_REFRESH_INTERVAL_S_)) {
- openCtrlDevice();
- bool hidehide_state_store = hidhide_active_;
- if (hidhide_active_) {
- setActive(false);
- }
- avail_devices_ = GetHidDeviceList();
- blacklisted_devices_ = getBlackListDevices();
- if (hidehide_state_store) {
- setActive(true);
- }
- closeCtrlDevice();
- overlay_elem_clock_.restart();
- }
- ImGui::SetNextWindowPos({650, 100}, ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSizeConstraints({400, 270}, {1000, 1000});
- ImGui::Begin("Hidden Devices");
- ImGui::BeginChild("Inner", {0.f, ImGui::GetItemRectSize().y - 64}, true);
- std::ranges::for_each(avail_devices_, [this](const auto& device) {
- std::string label = (std::string(device.name.begin(), std::ranges::find(device.name, L'\0')) + "##" + std::string(device.device_instance_path.begin(), device.device_instance_path.end()));
- const auto findDeviceFn = [&device](const auto& blackdev) {
- return device.device_instance_path == blackdev || device.base_container_device_instance_path == blackdev;
- };
- bool hidden = std::ranges::find_if(blacklisted_devices_, findDeviceFn) != blacklisted_devices_.end();
- if (ImGui::Checkbox(label.data(), &hidden)) {
+ Overlay::AddOverlayElem([this](bool window_has_focus, ImGuiID dockspace_id) {
+ ImGui::SetNextWindowDockID(dockspace_id, ImGuiCond_FirstUseEver);
+ if (ImGui::Begin("Hidden Devices")) {
+ if (window_has_focus && (overlay_elem_clock_.getElapsedTime().asSeconds() > OVERLAY_ELEM_REFRESH_INTERVAL_S_)) {
+ // UnPatchValveHooks();
openCtrlDevice();
- if (hidden) {
- if (std::ranges::none_of(blacklisted_devices_, findDeviceFn)) {
- if (!device.device_instance_path.empty()) {
- blacklisted_devices_.push_back(device.device_instance_path);
- }
- if (!device.device_instance_path.empty()) {
- blacklisted_devices_.push_back(device.base_container_device_instance_path);
+ bool hidehide_state_store = hidhide_active_;
+ if (Settings::extendedLogging) {
+ spdlog::debug("Refreshing HID devices");
+ }
+ if (hidhide_active_) {
+ setActive(false);
+ }
+ avail_devices_ = GetHidDeviceList();
+ if (Settings::extendedLogging) {
+ std::ranges::for_each(avail_devices_, [](const auto& dev) {
+ spdlog::trace(L"AvailDevice device: {}", dev.name);
+ });
+ }
+ blacklisted_devices_ = getBlackListDevices();
+ if (hidehide_state_store) {
+ setActive(true);
+ }
+ closeCtrlDevice();
+ overlay_elem_clock_.restart();
+ }
+ ImGui::BeginChild("Inner", {0.f, ImGui::GetItemRectSize().y - 64}, true);
+ std::ranges::for_each(avail_devices_, [this](const auto& device) {
+ std::string label = (std::string(device.name.begin(), std::ranges::find(device.name, L'\0')) + "##" + std::string(device.device_instance_path.begin(), device.device_instance_path.end()));
+ const auto findDeviceFn = [&device](const auto& blackdev) {
+ return device.device_instance_path == blackdev || device.base_container_device_instance_path == blackdev;
+ };
+ bool hidden = std::ranges::find_if(blacklisted_devices_, findDeviceFn) != blacklisted_devices_.end();
+ if (ImGui::Checkbox(label.data(), &hidden)) {
+ openCtrlDevice();
+ if (hidden) {
+ if (std::ranges::none_of(blacklisted_devices_, findDeviceFn)) {
+ if (!device.device_instance_path.empty()) {
+ blacklisted_devices_.push_back(device.device_instance_path);
+ }
+ if (!device.device_instance_path.empty()) {
+ blacklisted_devices_.push_back(device.base_container_device_instance_path);
+ }
}
}
+ else {
+ blacklisted_devices_.erase(std::ranges::remove_if(blacklisted_devices_, findDeviceFn).begin(),
+ blacklisted_devices_.end());
+ }
+ setBlacklistDevices(blacklisted_devices_);
+ if (Settings::extendedLogging) {
+ std::ranges::for_each(blacklisted_devices_, [](const auto& dev) {
+ spdlog::trace(L"Blacklisted device: {}", dev);
+ });
+ }
+ closeCtrlDevice();
}
- else {
- blacklisted_devices_.erase(std::ranges::remove_if(blacklisted_devices_, findDeviceFn).begin(),
- blacklisted_devices_.end());
- }
- setBlacklistDevices(blacklisted_devices_);
+ });
+ ImGui::EndChild();
+ if (ImGui::Checkbox("Devices Hidden", &hidhide_active_)) {
+ openCtrlDevice();
+ setActive(hidhide_active_);
closeCtrlDevice();
}
- });
- ImGui::EndChild();
- if (ImGui::Checkbox("Devices Hidden", &hidhide_active_)) {
- openCtrlDevice();
- setActive(hidhide_active_);
- closeCtrlDevice();
}
ImGui::End();
});
@@ -316,6 +345,9 @@ void HidHide::setActive(bool active)
return;
}
hidhide_active_ = active;
+ if (Settings::extendedLogging) {
+ spdlog::debug("HidHide State set to {}", active);
+ }
}
DWORD HidHide::getRequiredOutputBufferSize(IOCTL_TYPE type) const
diff --git a/GlosSITarget/InputRedirector.cpp b/GlosSITarget/InputRedirector.cpp
index 2645b10..498ce05 100644
--- a/GlosSITarget/InputRedirector.cpp
+++ b/GlosSITarget/InputRedirector.cpp
@@ -53,9 +53,8 @@ void InputRedirector::run()
max_controller_count_ = Settings::controller.maxControllers;
use_real_vid_pid_ = Settings::devices.realDeviceIds;
#ifdef _WIN32
- Overlay::AddOverlayElem([this](bool window_has_focus) {
- ImGui::SetNextWindowPos({650, 450}, ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSizeConstraints({400, 270}, {1000, 1000});
+ Overlay::AddOverlayElem([this](bool window_has_focus, ImGuiID dockspace_id) {
+ ImGui::SetNextWindowDockID(dockspace_id, ImGuiCond_FirstUseEver);
ImGui::Begin("Controller Emulation");
int countcopy = max_controller_count_;
ImGui::Text("Max. controller count");
@@ -163,7 +162,11 @@ void InputRedirector::runLoop()
// Multiple controllers can be worked around with by setting max count.
if (!use_real_vid_pid_) {
vigem_target_set_vid(vt_pad_[i], 0x28de); //VALVE_DIRECTINPUT_GAMEPAD_VID
- // vigem_target_set_pid(vt_pad_[i], 0x11FF); //VALVE_DIRECTINPUT_GAMEPAD_PID
+ //vigem_target_set_pid(vt_pad_[i], 0x11FF); //VALVE_DIRECTINPUT_GAMEPAD_PID
+ vigem_target_set_pid(vt_pad_[i], 0x028E); // XBOX 360 Controller
+ } else {
+ vigem_target_set_vid(vt_pad_[i], 0x045E); // MICROSOFT
+ vigem_target_set_pid(vt_pad_[i], 0x028E); // XBOX 360 Controller
}
// TODO: MAYBE!: In a future version, use something like OpenXInput
//and filter out emulated controllers to support a greater amount of controllers simultaneously
@@ -178,7 +181,11 @@ void InputRedirector::runLoop()
}
}
if (target_add_res == VIGEM_ERROR_NONE) {
- spdlog::info("Plugged in controller {}, {}", i, vigem_target_get_index(vt_pad_[i]));
+ spdlog::info("Plugged in controller {}, {}; VID: {:x}; PID: {:x}",
+ i,
+ vigem_target_get_index(vt_pad_[i]),
+ vigem_target_get_vid(vt_pad_[i]),
+ vigem_target_get_pid(vt_pad_[i]));
if (Settings::controller.emulateDS4) {
const auto callback_register_res = vigem_target_ds4_register_notification(
diff --git a/GlosSITarget/Overlay.cpp b/GlosSITarget/Overlay.cpp
index d317175..a952dcb 100644
--- a/GlosSITarget/Overlay.cpp
+++ b/GlosSITarget/Overlay.cpp
@@ -21,6 +21,7 @@ limitations under the License.
#include
#include "Roboto.h"
+#include "Settings.h"
Overlay::Overlay(
sf::RenderWindow& window,
@@ -37,12 +38,14 @@ Overlay::Overlay(
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
+
io.Fonts->Clear(); // clear fonts if you loaded some before (even if only default one was loaded)
auto fontconf = ImFontConfig{};
fontconf.FontDataOwnedByAtlas = false;
io.Fonts->AddFontFromMemoryTTF(Roboto_Regular_ttf.data(), Roboto_Regular_ttf.size(), 24, &fontconf);
- ImGui::SFML::UpdateFontTexture(); // important call: updates font texture
+ ImGui::SFML::UpdateFontTexture();
#ifdef _WIN32
auto config_path = std::filesystem::temp_directory_path()
@@ -55,6 +58,7 @@ Overlay::Overlay(
if (!std::filesystem::exists(config_path))
std::filesystem::create_directories(config_path);
config_path /= "imgui.ini";
+
// This assumes that char is utf8 and wchar_t is utf16, which is guaranteed on Windows.
config_file_name_ = std::wstring_convert>().to_bytes(config_path.wstring());
io.IniFilename = config_file_name_.data();
@@ -151,14 +155,31 @@ void Overlay::update()
{
ImGui::SFML::Update(window_, update_clock_.restart());
- showLogs();
+ showLogs(0);
+
if (enabled_ || force_enable_) {
+ // Create a DockSpace node where any window can be docked
+ ImGui::SetNextWindowSize({ImGui::GetMainViewport()->Size.x * 0.6f, ImGui::GetMainViewport()->Size.y * 0.7f}, ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowPos({ImGui::GetMainViewport()->Size.x * 0.25f, 100 }, ImGuiCond_FirstUseEver);
+ ImGui::Begin("GlosSI Settings");
+ if (Settings::settings_path_ != "") {
+ if (ImGui::Button("Save shortcut settings", {256, 32})) {
+ Settings::StoreSettings();
+ }
+ }
+ ImGuiID dockspace_id = ImGui::GetID("GlosSI-DockSpace");
+ ImGui::DockSpace(dockspace_id);
+
window_.clear(sf::Color(0, 0, 0, 128)); // make window slightly dim screen with overlay
- std::ranges::for_each(OVERLAY_ELEMS_, [this](const auto& elem) {
- elem.second(window_.hasFocus());
+
+
+ std::ranges::for_each(OVERLAY_ELEMS_, [this, &dockspace_id](const auto& elem) {
+ elem.second(window_.hasFocus(), dockspace_id);
});
+ ImGui::End();
+
// ImGui::ShowDemoWindow();
if (closeButton()) {
@@ -186,7 +207,7 @@ void Overlay::AddLog(const spdlog::details::log_msg& msg)
LOG_MSGS_.push_back({.time = msg.time, .level = msg.level, .payload = msg.payload.data()});
}
-int Overlay::AddOverlayElem(const std::function& elem_fn)
+int Overlay::AddOverlayElem(const std::function& elem_fn)
{
OVERLAY_ELEMS_.insert({overlay_element_id_, elem_fn});
// keep this non confusing, but longer...
@@ -200,20 +221,22 @@ void Overlay::RemoveOverlayElem(int id)
OVERLAY_ELEMS_.erase(id);
}
-void Overlay::showLogs()
+void Overlay::showLogs(ImGuiID dockspace_id)
{
std::vector logs;
if (!enabled_ && !log_expanded_) {
return;
}
+ bool logs_contain_warn_or_worse = false;
if (enabled_) {
logs = LOG_MSGS_;
}
else {
std::ranges::copy_if(LOG_MSGS_,
std::back_inserter(logs),
- [](const auto& log) {
- return (
+ [&logs_contain_warn_or_worse](const auto& log) {
+
+ const auto res = (
log.time.time_since_epoch() + std::chrono::seconds(
LOG_RETENTION_TIME_) >
std::chrono::system_clock::now().time_since_epoch())
@@ -221,9 +244,13 @@ void Overlay::showLogs()
&& (log.level > spdlog::level::debug)
#endif
;
+ if (res && log.level > spdlog::level::warn) {
+ logs_contain_warn_or_worse = true;
+ }
+ return res;
});
}
- if (logs.empty())
+ if (logs.empty() || ( !enabled_ && !logs_contain_warn_or_worse && time_since_start_clock_.getElapsedTime().asSeconds() > HIDE_NORMAL_LOGS_AFTER_S))
return;
ImGui::SetNextWindowSizeConstraints({150, 150}, {1000, window_.getSize().y - 250.f});
if (!enabled_) {
@@ -232,6 +259,9 @@ void Overlay::showLogs()
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar);
}
else {
+ //ImGui::SetNextWindowDockID(dockspace_id, ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowSize({ImGui::GetMainViewport()->Size.x * 0.2f, ImGui::GetMainViewport()->Size.y * 0.7f}, ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowPos({ImGui::GetMainViewport()->Size.x * 0.05f, 100}, ImGuiCond_FirstUseEver);
log_expanded_ = ImGui::Begin("Log");
}
if (log_expanded_) {
diff --git a/GlosSITarget/Overlay.h b/GlosSITarget/Overlay.h
index 46cda4f..1f0ebf1 100644
--- a/GlosSITarget/Overlay.h
+++ b/GlosSITarget/Overlay.h
@@ -38,7 +38,7 @@ class Overlay {
static void Shutdown();
static void AddLog(const spdlog::details::log_msg& msg);
- static int AddOverlayElem(const std::function& elem_fn);
+ static int AddOverlayElem(const std::function& elem_fn);
static void RemoveOverlayElem(int id);
private:
@@ -47,11 +47,12 @@ class Overlay {
bool enabled_ = true;
std::function on_close_;
std::function trigger_state_change_;
- void showLogs();
+ void showLogs(ImGuiID dockspace_id);
bool closeOverlayButton() const;
[[nodiscard]] bool closeButton() const;
bool force_enable_ = false;
bool log_expanded_ = true;
+ sf::Clock time_since_start_clock_;
struct Log {
std::chrono::system_clock::time_point time;
@@ -60,9 +61,10 @@ class Overlay {
};
static inline std::vector LOG_MSGS_;
static constexpr int LOG_RETENTION_TIME_ = 5;
+ static constexpr int HIDE_NORMAL_LOGS_AFTER_S = 20;
static inline int overlay_element_id_ = 0;
- static inline std::map> OVERLAY_ELEMS_;
+ static inline std::map> OVERLAY_ELEMS_;
#ifdef _WIN32
std::string config_file_name_;
diff --git a/GlosSITarget/ProcessPriority.h b/GlosSITarget/ProcessPriority.h
index 5357a77..60528e8 100644
--- a/GlosSITarget/ProcessPriority.h
+++ b/GlosSITarget/ProcessPriority.h
@@ -12,35 +12,41 @@ static int current_priority = HIGH_PRIORITY_CLASS;
inline void init()
{
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
+ spdlog::trace("Set process priority to HIGH_PRIORITY_CLASS");
- Overlay::AddOverlayElem([](bool window_has_focus) {
- ImGui::SetNextWindowPos({913, 418}, ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSizeConstraints({170, 325}, {1000, 1000});
+ Overlay::AddOverlayElem([](bool window_has_focus, ImGuiID dockspace_id) {
+ ImGui::SetNextWindowDockID(dockspace_id, ImGuiCond_FirstUseEver);
ImGui::Begin("Process Priority");
ImGui::Text("Might help with input-lag or bad game performance");
if (ImGui::RadioButton("Realtime", current_priority == REALTIME_PRIORITY_CLASS)) {
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
current_priority = REALTIME_PRIORITY_CLASS;
+ spdlog::trace("Set process priority to REALTIME_PRIORITY_CLASS");
}
if (ImGui::RadioButton("High", current_priority == HIGH_PRIORITY_CLASS)) {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
current_priority = HIGH_PRIORITY_CLASS;
+ spdlog::trace("Set process priority to HIGH_PRIORITY_CLASS");
}
if (ImGui::RadioButton("Above Normal", current_priority == ABOVE_NORMAL_PRIORITY_CLASS)) {
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
current_priority = ABOVE_NORMAL_PRIORITY_CLASS;
+ spdlog::trace("Set process priority to ABOVE_NORMAL_PRIORITY_CLASS");
}
if (ImGui::RadioButton("Normal", current_priority == NORMAL_PRIORITY_CLASS)) {
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
current_priority = NORMAL_PRIORITY_CLASS;
+ spdlog::trace("Set process priority to NORMAL_PRIORITY_CLASS");
}
if (ImGui::RadioButton("Below Normal", current_priority == BELOW_NORMAL_PRIORITY_CLASS)) {
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
current_priority = BELOW_NORMAL_PRIORITY_CLASS;
+ spdlog::trace("Set process priority to BELOW_NORMAL_PRIORITY_CLASS");
}
if (ImGui::RadioButton("Low", current_priority == IDLE_PRIORITY_CLASS)) {
SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
current_priority = IDLE_PRIORITY_CLASS;
+ spdlog::trace("Set process priority to IDLE_PRIORITY_CLASS");
}
ImGui::End();
});
diff --git a/GlosSITarget/Resource.rc b/GlosSITarget/Resource.rc
index e37e0b4..0bece18 100644
--- a/GlosSITarget/Resource.rc
+++ b/GlosSITarget/Resource.rc
@@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,0,7,1018000020006
- PRODUCTVERSION 0,0,7,1018000020006
+ FILEVERSION 0,0,8,1031000051035
+ PRODUCTVERSION 0,0,8,1031000051035
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -69,12 +69,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Peter Repukat - FlatspotSoftware"
VALUE "FileDescription", "GlosSI - SteamTarget"
- VALUE "FileVersion", "0.0.7.1-18-g0f2bac6"
+ VALUE "FileVersion", "0.0.8.1-31-gda51d35"
VALUE "InternalName", "GlosSITarget"
VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware"
VALUE "OriginalFilename", "GlosSITarget.exe"
VALUE "ProductName", "GlosSI"
- VALUE "ProductVersion", "0.0.7.1-18-g0f2bac6"
+ VALUE "ProductVersion", "0.0.8.1-31-gda51d35"
END
END
BLOCK "VarFileInfo"
@@ -168,6 +168,234 @@ IDI_ICON1 ICON "GloSC_Icon.ico"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GlosSITarget/Settings.h b/GlosSITarget/Settings.h
index 6b80fd0..9e25bc9 100644
--- a/GlosSITarget/Settings.h
+++ b/GlosSITarget/Settings.h
@@ -47,11 +47,15 @@ inline struct Window {
} window;
inline struct Controller {
- int maxControllers = 4;
+ int maxControllers = 1;
bool allowDesktopConfig = false;
bool emulateDS4 = false;
} controller;
+inline bool extendedLogging = false;
+
+inline std::filesystem::path settings_path_ = "";
+
inline bool checkIsUwp(const std::wstring& launch_path)
{
if (launch_path.find(L"://") != std::wstring::npos) {
@@ -87,14 +91,9 @@ inline void Parse(std::wstring arg1)
spdlog::error(L"Couldn't open settings file {}", path.wstring());
return;
}
- const auto json = nlohmann::json::parse(json_file);
- if (json["version"] != 1) { // TODO: versioning stuff
- spdlog::warn("Config version doesn't match application version.");
- }
+ settings_path_ = path;
- // TODO: make this as much generic as fits in about the same amount of code if one would parse every value separately.
-
- auto safeParseValue = [](const auto& object, const auto& key, auto& value) {
+ auto safeParseValue = [](const auto& object, const auto& key, auto& value) {
try {
if (object.is_null() || object.empty() || object.at(key).empty() || object.at(key).is_null()) {
return;
@@ -102,10 +101,10 @@ inline void Parse(std::wstring arg1)
value = object[key];
}
catch (const nlohmann::json::exception& e) {
- spdlog::error("Err parsing \"{}\"; {}", key, e.what());
+ spdlog::warn("Err parsing \"{}\"; {}", key, e.what());
}
catch (const std::exception& e) {
- spdlog::error("Err parsing \"{}\"; {}", key, e.what());
+ spdlog::warn("Err parsing \"{}\"; {}", key, e.what());
}
};
@@ -118,6 +117,15 @@ inline void Parse(std::wstring arg1)
}
};
+ const auto json = nlohmann::json::parse(json_file);
+ int version;
+ safeParseValue(json, "version" ,version);
+ if (version != 1) { // TODO: versioning stuff
+ spdlog::warn("Config version doesn't match application version.");
+ }
+
+ // TODO: make this as much generic as fits in about the same amount of code if one would parse every value separately.
+
if (auto launchconf = json["launch"]; launchconf.is_object()) {
safeParseValue(launchconf, "launch", launch.launch);
safeWStringParse(launchconf, "launchPath", launch.launchPath);
@@ -144,13 +152,47 @@ inline void Parse(std::wstring arg1)
safeParseValue(controllerConf, "emulateDS4", controller.emulateDS4);
}
+ safeParseValue(json, "extendedLogging", extendedLogging);
+
json_file.close();
- spdlog::debug(L"Read config file \"{}\"", path.wstring());
+ // c++ is stupid...
+ spdlog::debug(L"Read config file \"{}\"; config: {}", path.wstring(), std::filesystem::path(json.dump()).wstring());
if (launch.launch) {
launch.isUWP = checkIsUwp(launch.launchPath);
}
}
+inline void StoreSettings()
+{
+ nlohmann::json json;
+ json["version"] = 1;
+ json["launch"]["launch"] = launch.launch;
+ json["launch"]["launchPath"] = std::wstring_convert>().to_bytes(launch.launchPath);
+ json["launch"]["launchAppArgs"] = std::wstring_convert>().to_bytes(launch.launchAppArgs);
+ json["launch"]["closeOnExit"] = launch.closeOnExit;
+ json["launch"]["waitForChildProcs"] = launch.waitForChildProcs;
+ json["devices"]["hideDevices"] = devices.hideDevices;
+ json["devices"]["realDeviceIds"] = devices.realDeviceIds;
+ json["window"]["windowMode"] = window.windowMode;
+ json["window"]["maxFps"] = window.maxFps;
+ json["window"]["scale"] = window.scale;
+ json["window"]["disableOverlay"] = window.disableOverlay;
+ json["controller"]["maxControllers"] = controller.maxControllers;
+ json["controller"]["allowDesktopConfig"] = controller.allowDesktopConfig;
+ json["controller"]["emulateDS4"] = controller.emulateDS4;
+
+ json["extendedLogging"] = extendedLogging;
+
+ std::ofstream json_file;
+ json_file.open(settings_path_);
+ if (!json_file.is_open()) {
+ spdlog::error(L"Couldn't open settings file {}", settings_path_.wstring());
+ return;
+ }
+ json_file << json.dump(4);
+ json_file.close();
+}
+
} // namespace Settings
diff --git a/GlosSITarget/SteamOverlayDetector.cpp b/GlosSITarget/SteamOverlayDetector.cpp
index 003a1e6..12fdf86 100644
--- a/GlosSITarget/SteamOverlayDetector.cpp
+++ b/GlosSITarget/SteamOverlayDetector.cpp
@@ -17,6 +17,8 @@ limitations under the License.
#include
+#include "Settings.h"
+
#ifdef _WIN32
#define NOMINMAX
#include
@@ -44,6 +46,11 @@ void SteamOverlayDetector::update()
// okey to use nullptr as hwnd. get EVERY message
if (PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE)) {
// filter out some messages as not all get altered by steam...
+
+ if (Settings::extendedLogging && msg.message != 512 && msg.message != 5374) {
+ spdlog::trace("PeekMessage: Window msg: {}", msg.message);
+ }
+
if (msg.message < 1000 && msg.message > 0) {
return;
}
diff --git a/GlosSITarget/SteamTarget.cpp b/GlosSITarget/SteamTarget.cpp
index b11a51a..89feee7 100644
--- a/GlosSITarget/SteamTarget.cpp
+++ b/GlosSITarget/SteamTarget.cpp
@@ -181,6 +181,9 @@ void SteamTarget::toggleGlossiOverlay()
void SteamTarget::focusWindow(WindowHandle hndl)
{
+ if (reinterpret_cast(hndl) == 0) {
+ return;
+ }
#ifdef _WIN32
if (hndl == target_window_handle_) {
spdlog::debug("Bring own window to foreground");
diff --git a/GlosSITarget/TargetWindow.cpp b/GlosSITarget/TargetWindow.cpp
index f2eb178..32790c6 100644
--- a/GlosSITarget/TargetWindow.cpp
+++ b/GlosSITarget/TargetWindow.cpp
@@ -50,9 +50,9 @@ TargetWindow::TargetWindow(
{
createWindow(Settings::window.windowMode);
- Overlay::AddOverlayElem([this](bool window_has_focus) {
+ Overlay::AddOverlayElem([this](bool window_has_focus, ImGuiID dockspace_id) {
+ ImGui::SetNextWindowDockID(dockspace_id, ImGuiCond_FirstUseEver);
bool windowed_copy = windowed_;
- ImGui::SetNextWindowPos({window_.getSize().x - 370.f, 100}, ImGuiCond_FirstUseEver);
ImGui::Begin("Window mode");
if (ImGui::Checkbox("Window mode", &windowed_copy)) {
toggle_window_mode_after_frame_ = true;
@@ -254,14 +254,26 @@ void TargetWindow::createWindow(bool window_mode)
#ifdef _WIN32
// For some completely odd reason, the Background becomes black when enabled dpi-awareness and making the window desktop-size.
// Scaling down by 1px each direction is barely noticeable and works.
+
+ // Due to some other issue, the (Steam) overlay might get blurred when doing this
+ // as a workaround, start in full size, and scale down later...
spdlog::info("Creating Overlay window (Borderless Fullscreen)...");
- window_.create(sf::VideoMode(desktop_mode.width - 1, desktop_mode.height - 1, 32), "GlosSITarget", sf::Style::None);
+ window_.create(sf::VideoMode(desktop_mode.width -1, desktop_mode.height -1, 32), "GlosSITarget", sf::Style::None);
+
+ // get size of all monitors combined
+ const auto screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ const auto screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ spdlog::debug("Full screen size: {}x{}", screenWidth, screenHeight);
+
+ spdlog::debug("Primary monitor size: {}x{}", desktop_mode.width, desktop_mode.height);
+
#else
window_.create(desktop_mode, "GlosSITarget", sf::Style::None);
#endif
windowed_ = false;
}
window_.setActive(true);
+ spdlog::debug("Window position: {}x{}", window_.getPosition().x, window_.getPosition().y);
#ifdef _WIN32
HWND hwnd = window_.getSystemHandle();
@@ -320,6 +332,9 @@ void TargetWindow::createWindow(bool window_mode)
else {
spdlog::warn("Not applying too low screen scale setting");
}
+
+ // window_.setSize({desktop_mode.width - 1, desktop_mode.height - 1 });
+
on_window_changed_();
#ifdef _WIN32
diff --git a/GlosSITarget/UWPOverlayEnabler.h b/GlosSITarget/UWPOverlayEnabler.h
index 110b329..02e63fa 100644
--- a/GlosSITarget/UWPOverlayEnabler.h
+++ b/GlosSITarget/UWPOverlayEnabler.h
@@ -60,10 +60,8 @@ inline void EnableUwpOverlay()
inline void AddUwpOverlayOvWidget()
{
- Overlay::AddOverlayElem([](bool window_has_focus) {
- ImGui::SetNextWindowPos({1200, 250}, ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSizeConstraints({170, 325}, {1000, 1000});
- ImGui::SetNextWindowCollapsed(true, ImGuiCond_FirstUseEver);
+ Overlay::AddOverlayElem([](bool window_has_focus, ImGuiID dockspace_id) {
+ ImGui::SetNextWindowDockID(dockspace_id, ImGuiCond_FirstUseEver);
ImGui::Begin("UWP-Overlay");
ImGui::Text("To enable the overlay on top of \"fullscreen\" UWP-Apps,");
ImGui::Text("a .dll has to be injected into explorer.exe");
diff --git a/UWPOverlayEnablerDLL/UWPOverlayEnablerDLL.vcxproj b/UWPOverlayEnablerDLL/UWPOverlayEnablerDLL.vcxproj
index 9d0ad5a..34e5567 100644
--- a/UWPOverlayEnablerDLL/UWPOverlayEnablerDLL.vcxproj
+++ b/UWPOverlayEnablerDLL/UWPOverlayEnablerDLL.vcxproj
@@ -78,11 +78,11 @@
true
- ..\deps\subhook;$(IncludePath)
+ ..\deps\subhook;..\deps\spdlog\include;$(IncludePath)
false
- ..\deps\subhook;$(IncludePath)
+ ..\deps\subhook;..\deps\spdlog\include;$(IncludePath)
@@ -126,6 +126,7 @@
true
NotUsing
pch.h
+ stdcpp20
Windows
@@ -143,6 +144,7 @@
true
NotUsing
pch.h
+ stdcpp20
Windows
diff --git a/UWPOverlayEnablerDLL/dllmain.cpp b/UWPOverlayEnablerDLL/dllmain.cpp
index fe4dd04..2e2f1a3 100644
--- a/UWPOverlayEnablerDLL/dllmain.cpp
+++ b/UWPOverlayEnablerDLL/dllmain.cpp
@@ -47,8 +47,15 @@ There are two (known to me, at time of writing) ways to get a working overlay fo
#define SUBHOOK_STATIC
#include
+#include
#include
+#include
+#include
+#include
+
+#include
+
enum ZBID
{
ZBID_DEFAULT = 0,
@@ -71,6 +78,7 @@ enum ZBID
ZBID_LOCK = 17,
ZBID_ABOVELOCK_UX = 18,
};
+
typedef BOOL(WINAPI* fSetWindowBand)(HWND hWnd, HWND hwndInsertAfter, DWORD dwBand);
@@ -79,18 +87,22 @@ fSetWindowBand SetWindowBand;
std::atomic allow_exit = false;
+std::atomic to_set_window_band = ZBID_SYSTEM_TOOLS;
+
BOOL WINAPI SetGlosSIWindowBand(HWND hWnd, HWND hwndInsertAfter, DWORD dwBand)
{
subhook::ScopedHookRemove remove(&SetWindowBandHook);
const auto glossi_hwnd = FindWindowA(nullptr, "GlosSITarget");
if (glossi_hwnd)
{
+ spdlog::info("Found GlosSI Window");
// Most window bands don't really seem to work.
// However, notification and system_tools does!
// use system tools, as that allows the steam overlay to be interacted with
// without UWP apps minimizing
- SetWindowBand(glossi_hwnd, nullptr, ZBID_SYSTEM_TOOLS);
+ auto success = SetWindowBand(glossi_hwnd, nullptr, to_set_window_band);
allow_exit = true;
+ spdlog::info("Set GlosSI Window Band to {}; success: {}", static_cast(to_set_window_band), success);
}
return SetWindowBand(hWnd, hwndInsertAfter, dwBand);
}
@@ -102,7 +114,10 @@ DWORD WINAPI WaitThread(HMODULE hModule)
Sleep(10);
}
if (SetWindowBandHook.IsInstalled())
+ {
+ spdlog::debug("Uninstalling SetWindowBand hook");
SetWindowBandHook.Remove();
+ }
FreeLibraryAndExitThread(hModule, 0);
}
@@ -113,17 +128,104 @@ BOOL APIENTRY DllMain( HMODULE hModule,
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
+
+ auto configDirPath = std::filesystem::temp_directory_path()
+ .parent_path()
+ .parent_path()
+ .parent_path();
+
+ configDirPath /= "Roaming";
+ configDirPath /= "GlosSI";
+ if (!std::filesystem::exists(configDirPath))
+ std::filesystem::create_directories(configDirPath);
+
+
+
+ auto logPath = configDirPath;
+ logPath /= "UWPOverlayEnabler.log";
+ const auto file_sink = std::make_shared(logPath.string(), true);
+ std::vector sinks{ file_sink };
+ auto logger = std::make_shared("log", sinks.begin(), sinks.end());
+ logger->set_level(spdlog::level::trace);
+ logger->flush_on(spdlog::level::trace);
+ spdlog::set_default_logger(logger);
+
+ spdlog::info("UWPOverlayEnabler loaded");
+
+ auto configPath = configDirPath;
+ configPath /= "UWPOverlayEnabler.cfg";
+ if (std::filesystem::exists(configPath))
+ {
+ std::ifstream config(configPath);
+ std::string line;
+ while (std::getline(config, line))
+ {
+ // github copilot, lol
+ // i take it!
+ if (line == "ZBID_DEFAULT")
+ to_set_window_band = ZBID_DEFAULT;
+ else if (line == "ZBID_DESKTOP")
+ to_set_window_band = ZBID_DESKTOP;
+ else if (line == "ZBID_UIACCESS")
+ to_set_window_band = ZBID_UIACCESS;
+ else if (line == "ZBID_IMMERSIVE_IHM")
+ to_set_window_band = ZBID_IMMERSIVE_IHM;
+ else if (line == "ZBID_IMMERSIVE_NOTIFICATION")
+ to_set_window_band = ZBID_IMMERSIVE_NOTIFICATION;
+ else if (line == "ZBID_IMMERSIVE_APPCHROME")
+ to_set_window_band = ZBID_IMMERSIVE_APPCHROME;
+ else if (line == "ZBID_IMMERSIVE_MOGO")
+ to_set_window_band = ZBID_IMMERSIVE_MOGO;
+ else if (line == "ZBID_IMMERSIVE_EDGY")
+ to_set_window_band = ZBID_IMMERSIVE_EDGY;
+ else if (line == "ZBID_IMMERSIVE_INACTIVEMOBODY")
+ to_set_window_band = ZBID_IMMERSIVE_INACTIVEMOBODY;
+ else if (line == "ZBID_IMMERSIVE_INACTIVEDOCK")
+ to_set_window_band = ZBID_IMMERSIVE_INACTIVEDOCK;
+ else if (line == "ZBID_IMMERSIVE_ACTIVEMOBODY")
+ to_set_window_band = ZBID_IMMERSIVE_ACTIVEMOBODY;
+ else if (line == "ZBID_IMMERSIVE_ACTIVEDOCK")
+ to_set_window_band = ZBID_IMMERSIVE_ACTIVEDOCK;
+ else if (line == "ZBID_IMMERSIVE_BACKGROUND")
+ to_set_window_band = ZBID_IMMERSIVE_BACKGROUND;
+ else if (line == "ZBID_IMMERSIVE_SEARCH")
+ to_set_window_band = ZBID_IMMERSIVE_SEARCH;
+ else if (line == "ZBID_GENUINE_WINDOWS")
+ to_set_window_band = ZBID_GENUINE_WINDOWS;
+ else if (line == "ZBID_IMMERSIVE_RESTRICTED")
+ to_set_window_band = ZBID_IMMERSIVE_RESTRICTED;
+ else if (line == "ZBID_SYSTEM_TOOLS")
+ to_set_window_band = ZBID_SYSTEM_TOOLS;
+ else if (line == "ZBID_LOCK")
+ to_set_window_band = ZBID_LOCK;
+ else if (line == "ZBID_ABOVELOCK_UX")
+ to_set_window_band = ZBID_ABOVELOCK_UX;
+
+ }
+ spdlog::info("Read window band from config: {}", static_cast(to_set_window_band));
+ }
+
const auto hpath = LoadLibrary(L"user32.dll");
if (hpath)
{
+ spdlog::debug("Loaded user32.dll");
+ spdlog::debug("Installing SetWindowBand hook");
SetWindowBand = reinterpret_cast(GetProcAddress(hpath, "SetWindowBand"));
SetWindowBandHook.Install(GetProcAddress(hpath, "SetWindowBand"), &SetGlosSIWindowBand, subhook::HookFlags::HookFlag64BitOffset);
+ spdlog::debug("Creating wait thread");
CloseHandle(CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)WaitThread, hModule, 0, nullptr));
+ } else
+ {
+ spdlog::error("Loaded user32.dll");
}
}
else if (ul_reason_for_call == DLL_PROCESS_DETACH) {
+ spdlog::info("unloading UWPOverlayEnabler");
if (SetWindowBandHook.IsInstalled())
+ {
+ spdlog::debug("Uninstalling SetWindowBand hook");
SetWindowBandHook.Remove();
+ }
}
return TRUE;
}
diff --git a/deps/Shortcuts_VDF b/deps/Shortcuts_VDF
index 2816b31..59108a7 160000
--- a/deps/Shortcuts_VDF
+++ b/deps/Shortcuts_VDF
@@ -1 +1 @@
-Subproject commit 2816b31c8e777c2920e1f0881ce10c5c66e30c63
+Subproject commit 59108a7f9a938911e1cc237003a396c886be85f8
diff --git a/deps/imgui b/deps/imgui
index 9aae45e..9cd9c2e 160000
--- a/deps/imgui
+++ b/deps/imgui
@@ -1 +1 @@
-Subproject commit 9aae45eb4a05a5a1f96be1ef37eb503a12ceb889
+Subproject commit 9cd9c2eff99877a3f10a7f9c2a3a5b9c15ea36c6