123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- #include "InputMapping.h"
- #include <QDir>
- #include <QDirIterator>
- #include <QByteArray>
- #include <QFile>
- #include <QJsonArray>
- #include <QJsonObject>
- #include <QJsonDocument>
- #include "QsLog.h"
- #include "Paths.h"
- #include "utils/Utils.h"
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- InputMapping::InputMapping(QObject *parent) : QObject(parent), m_sourceMatcher(false)
- {
- m_watcher = new QFileSystemWatcher(this);
- connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &InputMapping::dirChange);
- connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &InputMapping::dirChange);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- void InputMapping::dirChange()
- {
- QLOG_INFO() << "Change to user input path, reloading mappings.";
- loadMappings();
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- bool InputMapping::loadMappings()
- {
- m_inputMatcher.clear();
- m_sourceMatcher.clear();
- // don't watch the path while we potentially copy files to the directory
- if (m_watcher->directories().size() > 0)
- m_watcher->removePath(Paths::dataDir("inputmaps"));
- // first we load the bundled mappings
- loadMappingDirectory(":/inputmaps", true);
- // now we load the user ones, if there are any
- // they will now overload the built-in ones.
- //
- loadMappingDirectory(Paths::dataDir("inputmaps"), false);
- // we want to watch this dir for new files and changed files
- m_watcher->addPath(Paths::dataDir("inputmaps"));
- emit mappingChanged();
- return true;
- }
- /////////////////////////////////////////////////////////////////////////////////////////
- QVariantList InputMapping::mapToAction(const QString& source, const QString& keycode)
- {
- // if the source is direct we will just use the keycode as the action
- if (source == "direct")
- return { QVariant(keycode) };
- QVariantList strActions;
- // first we need to match the source
- for (auto src : m_sourceMatcher.match(source))
- strActions << m_inputMatcher.value(src.toString())->match(keycode);
- return strActions;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- bool InputMapping::loadMappingFile(const QString& path, QPair<QString, QVariantMap> &mappingPair)
- {
- QJsonParseError err;
- auto doc = Utils::OpenJsonDocument(path, &err);
- if (doc.isNull())
- {
- QLOG_WARN() << "Failed to parse input mapping file:" << path << "," << err.errorString();
- return false;
- }
- if (doc.isObject())
- {
- auto obj = doc.object();
- if (!obj.contains("name"))
- {
- QLOG_WARN() << "Missing elements 'name' from mapping file:" << path;
- return false;
- }
- if (!obj.contains("idmatcher"))
- {
- QLOG_WARN() << "Missing element 'idmatcher' from mapping file:" << path;
- return false;
- }
- if (!obj.contains("mapping"))
- {
- QLOG_WARN() << "Missing element 'mapping' from mapping file:" << path;
- return false;
- }
- mappingPair = qMakePair(obj["name"].toString(), obj.toVariantMap());
- return true;
- }
- QLOG_WARN() << "Wrong format for file:" << path;
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- bool InputMapping::loadMappingDirectory(const QString& path, bool copy)
- {
- QLOG_INFO() << "Loading inputmaps from:" << path;
- QDirIterator it(path);
- while (it.hasNext())
- {
- QFileInfo finfo = QFileInfo(it.next());
- if (finfo.isFile() && finfo.isReadable() && finfo.fileName().endsWith(".json"))
- {
- // make a copy of the original file to the example directory
- if (copy)
- {
- QDir userdir(Paths::dataDir());
- userdir.mkpath("inputmaps/examples/");
- QString examplePath(userdir.filePath("inputmaps/examples/" + finfo.fileName()));
- // make sure we really overwrite the file. copy will not do this.
- if (QFile(examplePath).exists())
- QFile::remove(examplePath);
- QFile::copy(finfo.absoluteFilePath(), examplePath);
- QFile(examplePath).setPermissions(QFileDevice::ReadOwner | QFileDevice::ReadGroup | QFileDevice::WriteOwner |
- QFileDevice::WriteGroup | QFileDevice::ReadOther);
- }
- QPair<QString, QVariantMap> mapping;
- if (loadMappingFile(finfo.absoluteFilePath(), mapping))
- {
- // add the source regexp to the matcher
- if (m_sourceMatcher.addMatcher(mapping.second.value("idmatcher").toString(), mapping.first))
- {
- // get the input map and add it to a new CachedMatcher
- QVariantMap inputMap = mapping.second.value("mapping").toMap();
- auto inputMatcher = new CachedRegexMatcher(true, this);
- for(const QString& pattern : inputMap.keys())
- inputMatcher->addMatcher("^" + pattern + "$", inputMap.value(pattern));
- m_inputMatcher.insert(mapping.first, inputMatcher);
- }
- }
- }
- }
- return true;
- }
|