From e224a7f0c78b0bdaceb596347230e55ee38dffa2 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 21 Nov 2020 14:45:34 -0600 Subject: [PATCH] Fetch updated gamepad mappings each launch --- app/app.pro | 2 ++ app/path.cpp | 19 +++++++++++- app/path.h | 2 ++ app/settings/mappingfetcher.cpp | 52 +++++++++++++++++++++++++++++++++ app/settings/mappingfetcher.h | 20 +++++++++++++ app/settings/mappingmanager.cpp | 8 +++++ app/settings/mappingmanager.h | 4 +++ 7 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 app/settings/mappingfetcher.cpp create mode 100644 app/settings/mappingfetcher.h diff --git a/app/app.pro b/app/app.pro index f4af7272..3d078139 100644 --- a/app/app.pro +++ b/app/app.pro @@ -132,6 +132,7 @@ SOURCES += \ cli/commandlineparser.cpp \ cli/quitstream.cpp \ cli/startstream.cpp \ + settings/mappingfetcher.cpp \ settings/streamingpreferences.cpp \ streaming/input/abstouch.cpp \ streaming/input/gamepad.cpp \ @@ -155,6 +156,7 @@ SOURCES += \ HEADERS += \ backend/nvapp.h \ + settings/mappingfetcher.h \ utils.h \ backend/computerseeker.h \ backend/identitymanager.h \ diff --git a/app/path.cpp b/app/path.cpp index bd5c114f..30de556e 100644 --- a/app/path.cpp +++ b/app/path.cpp @@ -6,6 +6,7 @@ #include #include +QString Path::s_CacheDir; QString Path::s_LogDir; QString Path::s_BoxArtCacheDir; @@ -28,11 +29,25 @@ QByteArray Path::readDataFile(QString fileName) return dataFile.readAll(); } +void Path::writeDataFile(QString fileName, QByteArray data) +{ + QFile dataFile(QDir(s_CacheDir).absoluteFilePath(fileName)); + dataFile.open(QIODevice::WriteOnly); + dataFile.write(data); +} + QString Path::getDataFilePath(QString fileName) { QString candidatePath; - // Check the current directory first + // Check the cache location first (used by Path::writeDataFile()) + candidatePath = QDir(s_CacheDir).absoluteFilePath(fileName); + if (QFile::exists(candidatePath)) { + qInfo() << "Found" << fileName << "at" << candidatePath; + return candidatePath; + } + + // Check the current directory candidatePath = QDir(QDir::currentPath()).absoluteFilePath(fileName); if (QFile::exists(candidatePath)) { qInfo() << "Found" << fileName << "at" << candidatePath; @@ -64,6 +79,7 @@ void Path::initialize(bool portable) if (portable) { s_LogDir = QDir::currentPath(); s_BoxArtCacheDir = QDir::currentPath() + "/boxart"; + s_CacheDir = QDir::currentPath(); } else { #ifdef Q_OS_DARWIN @@ -73,6 +89,7 @@ void Path::initialize(bool portable) #else s_LogDir = QDir::tempPath(); #endif + s_CacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); s_BoxArtCacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/boxart"; } } diff --git a/app/path.h b/app/path.h index cb4aa90e..b5ae73f2 100644 --- a/app/path.h +++ b/app/path.h @@ -10,6 +10,7 @@ public: static QString getBoxArtCacheDir(); static QByteArray readDataFile(QString fileName); + static void writeDataFile(QString fileName, QByteArray data); // Only safe to use directly for Qt classes static QString getDataFilePath(QString fileName); @@ -17,6 +18,7 @@ public: static void initialize(bool portable); private: + static QString s_CacheDir; static QString s_LogDir; static QString s_BoxArtCacheDir; }; diff --git a/app/settings/mappingfetcher.cpp b/app/settings/mappingfetcher.cpp new file mode 100644 index 00000000..00cdb4a8 --- /dev/null +++ b/app/settings/mappingfetcher.cpp @@ -0,0 +1,52 @@ +#include "mappingfetcher.h" +#include "path.h" + +#include + +MappingFetcher::MappingFetcher(QObject *parent) : + QObject(parent), + m_Nam(this) +{ + // Never communicate over HTTP + m_Nam.setStrictTransportSecurityEnabled(true); + + // Allow HTTP redirects + m_Nam.setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); + + connect(&m_Nam, SIGNAL(finished(QNetworkReply*)), + this, SLOT(handleMappingListFetched(QNetworkReply*))); +} + +void MappingFetcher::start() +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && QT_VERSION < QT_VERSION_CHECK(5, 15, 1) && !defined(QT_NO_BEARERMANAGEMENT) + // HACK: Set network accessibility to work around QTBUG-80947 (introduced in Qt 5.14.0 and fixed in Qt 5.15.1) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + m_Nam.setNetworkAccessible(QNetworkAccessManager::Accessible); + QT_WARNING_POP +#endif + + // We'll get a callback when this is finished + QUrl url("https://moonlight-stream.org/SDL_GameControllerDB/gamecontrollerdb.txt"); + m_Nam.get(QNetworkRequest(url)); +} + +void MappingFetcher::handleMappingListFetched(QNetworkReply* reply) +{ + Q_ASSERT(reply->isFinished()); + + if (reply->error() == QNetworkReply::NoError) { + // Queue the reply for deletion + reply->deleteLater(); + + // Update the cached data on disk for next call to applyMappings() + Path::writeDataFile("gamecontrollerdb.txt", reply->readAll()); + + qInfo() << "Downloaded updated gamepad mappings"; + } + else { + qWarning() << "Failed to download updated gamepad mappings:" << reply->error(); + reply->deleteLater(); + } +} diff --git a/app/settings/mappingfetcher.h b/app/settings/mappingfetcher.h new file mode 100644 index 00000000..8a2097c1 --- /dev/null +++ b/app/settings/mappingfetcher.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +class MappingFetcher : public QObject +{ + Q_OBJECT + +public: + explicit MappingFetcher(QObject *parent = nullptr); + + void start(); + +private slots: + void handleMappingListFetched(QNetworkReply* reply); + +private: + QNetworkAccessManager m_Nam; +}; diff --git a/app/settings/mappingmanager.cpp b/app/settings/mappingmanager.cpp index c7e17c61..8835e844 100644 --- a/app/settings/mappingmanager.cpp +++ b/app/settings/mappingmanager.cpp @@ -10,10 +10,18 @@ #define SER_GUID "guid" #define SER_MAPPING "mapping" +MappingFetcher* MappingManager::s_MappingFetcher; + MappingManager::MappingManager() { QSettings settings; + // Load updated mappings from the Internet once per Moonlight launch + if (s_MappingFetcher == nullptr) { + s_MappingFetcher = new MappingFetcher(); + s_MappingFetcher->start(); + } + // First load existing saved mappings. This ensures the user's // hints can always override the old data. int mappingCount = settings.beginReadArray(SER_GAMEPADMAPPING); diff --git a/app/settings/mappingmanager.h b/app/settings/mappingmanager.h index bdbb2d26..c04da389 100644 --- a/app/settings/mappingmanager.h +++ b/app/settings/mappingmanager.h @@ -1,5 +1,7 @@ #pragma once +#include "mappingfetcher.h" + #include class SdlGamepadMapping @@ -70,5 +72,7 @@ public: private: QMap m_Mappings; + + static MappingFetcher* s_MappingFetcher; };