Fetch updated gamepad mappings each launch

This commit is contained in:
Cameron Gutman 2020-11-21 14:45:34 -06:00
parent aa4684077d
commit e224a7f0c7
7 changed files with 106 additions and 1 deletions

View file

@ -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 \

View file

@ -6,6 +6,7 @@
#include <QSettings>
#include <QCoreApplication>
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";
}
}

View file

@ -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;
};

View file

@ -0,0 +1,52 @@
#include "mappingfetcher.h"
#include "path.h"
#include <QNetworkReply>
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();
}
}

View file

@ -0,0 +1,20 @@
#pragma once
#include <QObject>
#include <QNetworkAccessManager>
class MappingFetcher : public QObject
{
Q_OBJECT
public:
explicit MappingFetcher(QObject *parent = nullptr);
void start();
private slots:
void handleMappingListFetched(QNetworkReply* reply);
private:
QNetworkAccessManager m_Nam;
};

View file

@ -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);

View file

@ -1,5 +1,7 @@
#pragma once
#include "mappingfetcher.h"
#include <QSettings>
class SdlGamepadMapping
@ -70,5 +72,7 @@ public:
private:
QMap<QString, SdlGamepadMapping> m_Mappings;
static MappingFetcher* s_MappingFetcher;
};