diff --git a/CMakeLists.txt b/CMakeLists.txt index 83b152fb7..5b5ab7039 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -404,21 +404,26 @@ if(UNIX) elseif(WIN32) LIST(APPEND antimicrox_SOURCES + src/autoprofilewatcher.cpp src/winextras.cpp src/qtwinkeymapper.cpp - # src/winappprofiletimerdialog.cpp - # src/capturedwindowinfodialog.cpp + src/winappprofiletimerdialog.cpp + src/capturedwindowinfodialog.cpp src/eventhandlers/winsendinputeventhandler.cpp src/joykeyrepeathelper.cpp ) LIST(APPEND antimicrox_HEADERS + src/autoprofilewatcher.h src/winextras.h src/qtwinkeymapper.h - # src/winappprofiletimerdialog.h - # src/capturedwindowinfodialog.h + src/winappprofiletimerdialog.h + src/capturedwindowinfodialog.h src/eventhandlers/winsendinputeventhandler.h src/joykeyrepeathelper.h ) + LIST(APPEND antimicrox_FORMS + src/winappprofiletimerdialog.ui + ) endif(UNIX) ############################### diff --git a/src/addeditautoprofiledialog.cpp b/src/addeditautoprofiledialog.cpp index cb82783f0..e7228a69e 100644 --- a/src/addeditautoprofiledialog.cpp +++ b/src/addeditautoprofiledialog.cpp @@ -24,10 +24,16 @@ #include "common.h" #include "inputdevice.h" -#ifdef WITH_X11 +#if defined(Q_OS_UNIX) + #ifdef WITH_X11 + #include "capturedwindowinfodialog.h" + #include "unixcapturewindowutility.h" + #include "x11extras.h" + #endif +#elif defined(Q_OS_WIN) #include "capturedwindowinfodialog.h" - #include "unixcapturewindowutility.h" - #include "x11extras.h" + #include "winappprofiletimerdialog.h" + #include "winextras.h" #endif #include @@ -103,7 +109,16 @@ AddEditAutoProfileDialog::AddEditAutoProfileDialog(AutoProfileInfo *info, AntiMi ui->applicationLineEdit->setText(info->getExe()); ui->winClassLineEdit->setText(info->getWindowClass()); ui->winNameLineEdit->setText(info->getWindowName()); +#ifdef Q_OS_UNIX ui->selectWindowPushButton->setVisible(false); +#elif defined(Q_OS_WIN) + ui->detectWinPropsSelectWindowPushButton->setVisible(false); + + ui->winClassLineEdit->setVisible(false); + ui->winClassLabel->setVisible(false); + // ui->winNameLineEdit->setVisible(false); + // ui->winNameLabel->setVisible(false); +#endif ui->asDefaultCheckBox->setEnabled(info->isCurrentDefault()); connect(ui->profileBrowsePushButton, &QPushButton::clicked, this, &AddEditAutoProfileDialog::openProfileBrowseDialog); @@ -115,10 +130,12 @@ AddEditAutoProfileDialog::AddEditAutoProfileDialog(AutoProfileInfo *info, AntiMi connect(ui->applicationLineEdit, &QLineEdit::textChanged, this, &AddEditAutoProfileDialog::checkForDefaultStatus); connect(ui->winClassLineEdit, &QLineEdit::textChanged, this, &AddEditAutoProfileDialog::checkForDefaultStatus); connect(ui->winNameLineEdit, &QLineEdit::textChanged, this, &AddEditAutoProfileDialog::checkForDefaultStatus); - +#if defined(Q_OS_UNIX) connect(ui->detectWinPropsSelectWindowPushButton, &QPushButton::clicked, this, &AddEditAutoProfileDialog::showCaptureHelpWindow); - +#elif defined(Q_OS_WIN) + connect(ui->selectWindowPushButton, &QPushButton::clicked, this, &AddEditAutoProfileDialog::openWinAppProfileDialog); +#endif connect(this, &AddEditAutoProfileDialog::accepted, this, &AddEditAutoProfileDialog::saveAutoProfileInformation); ui->asDefaultCheckBox->setChecked(info->isCurrentDefault()); @@ -145,8 +162,11 @@ void AddEditAutoProfileDialog::openProfileBrowseDialog() void AddEditAutoProfileDialog::openApplicationBrowseDialog() { +#ifdef Q_OS_WIN + QString filename = QFileDialog::getOpenFileName(this, tr("Select Program"), QDir::homePath(), tr("Programs (*.exe)")); +#else QString filename = QFileDialog::getOpenFileName(this, tr("Select Program"), QDir::homePath(), QString()); - +#endif if (!filename.isNull() && !filename.isEmpty()) { QFileInfo exe(filename); @@ -217,12 +237,13 @@ QString AddEditAutoProfileDialog::getOriginalWindowClass() const { return origin QString AddEditAutoProfileDialog::getOriginalWindowName() const { return originalWindowName; } +#ifdef Q_OS_UNIX /** * @brief Display a simple message box and attempt to capture a window using the mouse */ void AddEditAutoProfileDialog::showCaptureHelpWindow() { -#ifdef WITH_X11 + #ifdef WITH_X11 if (QApplication::platformName() == QStringLiteral("xcb")) { @@ -249,7 +270,7 @@ void AddEditAutoProfileDialog::showCaptureHelpWindow() thread->start(); } -#endif + #endif } /** @@ -258,7 +279,7 @@ void AddEditAutoProfileDialog::showCaptureHelpWindow() */ void AddEditAutoProfileDialog::checkForGrabbedWindow(UnixCaptureWindowUtility *util) { -#ifdef WITH_X11 if (QApplication::platformName() == QStringLiteral("xcb")) + #ifdef WITH_X11 if (QApplication::platformName() == QStringLiteral("xcb")) { long targetWindow = util->getTargetWindow(); bool escaped = !util->hasFailed(); @@ -305,8 +326,9 @@ void AddEditAutoProfileDialog::checkForGrabbedWindow(UnixCaptureWindowUtility *u util->deleteLater(); } -#endif + #endif } +#endif void AddEditAutoProfileDialog::windowPropAssignment(CapturedWindowInfoDialog *dialog) { @@ -416,6 +438,13 @@ void AddEditAutoProfileDialog::accept() validForm = false; errorString = tr("Program path is invalid or not executable."); } +#ifdef Q_OS_WIN + else if (!info.isAbsolute() && (info.fileName() != exeFileName || info.suffix() != "exe")) + { + validForm = false; + errorString = tr("File is not an .exe file."); + } +#endif } if (validForm && !propertyFound && !ui->asDefaultCheckBox->isChecked()) @@ -465,3 +494,19 @@ void AddEditAutoProfileDialog::checkDefaultCheckbox(const QString &text) ui->asDefaultCheckBox->setDisabled(false); } } + +#ifdef Q_OS_WIN +void AddEditAutoProfileDialog::openWinAppProfileDialog() +{ + WinAppProfileTimerDialog *dialog = new WinAppProfileTimerDialog(this); + connect(dialog, SIGNAL(accepted()), this, SLOT(captureWindowsApplicationPath())); + dialog->show(); +} + +void AddEditAutoProfileDialog::captureWindowsApplicationPath() +{ + CapturedWindowInfoDialog *dialog = new CapturedWindowInfoDialog(this); + connect(dialog, SIGNAL(accepted()), this, SLOT(windowPropAssignment())); + dialog->show(); +} +#endif diff --git a/src/addeditautoprofiledialog.h b/src/addeditautoprofiledialog.h index 72f4b24f1..6296f2440 100644 --- a/src/addeditautoprofiledialog.h +++ b/src/addeditautoprofiledialog.h @@ -68,10 +68,15 @@ class AddEditAutoProfileDialog : public QDialog void checkForReservedUniques(int index); void checkForDefaultStatus(); void windowPropAssignment(CapturedWindowInfoDialog *dialog); - void showCaptureHelpWindow(); - void checkForGrabbedWindow(UnixCaptureWindowUtility *util); void on_setPartialCheckBox_stateChanged(int arg1); void checkDefaultCheckbox(const QString &text); +#ifdef Q_OS_WIN + void openWinAppProfileDialog(); + void captureWindowsApplicationPath(); +#else + void showCaptureHelpWindow(); + void checkForGrabbedWindow(UnixCaptureWindowUtility *util); +#endif private: Ui::AddEditAutoProfileDialog *ui; diff --git a/src/antimicrosettings.cpp b/src/antimicrosettings.cpp index fffcc58a4..35a7abbbb 100644 --- a/src/antimicrosettings.cpp +++ b/src/antimicrosettings.cpp @@ -20,6 +20,8 @@ #include +const bool AntiMicroSettings::defaultDisabledWinEnhanced = false; + AntiMicroSettings::AntiMicroSettings(const QString &fileName, Format format, QObject *parent) : QSettings(fileName, format, parent) { diff --git a/src/antimicrosettings.h b/src/antimicrosettings.h index cc9382e57..e2ef74768 100644 --- a/src/antimicrosettings.h +++ b/src/antimicrosettings.h @@ -35,6 +35,8 @@ class AntiMicroSettings : public QSettings QMutex *getLock(); QSettings &getCmdSettings(); + static const bool defaultDisabledWinEnhanced; + void applySettingsToLogger(CommandLineUtility &cmdutility, Logger *logger = nullptr); protected: diff --git a/src/applaunchhelper.cpp b/src/applaunchhelper.cpp index 4915970f7..ce09630cd 100644 --- a/src/applaunchhelper.cpp +++ b/src/applaunchhelper.cpp @@ -28,6 +28,10 @@ #include #include +#ifdef Q_OS_WIN + #include +#endif + AppLaunchHelper::AppLaunchHelper(AntiMicroSettings *settings, bool graphical, QObject *parent) : QObject(parent) { @@ -44,6 +48,9 @@ void AppLaunchHelper::initRunMethods() changeMouseRefreshRate(); changeSpringModeScreen(); changeGamepadPollRate(); +#ifdef Q_OS_WIN + checkPointerPrecision(); +#endif } } @@ -150,6 +157,29 @@ void AppLaunchHelper::changeSpringModeScreen() JoyButton::setSpringModeScreen(springScreen, GlobalVariables::JoyButton::springModeScreen); } +#ifdef Q_OS_WIN +void AppLaunchHelper::checkPointerPrecision() +{ + WinExtras::grabCurrentPointerPrecision(); + bool disableEnhandedPoint = + settings->value("Mouse/DisableWinEnhancedPointer", AntiMicroSettings::defaultDisabledWinEnhanced).toBool(); + if (disableEnhandedPoint) + { + WinExtras::disablePointerPrecision(); + } +} + +void AppLaunchHelper::appQuitPointerPrecision() +{ + bool disableEnhancedPoint = + settings->value("Mouse/DisableWinEnhancedPointer", AntiMicroSettings::defaultDisabledWinEnhanced).toBool(); + if (disableEnhancedPoint && !WinExtras::isUsingEnhancedPointerPrecision()) + { + WinExtras::enablePointerPrecision(); + } +} +#endif + void AppLaunchHelper::revertMouseThread() { JoyButton::indirectStaticMouseThread(QThread::currentThread(), JoyButton::getStaticMouseEventTimer(), diff --git a/src/applaunchhelper.h b/src/applaunchhelper.h index 2df1a2ab0..8c9db0313 100644 --- a/src/applaunchhelper.h +++ b/src/applaunchhelper.h @@ -44,8 +44,14 @@ class AppLaunchHelper : public QObject void changeMouseRefreshRate(); void changeSpringModeScreen(); void changeGamepadPollRate(); +#ifdef Q_OS_WIN + void checkPointerPrecision(); +#endif public slots: +#ifdef Q_OS_WIN + void appQuitPointerPrecision(); +#endif void initRunMethods(); void revertMouseThread(); void changeMouseThread(QThread *thread); diff --git a/src/autoprofileinfo.cpp b/src/autoprofileinfo.cpp index 8f1dd0ddd..9ca4c25c3 100644 --- a/src/autoprofileinfo.cpp +++ b/src/autoprofileinfo.cpp @@ -82,6 +82,12 @@ void AutoProfileInfo::setExe(QString exe) { this->exe = exe; } +#ifdef Q_OS_WIN + else if (exe != this->exe && info.suffix() == "exe") + { + this->exe = exe; + } +#endif } else { this->exe = exe; diff --git a/src/autoprofilewatcher.cpp b/src/autoprofilewatcher.cpp index 48cf68438..2c791d54d 100644 --- a/src/autoprofilewatcher.cpp +++ b/src/autoprofilewatcher.cpp @@ -30,8 +30,12 @@ #include #include -#if defined(WITH_X11) +#if defined(Q_OS_UNIX) && defined(WITH_X11) #include "x11extras.h" + +#elif defined(Q_OS_WIN) + #include "winextras.h" + #endif AutoProfileWatcher *AutoProfileWatcher::_instance = nullptr; @@ -83,11 +87,21 @@ void AutoProfileWatcher::runAppCheck() // Check whether program path needs to be parsed. Removes processing time // and need to run Linux specific code searching /proc. - if (!getAppProfileAssignments().isEmpty()) +#ifdef Q_OS_LINUX + if (!appProfileAssignments.isEmpty()) { appLocation = findAppLocation(); - qDebug() << "appLocation is " << appLocation; } +#else + // In Windows, get program location no matter what. + appLocation = findAppLocation(); + if (!appLocation.isEmpty()) + { + baseAppFileName = QFileInfo(appLocation).fileName(); + } +#endif + + qDebug() << "appLocation is " << appLocation; // More portable check for whether antimicrox is the current application // with focus. @@ -97,7 +111,9 @@ void AutoProfileWatcher::runAppCheck() QString nowWindow = QString(); QString nowWindowClass = QString(); QString nowWindowName = QString(); - +#ifdef Q_OS_WIN + nowWindowName = WinExtras::getCurrentWindowText(); +#else long currentWindow = X11Extras::getInstance()->getWindowInFocus(); qDebug() << "getWindowInFocus: " << currentWindow; @@ -118,10 +134,10 @@ void AutoProfileWatcher::runAppCheck() nowWindowName = X11Extras::getInstance()->getWindowTitle(static_cast(currentWindow)); qDebug() << "title of window now: " << nowWindowName; } - qDebug() << "WINDOW CLASS: " << nowWindowClass; - qDebug() << "WINDOW NAME: " << nowWindowName; qDebug() << "WINDOW IN FOCUS: " << nowWindow; +#endif + qDebug() << "WINDOW NAME: " << nowWindowName; bool checkForTitleChange = getWindowNameProfileAssignments().size() > 0; @@ -129,10 +145,21 @@ void AutoProfileWatcher::runAppCheck() qDebug() << "checkForTitleChange: " << checkForTitleChange; - if (!focusedWidget && ((!nowWindow.isEmpty() && (nowWindow != currentApplication)) || - (checkForTitleChange && (nowWindowName != currentAppWindowTitle)))) +#ifdef Q_OS_WIN + if (!focusedWidget && ((!appLocation.isEmpty() && appLocation != currentApplication) || + (checkForTitleChange && nowWindowName != currentAppWindowTitle))) + +#else + if (!focusedWidget && ((!nowWindow.isEmpty() && nowWindow != currentApplication) || + (checkForTitleChange && nowWindowName != currentAppWindowTitle))) + +#endif { +#ifdef Q_OS_WIN + currentApplication = appLocation; +#else currentApplication = nowWindow; +#endif currentAppWindowTitle = nowWindowName; qInfo() << QObject::tr("Active window changed to: Title = \"%1\", " @@ -539,8 +566,8 @@ void AutoProfileWatcher::clearProfileAssignments() QString AutoProfileWatcher::findAppLocation() { QString exepath = QString(); - -#ifdef WITH_X11 +#if defined(Q_OS_LINUX) + #ifdef WITH_X11 Window currentWindow = 0; int pid = 0; @@ -549,6 +576,9 @@ QString AutoProfileWatcher::findAppLocation() pid = X11Extras::getInstance()->getApplicationPid(currentWindow); if (pid > 0) exepath = X11Extras::getInstance()->getApplicationLocation(pid); + #endif +#elif defined(Q_OS_WIN) + exepath = WinExtras::getForegroundWindowExePath(); #endif return exepath; diff --git a/src/buttoneditdialog.cpp b/src/buttoneditdialog.cpp index 733aa7a22..468f1e267 100644 --- a/src/buttoneditdialog.cpp +++ b/src/buttoneditdialog.cpp @@ -40,6 +40,11 @@ #include #include +#ifdef Q_OS_WIN + #include "winextras.h" + #include +#endif + ButtonEditDialog *ButtonEditDialog::instance = nullptr; ButtonEditDialog::ButtonEditDialog(InputDevice *joystick, bool isNumKeypad, QWidget *parent) @@ -241,16 +246,50 @@ void ButtonEditDialog::keyReleaseEvent(QKeyEvent *event) BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); -#if defined(WITH_X11) int finalvirtual = 0; int checkalias = 0; +#ifdef Q_OS_WIN + #ifdef WITH_VMULTI + if (handler->getIdentifier() == "vmulti") + { + finalvirtual = WinExtras::correctVirtualKey(controlcode, virtualactual); + checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); + + // unsigned int tempQtKey = nativeWinKeyMapper.returnQtKey(finalvirtual); + QtKeyMapperBase *nativeWinKeyMapper = AntKeyMapper::getInstance()->getNativeKeyMapper(); + unsigned int tempQtKey = 0; + if (nativeWinKeyMapper) + { + tempQtKey = nativeWinKeyMapper->returnQtKey(finalvirtual); + } + + if (tempQtKey > 0) + { + finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(tempQtKey); + checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); + } else + { + finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(event->key()); + } + } + #endif + + BACKEND_ELSE_IF(handler->getIdentifier() == "sendinput") + { + // Find more specific virtual key (VK_SHIFT -> VK_LSHIFT) + // by checking for extended bit in scan code. + finalvirtual = WinExtras::correctVirtualKey(controlcode, virtualactual); + checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual, controlcode); + } +#else + #if defined(WITH_X11) if (QApplication::platformName() == QStringLiteral("xcb")) { // Obtain group 1 X11 keysym. Removes effects from modifiers. finalvirtual = X11KeyCodeToX11KeySym(controlcode); - #ifdef WITH_UINPUT + #ifdef WITH_UINPUT if (handler->getIdentifier() == "uinput") { // Find Qt Key corresponding to X11 KeySym. @@ -261,15 +300,15 @@ void ButtonEditDialog::keyReleaseEvent(QKeyEvent *event) finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey( checkalias); // Find corresponding Linux input key for the Qt key. } - #endif + #endif - #ifdef WITH_XTEST + #ifdef WITH_XTEST BACKEND_ELSE_IF(handler->getIdentifier() == "xtest") { // Check for alias against group 1 keysym. checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } - #endif + #endif } else { // Not running on xcb platform. @@ -277,7 +316,7 @@ void ButtonEditDialog::keyReleaseEvent(QKeyEvent *event) checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } -#else + #else int finalvirtual = 0; int checkalias = 0; if (QApplication::platformName() == QStringLiteral("xcb")) @@ -291,6 +330,7 @@ void ButtonEditDialog::keyReleaseEvent(QKeyEvent *event) checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } + #endif #endif if (!ignoreRelease && (event->modifiers() & Qt::ControlModifier) && (event->key() == Qt::Key_X)) diff --git a/src/capturedwindowinfodialog.cpp b/src/capturedwindowinfodialog.cpp index b43c7a222..3af7df516 100644 --- a/src/capturedwindowinfodialog.cpp +++ b/src/capturedwindowinfodialog.cpp @@ -23,9 +23,17 @@ #include #include -#include "x11extras.h" - +#ifdef Q_OS_WIN + #include "winextras.h" +#else + #include "x11extras.h" +#endif + +#ifdef Q_OS_WIN +CapturedWindowInfoDialog::CapturedWindowInfoDialog(QWidget *parent) +#else CapturedWindowInfoDialog::CapturedWindowInfoDialog(long window, QWidget *parent) +#endif : QDialog(parent) , ui(new Ui::CapturedWindowInfoDialog) { @@ -34,12 +42,20 @@ CapturedWindowInfoDialog::CapturedWindowInfoDialog(long window, QWidget *parent) selectedMatch = WindowNone; +#ifdef Q_OS_UNIX X11Extras *info = X11Extras::getInstance(); ui->winPathChoiceComboBox->setVisible(false); +#endif bool setRadioDefault = false; fullWinPath = false; +#ifdef Q_OS_WIN + ui->winClassCheckBox->setVisible(false); + ui->winClassLabel->setVisible(false); + ui->winClassHeadLabel->setVisible(false); +#else + winClass = info->getWindowClass(static_cast(window)); ui->winClassLabel->setText(winClass); @@ -54,8 +70,13 @@ CapturedWindowInfoDialog::CapturedWindowInfoDialog(long window, QWidget *parent) } ui->winPathChoiceComboBox->setVisible(false); +#endif - winName = info->getWindowTitle(static_cast(window)); +#ifdef Q_OS_WIN + winName = WinExtras::getCurrentWindowText(); +#else + winName = info->getWindowTitle(window); +#endif ui->winTitleLabel->setText(winName); @@ -70,7 +91,22 @@ CapturedWindowInfoDialog::CapturedWindowInfoDialog(long window, QWidget *parent) } ui->winPathLabel->clear(); +#ifdef Q_OS_WIN + winPath = WinExtras::getForegroundWindowExePath(); + ui->winPathLabel->setText(winPath); + + if (winPath.isEmpty()) + { + ui->winPathCheckBox->setEnabled(false); + ui->winPathCheckBox->setChecked(false); + } else + { + ui->winPathCheckBox->setChecked(true); + ui->winTitleCheckBox->setChecked(false); + setRadioDefault = true; + } +#elif defined(Q_OS_LINUX) int pid = info->getApplicationPid(static_cast(window)); if (pid > 0) @@ -95,6 +131,7 @@ CapturedWindowInfoDialog::CapturedWindowInfoDialog(long window, QWidget *parent) ui->winPathCheckBox->setEnabled(false); ui->winPathCheckBox->setChecked(false); } +#endif if (winClass.isEmpty() && winName.isEmpty() && winPath.isEmpty()) { diff --git a/src/capturedwindowinfodialog.h b/src/capturedwindowinfodialog.h index a695781c2..f77bd24af 100644 --- a/src/capturedwindowinfodialog.h +++ b/src/capturedwindowinfodialog.h @@ -32,7 +32,11 @@ class CapturedWindowInfoDialog : public QDialog Q_OBJECT public: +#ifdef Q_OS_WIN + explicit CapturedWindowInfoDialog(QWidget *parent = 0); +#else explicit CapturedWindowInfoDialog(long window, QWidget *parent = nullptr); +#endif ~CapturedWindowInfoDialog(); enum diff --git a/src/common.cpp b/src/common.cpp index 72777c59d..cf1c2affd 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -23,6 +23,9 @@ #include #include #include +#ifdef Q_OS_WIN + #include +#endif namespace PadderCommon { QString preferredProfileDir(AntiMicroSettings *settings) @@ -49,7 +52,23 @@ QString preferredProfileDir(AntiMicroSettings *settings) if (lookupDir.isEmpty()) { +#ifdef Q_OS_WIN + #ifdef WIN_PORTABLE_PACKAGE + QString portableProDir = QDir::currentPath().append("/profiles"); + QFileInfo portableProDirInfo(portableProDir); + if (portableProDirInfo.isDir() && portableProDirInfo.isReadable()) + { + lookupDir = portableProDir; + } else + { + lookupDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + } + #else + lookupDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + #endif +#else lookupDir = QDir::homePath(); +#endif } return lookupDir; @@ -101,13 +120,27 @@ void reloadTranslations(QTranslator *translator, QTranslator *appTranslator, QSt qApp->removeTranslator(appTranslator); // Load new Qt translation strings +#if defined(Q_OS_UNIX) translator->load(QString("qt_").append(language), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); +#elif defined(Q_OS_WIN) + #ifdef QT_DEBUG + translator->load(QString("qt_").append(language), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + #else + translator->load(QString("qt_").append(language), + QApplication::applicationDirPath().append("\\share\\qt\\translations")); + #endif +#endif qApp->installTranslator(appTranslator); // Load application specific translation strings +#if defined(Q_OS_UNIX) translator->load("antimicrox_" + language, QApplication::applicationDirPath().append("/../share/antimicrox/translations")); +#elif defined(Q_OS_WIN) + translator->load("antimicrox_" + language, + QApplication::applicationDirPath().append("\\share\\antimicrox\\translations")); +#endif qApp->installTranslator(translator); } diff --git a/src/common.h b/src/common.h index f11ca6114..e5ab50a67 100644 --- a/src/common.h +++ b/src/common.h @@ -30,15 +30,78 @@ #include #include +#ifdef Q_OS_WIN + +static QString findWinSystemConfigPath() +{ + QString temp; + temp = (!qgetenv("LocalAppData").isEmpty()) ? QString::fromUtf8(qgetenv("LocalAppData")) + "/antimicrox" + : QDir::homePath() + "/.antimicrox"; + return temp; +} + +static QString findWinLocalConfigPath() +{ + QString temp = QCoreApplication::applicationDirPath(); + return temp; +} + +static QString findWinDefaultConfigPath() +{ + QString temp = findWinLocalConfigPath(); + QFileInfo dirInfo(temp); + if (!dirInfo.isWritable()) + { + temp = findWinSystemConfigPath(); + } + + return temp; +} + +static QString findWinConfigPath(QString configFileName) +{ + QString temp; + QFileInfo localConfigInfo(findWinLocalConfigPath().append("/").append(configFileName)); + QFileInfo systemConfigInfo(findWinSystemConfigPath().append("/").append(configFileName)); + if (localConfigInfo.exists() && localConfigInfo.isWritable()) + { + temp = localConfigInfo.absoluteFilePath(); + } else if (systemConfigInfo.exists() && systemConfigInfo.isWritable()) + { + temp = systemConfigInfo.absoluteFilePath(); + } else + { + temp = findWinDefaultConfigPath().append("/").append(configFileName); + } + + return temp; +} +#endif + namespace PadderCommon { inline QString configPath() { +#if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) + return findWinLocalConfigPath(); +#elif defined(Q_OS_WIN) + return findWinSystemConfigPath(); +#else return (!qgetenv("XDG_CONFIG_HOME").isEmpty()) ? QString::fromUtf8(qgetenv("XDG_CONFIG_HOME")) + "/antimicrox" : QDir::homePath() + "/.config/antimicrox"; +#endif } const QString configFileName = "antimicrox_settings.ini"; -inline QString configFilePath() { return QString(configPath()).append("/").append(configFileName); } +inline QString configFilePath() +{ +#if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) + return QString(configPath()).append("/").append(configFileName); +#elif defined(Q_OS_WIN) + return QString(configPath()).append("/").append(configFileName); +#else + return QString(configPath()).append("/").append(configFileName); +#endif +} inline QString configLegacyFilePath() { diff --git a/src/joytabwidget.cpp b/src/joytabwidget.cpp index 749b230b3..0d5c1e4b0 100644 --- a/src/joytabwidget.cpp +++ b/src/joytabwidget.cpp @@ -549,6 +549,18 @@ void JoyTabWidget::openConfigFileDialog() QString outputFilename = fileinfo.absoluteDir().absolutePath(); +#if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) + if (fileinfo.absoluteDir().isAbsolute()) + { + QDir tempDir = fileinfo.dir(); + tempDir.cdUp(); + if (tempDir.path() == qApp->applicationDirPath()) + { + outputFilename = QString("%1/").arg(fileinfo.dir().dirName()); + } + } +#endif + m_settings->getLock()->lock(); m_settings->setValue("LastProfileDir", outputFilename); @@ -989,6 +1001,18 @@ void JoyTabWidget::saveSettings() QFileInfo profileBaseFile(filename); QString outputFilename = filename; +#if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) + if (profileBaseFile.isAbsolute()) + { + QDir tempDir = profileBaseFile.dir(); + tempDir.cdUp(); + if (tempDir.path() == qApp->applicationDirPath()) + { + outputFilename = QString("%1/%2").arg(profileBaseFile.dir().dirName()).arg(profileBaseFile.fileName()); + } + } +#endif + m_settings->setValue(controlEntryString.arg(currentjoy), outputFilename); if (PadderCommon::getProfileName(profileBaseFile) != profileText) @@ -1015,6 +1039,19 @@ void JoyTabWidget::saveSettings() QFileInfo profileBaseFile(filename); QString outputFilename = filename; +#if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) + if (profileBaseFile.isAbsolute()) + { + QDir tempDir = profileBaseFile.dir(); + tempDir.cdUp(); + if (tempDir.path() == qApp->applicationDirPath()) + { + outputFilename = + QString("%1/%2").arg(profileBaseFile.dir().dirName()).arg(profileBaseFile.fileName()); + } + } +#endif + m_settings->setValue(controlEntryString.arg(currentjoy), outputFilename); if (PadderCommon::getProfileName(profileBaseFile) != profileText) @@ -1031,6 +1068,17 @@ void JoyTabWidget::saveSettings() { QFileInfo profileBaseFile(lastfile); QString outputFilename = lastfile; +#if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) + if (profileBaseFile.isAbsolute()) + { + QDir tempDir = profileBaseFile.dir(); + tempDir.cdUp(); + if (tempDir.path() == qApp->applicationDirPath()) + { + outputFilename = QString("%1/%2").arg(profileBaseFile.dir().dirName()).arg(profileBaseFile.fileName()); + } + } +#endif m_settings->setValue(controlEntryLastSelected, outputFilename); } @@ -1127,6 +1175,11 @@ void JoyTabWidget::loadSettings(bool forceRefresh) { QString lastFileAbsolute = lastfile; +#if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) + QFileInfo lastFileInfo(lastfile); + lastFileAbsolute = lastFileInfo.absoluteFilePath(); +#endif + int lastindex = configBox->findData(lastFileAbsolute); if (lastindex > 0) { diff --git a/src/keyboard/virtualkeyboardmousewidget.cpp b/src/keyboard/virtualkeyboardmousewidget.cpp index d690fcb58..e5bf2c95c 100644 --- a/src/keyboard/virtualkeyboardmousewidget.cpp +++ b/src/keyboard/virtualkeyboardmousewidget.cpp @@ -580,12 +580,20 @@ void VirtualKeyboardMouseWidget::setupMouseControlLayout() tempVBoxLayout = new QVBoxLayout(); tempVBoxLayout->setSpacing(20); +#ifdef Q_OS_WIN + pushButton = new VirtualMousePushButton(tr("Button 4", "Mouse"), 8, JoyButtonSlot::JoyMouseButton, this); +#else pushButton = new VirtualMousePushButton(tr("Mouse 8", "Mouse"), 8, JoyButtonSlot::JoyMouseButton, this); +#endif pushButton->setMinimumHeight(40); tempVBoxLayout->addWidget(pushButton); +#ifdef Q_OS_WIN + pushButton = new VirtualMousePushButton(tr("Button 5", "Mouse"), 9, JoyButtonSlot::JoyMouseButton, this); +#else pushButton = new VirtualMousePushButton(tr("Mouse 9", "Mouse"), 9, JoyButtonSlot::JoyMouseButton, this); +#endif pushButton->setMinimumHeight(40); tempVBoxLayout->addWidget(pushButton); @@ -990,6 +998,13 @@ QPushButton *VirtualKeyboardMouseWidget::createOtherKeysMenu() QAction *tempAction = nullptr; int temp = 0; +#ifdef Q_OS_WIN + tempAction = new QAction(tr("Applications"), otherKeysMenu); + temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Menu); + tempAction->setData(temp); + otherKeysMenu->addAction(tempAction); +#endif + tempAction = new QAction(tr("Browser Back"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Back); tempAction->setData(temp); diff --git a/src/keyboard/virtualkeypushbutton.cpp b/src/keyboard/virtualkeypushbutton.cpp index 977268f19..d5e7c0c82 100644 --- a/src/keyboard/virtualkeypushbutton.cpp +++ b/src/keyboard/virtualkeypushbutton.cpp @@ -47,22 +47,40 @@ VirtualKeyPushButton::VirtualKeyPushButton(QString xcodestring, QWidget *parent) if (!xcodestring.isEmpty()) { temp = X11KeySymToKeycode(xcodestring); - +#ifdef Q_OS_UNIX BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (handler->getIdentifier() == "xtest") { temp = X11KeyCodeToX11KeySym(temp); } +#endif } if (temp > 0) { +#ifdef Q_OS_WIN + // static QtWinKeyMapper nativeWinKeyMapper; + BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); + + BACKEND_ELSE_IF(handler->getIdentifier() == "sendinput") + { + this->keycode = temp; + this->qkeyalias = AntKeyMapper::getInstance()->returnQtKey(this->keycode); + } + + // Special exception for Numpad Enter on Windows. + if (xcodestring == "KP_Enter") + { + this->qkeyalias = Qt::Key_Enter; + } +#else this->keycode = temp; // this->keycode = X11KeyCodeToX11KeySym(temp); this->qkeyalias = AntKeyMapper::getInstance()->returnQtKey(this->keycode); // this->keycode = temp; +#endif this->xcodestring = xcodestring; this->displayString = setDisplayString(xcodestring); } diff --git a/src/mainsettingsdialog.cpp b/src/mainsettingsdialog.cpp index d449d09d9..c4e080c7f 100644 --- a/src/mainsettingsdialog.cpp +++ b/src/mainsettingsdialog.cpp @@ -29,6 +29,10 @@ #ifdef WITH_X11 #include "x11extras.h" +#elif defined Q_OS_WIN + #include "eventhandlerfactory.h" + #include "winextras.h" + #include #endif #include @@ -97,6 +101,9 @@ MainSettingsDialog::MainSettingsDialog(AntiMicroSettings *settings, QListautoProfileTableWidget->hideColumn(3); +#endif ui->autoProfileTableWidget->hideColumn(7); #if defined(WITH_X11) @@ -122,11 +129,33 @@ MainSettingsDialog::MainSettingsDialog(AntiMicroSettings *settings, QListautoProfileTableWidget->setEnabled(true); ui->autoProfileAddPushButton->setEnabled(true); } +#ifdef Q_OS_WIN + BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) + { + // Handle Windows Vista and later + QFile tempFile(RUNATSTARTUPLOCATION); + if (tempFile.exists()) + { + ui->launchAtWinStartupCheckBox->setChecked(true); + } + } else + { + // Handle Windows XP + QSettings autoRunReg(RUNATSTARTUPREGKEY, QSettings::NativeFormat); + QString autoRunEntry = autoRunReg.value("antimicrox", "").toString(); + if (!autoRunEntry.isEmpty()) + { + ui->launchAtWinStartupCheckBox->setChecked(true); + } + } +#else ui->launchAtWinStartupCheckBox->setVisible(false); // TODO #115 ui->keyRepeatGroupBox->setVisible(false); +#endif bool useSingleProfileList = settings->value("TrayProfileList", false).toBool(); if (useSingleProfileList) @@ -161,9 +190,26 @@ MainSettingsDialog::MainSettingsDialog(AntiMicroSettings *settings, QListlaunchInTrayCheckBox->setChecked(true); } +#ifdef Q_OS_WIN + bool associateProfiles = settings->value("AssociateProfiles", true).toBool(); + if (associateProfiles) + { + ui->associateProfilesCheckBox->setChecked(true); + } else + { + ui->associateProfilesCheckBox->setChecked(false); + } + + bool disableEnhancedMouse = settings->value("Mouse/DisableWinEnhancedPointer", false).toBool(); + if (disableEnhancedMouse) + { + ui->disableWindowsEnhancedPointCheckBox->setChecked(true); + } +#else ui->associateProfilesCheckBox->setVisible(false); ui->disableWindowsEnhancedPointCheckBox->setVisible(false); +#endif if (attachedNumKeypad) ui->attachNumKeypadCheckbox->setChecked(true); @@ -199,6 +245,15 @@ MainSettingsDialog::MainSettingsDialog(AntiMicroSettings *settings, QListmouseRefreshRateComboBox->setCurrentIndex(refreshIndex); } +#ifdef Q_OS_WIN + QString tempTooltip = ui->mouseRefreshRateComboBox->toolTip(); + tempTooltip.append("\n\n"); + tempTooltip.append(tr("Also, Windows users who want to use a low value should also check the\n" + "\"Disable Enhance Pointer Precision\" checkbox if you haven't disabled\n" + "the option in Windows.")); + ui->mouseRefreshRateComboBox->setToolTip(tempTooltip); +#endif + fillSpringScreenPresets(); for (int i = 1; i <= 16; i++) @@ -496,6 +551,42 @@ void MainSettingsDialog::saveNewSettings() settings->getLock()->lock(); +#ifdef Q_OS_WIN + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) + { + // Handle Windows Vista and later + QFile tempFile(RUNATSTARTUPLOCATION); + + if (ui->launchAtWinStartupCheckBox->isChecked() && !tempFile.exists()) + { + if (tempFile.open(QFile::WriteOnly)) + { + QFile currentAppLocation(qApp->applicationFilePath()); + currentAppLocation.link(QFileInfo(tempFile).absoluteFilePath()); + } + } else if (tempFile.exists() && QFileInfo(tempFile).isWritable()) + { + tempFile.remove(); + } + } else + { + // Handle Windows XP + QSettings autoRunReg(RUNATSTARTUPREGKEY, QSettings::NativeFormat); + QString autoRunEntry = autoRunReg.value("antimicrox", "").toString(); + + if (ui->launchAtWinStartupCheckBox->isChecked()) + { + QString nativeFilePath = QDir::toNativeSeparators(qApp->applicationFilePath()); + autoRunReg.setValue("antimicrox", nativeFilePath); + } else if (!autoRunEntry.isEmpty()) + { + autoRunReg.remove("antimicrox"); + } + } + + BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); +#endif + if (ui->traySingleProfileListCheckBox->isChecked()) { settings->setValue("TrayProfileList", "1"); @@ -516,6 +607,37 @@ void MainSettingsDialog::saveNewSettings() bool launchInTray = ui->launchInTrayCheckBox->isChecked(); settings->setValue("LaunchInTray", launchInTray ? "1" : "0"); +#ifdef Q_OS_WIN + bool associateProfiles = ui->associateProfilesCheckBox->isChecked(); + settings->setValue("AssociateProfiles", associateProfiles ? "1" : "0"); + + bool associationExists = WinExtras::containsFileAssociationinRegistry(); + if (associateProfiles && !associationExists) + { + WinExtras::writeFileAssocationToRegistry(); + } else if (!associateProfiles && associationExists) + { + WinExtras::removeFileAssociationFromRegistry(); + } + + bool disableEnhancePoint = ui->disableWindowsEnhancedPointCheckBox->isChecked(); + bool oldEnhancedValue = settings->value("Mouse/DisableWinEnhancedPointer", false).toBool(); + bool usingEnhancedPointer = WinExtras::isUsingEnhancedPointerPrecision(); + settings->setValue("Mouse/DisableWinEnhancedPointer", disableEnhancePoint ? "1" : "0"); + + if (disableEnhancePoint != oldEnhancedValue) + { + if (usingEnhancedPointer && disableEnhancePoint) + { + WinExtras::disablePointerPrecision(); + } else if (!usingEnhancedPointer && !disableEnhancePoint) + { + WinExtras::enablePointerPrecision(); + } + } + +#endif + PadderCommon::lockInputDevices(); if (connectedDevices->size() > 0) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9546c921e..e28ee8fd9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -43,7 +43,7 @@ #include "xml/inputdevicexml.h" #include "xml/joybuttonslotxml.h" -#if defined(WITH_X11) +#if defined(WITH_X11) || defined(Q_OS_WIN) #include "autoprofileinfo.h" #include "autoprofilewatcher.h" #endif @@ -71,6 +71,11 @@ #include +#ifdef Q_OS_WIN + #include "winextras.h" + #include +#endif + #define CHECK_BATTERIES_MSEC 600000 MainWindow::MainWindow(QMap *joysticks, CommandLineUtility *cmdutility, @@ -103,6 +108,11 @@ MainWindow::MainWindow(QMap *joysticks, CommandLi this->appWatcher = nullptr; qDebug() << "appWatcher instance set to null pointer"; } +#elif defined(Q_OS_WIN) + this->appWatcher = new AutoProfileWatcher(settings, this); + checkAutoProfileWatcherTimer(); +#else + this->appWatcher = 0; #endif signalDisconnect = false; @@ -167,9 +177,30 @@ MainWindow::MainWindow(QMap *joysticks, CommandLi { connect(appWatcher, &AutoProfileWatcher::foundApplicableProfile, this, &MainWindow::autoprofileLoad); } +#elif defined(Q_OS_WIN) + connect(appWatcher, &AutoProfileWatcher::foundApplicableProfile, this, &MainWindow::autoprofileLoad); #endif +#ifdef Q_OS_WIN + if (graphical) + { + if (!WinExtras::IsRunningAsAdmin()) + { + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) + { + QIcon uacIcon = QApplication::style()->standardIcon(QStyle::SP_VistaShield); + ui->uacPushButton->setIcon(uacIcon); + } + connect(ui->uacPushButton, SIGNAL(clicked()), this, SLOT(restartAsElevated())); + } else + { + ui->uacPushButton->setVisible(false); + } + } + +#else ui->uacPushButton->setVisible(false); +#endif QTimer *timer = new QTimer(this); @@ -1216,6 +1247,11 @@ void MainWindow::openMainSettingsDialog() appWatcher->stopTimer(); qDebug() << "Stopping appWatcher in openMainSettingsDialog"; } +#elif defined(Q_OS_WIN) + connect(dialog, &MainSettingsDialog::accepted, appWatcher, &AutoProfileWatcher::syncProfileAssignment); + connect(dialog, &MainSettingsDialog::accepted, this, &MainWindow::checkAutoProfileWatcherTimer); + connect(dialog, &MainSettingsDialog::rejected, this, &MainWindow::checkAutoProfileWatcherTimer); + appWatcher->stopTimer(); #endif } @@ -1370,6 +1406,49 @@ void MainWindow::checkHideEmptyOption() } } +#ifdef Q_OS_WIN + +/** + * @brief Check if user really wants to restart the program with elevated + * privileges. If yes, attempt to restart the program. + */ +void MainWindow::restartAsElevated() +{ + QMessageBox msg; + msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msg.setWindowTitle(tr("Run as Administrator?")); + msg.setText(tr("Are you sure that you want to run this program as Adminstrator?" + "\n\n" + "Some games run as Administrator which will cause events generated by antimicro " + "to not be used by those games unless antimicro is also run " + "as the Adminstrator. " + "This is due to permission problems caused by User Account " + "Control (UAC) options in Windows Vista and later.")); + + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) + { + QIcon uacIcon = QApplication::style()->standardIcon(QStyle::SP_VistaShield); + msg.button(QMessageBox::Yes)->setIcon(uacIcon); + } + + int result = msg.exec(); + if (result == QMessageBox::Yes) + { + bool result = WinExtras::elevateAntiMicro(); + if (result) + { + qApp->quit(); + } else + { + msg.setStandardButtons(QMessageBox::Close); + msg.setWindowTitle(tr("Failed to elevate program")); + msg.setText(tr("Failed to restart this program as the Administrator")); + msg.exec(); + } + } +} +#endif + void MainWindow::openGameControllerMappingWindow(bool openAsMain) { int index = ui->tabWidget->currentIndex(); @@ -1519,96 +1598,95 @@ void MainWindow::autoprofileLoad(AutoProfileInfo *info) { qCritical() << QObject::tr("Auto-switching to nullptr profile!"); } +#if defined(WITH_X11) || defined(Q_OS_WIN) + #if defined(WITH_X11) + if (QApplication::platformName() != QStringLiteral("xcb")) + return; + #endif -#if defined(WITH_X11) - - if (QApplication::platformName() == QStringLiteral("xcb")) + for (int i = 0; i < ui->tabWidget->count(); i++) { - for (int i = 0; i < ui->tabWidget->count(); i++) - { - JoyTabWidget *widget = qobject_cast(ui->tabWidget->widget(i)); // static_cast + JoyTabWidget *widget = qobject_cast(ui->tabWidget->widget(i)); // static_cast - if (widget != nullptr) + if (widget != nullptr) + { + // if (info->getGUID() == "all") + if (info->getUniqueID() == "all") { - // if (info->getGUID() == "all") - if (info->getUniqueID() == "all") + // If the all option for a Default profile was found, + // first check for controller specific associations. If one exists, + // skip changing the profile on the controller. A later call will + // be used to switch the profile for that controller. + QList *customs = appWatcher->getCustomDefaults(); + bool found = false; + QListIterator iter(*customs); + + while (iter.hasNext()) { - // If the all option for a Default profile was found, - // first check for controller specific associations. If one exists, - // skip changing the profile on the controller. A later call will - // be used to switch the profile for that controller. - QList *customs = appWatcher->getCustomDefaults(); - bool found = false; - QListIterator iter(*customs); - - while (iter.hasNext()) - { - AutoProfileInfo *tempinfo = iter.next(); + AutoProfileInfo *tempinfo = iter.next(); - // if (tempinfo->getGUID() == widget->getJoystick()->getGUIDString() && - if (tempinfo->getUniqueID() == widget->getJoystick()->getUniqueIDString() && - info->isCurrentDefault()) - { - found = true; - iter.toBack(); - qDebug() << "autoProfileInfo has the same GUID as GUID of joystick and the autoProfile is " - "default. Found = true."; - } + // if (tempinfo->getGUID() == widget->getJoystick()->getGUIDString() && + if (tempinfo->getUniqueID() == widget->getJoystick()->getUniqueIDString() && info->isCurrentDefault()) + { + found = true; + iter.toBack(); + qDebug() << "autoProfileInfo has the same GUID as GUID of joystick and the autoProfile is " + "default. Found = true."; } + } - delete customs; - customs = nullptr; + delete customs; + customs = nullptr; - // Check if profile has already been switched for a particular - // controller. - if (!found) - { - // QString tempguid = widget->getJoystick()->getGUIDString(); - // if (appWatcher->isGUIDLocked(tempguid)) + // Check if profile has already been switched for a particular + // controller. + if (!found) + { + // QString tempguid = widget->getJoystick()->getGUIDString(); + // if (appWatcher->isGUIDLocked(tempguid)) - QString tempguid = widget->getJoystick()->getUniqueIDString(); + QString tempguid = widget->getJoystick()->getUniqueIDString(); - if (appWatcher->isUniqueIDLocked(tempguid)) - { - found = true; - qDebug() << "GUID is locked in appWatcher. Found = true."; - } - } - - if (!found) + if (appWatcher->isUniqueIDLocked(tempguid)) { - // If the profile location is empty, assume - // that an empty profile should get loaded. - if (info->getProfileLocation().isEmpty()) - { - widget->setCurrentConfig(0); - qDebug() << "profile location is empty. setCurrentConfig(0)"; - } else - { - widget->loadConfigFile(info->getProfileLocation()); - qDebug() << "loaded config file for current AutoLoadInfo"; - } + found = true; + qDebug() << "GUID is locked in appWatcher. Found = true."; } } - // else if (info->getGUID() == widget->getJoystick()->getStringIdentifier()) - else if (info->getUniqueID() == widget->getJoystick()->getStringIdentifier()) - { - // qDebug() << "GUID of AutoProfileInfo: " << info->getGUID() << " == string identifier of - // AutoProfileInfo: " << widget->getJoystick()->getStringIdentifier(); - qDebug() << "GUID of AutoProfileInfo: " << info->getUniqueID() - << " == string identifier of AutoProfileInfo: " << widget->getJoystick()->getStringIdentifier(); + if (!found) + { + // If the profile location is empty, assume + // that an empty profile should get loaded. if (info->getProfileLocation().isEmpty()) { - qDebug() << "profile location of AutoProfileInfo is empty. Set first config"; widget->setCurrentConfig(0); + qDebug() << "profile location is empty. setCurrentConfig(0)"; } else { - qDebug() << "load config file for AutoProfileInfo"; widget->loadConfigFile(info->getProfileLocation()); + qDebug() << "loaded config file for current AutoLoadInfo"; } } } + // else if (info->getGUID() == widget->getJoystick()->getStringIdentifier()) + else if (info->getUniqueID() == widget->getJoystick()->getStringIdentifier()) + { + // qDebug() << "GUID of AutoProfileInfo: " << info->getGUID() << " == string identifier of + // AutoProfileInfo: " << widget->getJoystick()->getStringIdentifier(); + qDebug() << "GUID of AutoProfileInfo: " << info->getUniqueID() + << " == string identifier of AutoProfileInfo: " << widget->getJoystick()->getStringIdentifier(); + + if (info->getProfileLocation().isEmpty()) + { + qDebug() << "profile location of AutoProfileInfo is empty. Set first config"; + widget->setCurrentConfig(0); + } else + { + qDebug() << "load config file for AutoProfileInfo"; + widget->loadConfigFile(info->getProfileLocation()); + } + } } } @@ -1617,20 +1695,21 @@ void MainWindow::autoprofileLoad(AutoProfileInfo *info) void MainWindow::checkAutoProfileWatcherTimer() { -#if defined(WITH_X11) +#if defined(WITH_X11) || defined(Q_OS_WIN) + #if defined(WITH_X11) + if (QApplication::platformName() != QStringLiteral("xcb")) + return; + #endif - if (QApplication::platformName() == QStringLiteral("xcb")) + QString autoProfileActive = m_settings->value("AutoProfiles/AutoProfilesActive", "0").toString(); + if (autoProfileActive == "1") { - QString autoProfileActive = m_settings->value("AutoProfiles/AutoProfilesActive", "0").toString(); - if (autoProfileActive == "1") - { - appWatcher->startTimer(); - qDebug() << "Started timer for appWatcher"; - } else - { - appWatcher->stopTimer(); - qDebug() << "Stopped timer for appWatcher"; - } + appWatcher->startTimer(); + qDebug() << "Started timer for appWatcher"; + } else + { + appWatcher->stopTimer(); + qDebug() << "Stopped timer for appWatcher"; } #endif } diff --git a/src/mainwindow.h b/src/mainwindow.h index b120b9ce7..91f8e34f3 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -135,6 +135,10 @@ class MainWindow : public QMainWindow void showStickAssignmentDialog(); void checkHideEmptyOption(); +#ifdef Q_OS_WIN + void restartAsElevated(); +#endif + void openGameControllerMappingWindow(bool openAsMain = false); void propogateMappingUpdate(QString mapping, InputDevice *device); void autoprofileLoad(AutoProfileInfo *info); // MainConfiguration class diff --git a/src/mousedialog/springmoderegionpreview.cpp b/src/mousedialog/springmoderegionpreview.cpp index 330398d60..47057c31e 100644 --- a/src/mousedialog/springmoderegionpreview.cpp +++ b/src/mousedialog/springmoderegionpreview.cpp @@ -26,9 +26,11 @@ SpringModeRegionPreview::SpringModeRegionPreview(int width, int height, QWidget *parent) : - +#if defined(Q_OS_WIN) + QWidget(parent, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) +#else QWidget(parent, Qt::FramelessWindowHint) - +#endif { int tempwidth = adjustSpringSizeWidth(width); int tempheight = adjustSpringSizeHeight(height); diff --git a/src/qkeydisplaydialog.cpp b/src/qkeydisplaydialog.cpp index 40e986bcb..7941387b4 100644 --- a/src/qkeydisplaydialog.cpp +++ b/src/qkeydisplaydialog.cpp @@ -32,6 +32,10 @@ #include "x11extras.h" #endif +#ifdef Q_OS_WIN + #include "winextras.h" +#endif + QKeyDisplayDialog::QKeyDisplayDialog(QWidget *parent) : QDialog(parent) , ui(new Ui::QKeyDisplayDialog) @@ -67,7 +71,10 @@ void QKeyDisplayDialog::keyReleaseEvent(QKeyEvent *event) int finalvirtual = 0; -#ifdef WITH_X11 +#ifdef Q_OS_WIN + finalvirtual = WinExtras::correctVirtualKey(scancode, virtualkey); + unsigned int tempvirtual = finalvirtual; +#elif defined WITH_X11 if (QApplication::platformName() == QStringLiteral("xcb")) { @@ -103,7 +110,11 @@ void QKeyDisplayDialog::keyReleaseEvent(QKeyEvent *event) ui->nativeKeyLabel->setText(QString("0x%1").arg(finalvirtual, 0, 16)); ui->qtKeyLabel->setText(QString("0x%1").arg(event->key(), 0, 16)); +#ifdef Q_OS_WIN + QString tempValue = QString("0x%1").arg(AntKeyMapper::getInstance()->returnQtKey(tempvirtual, scancode), 0, 16); +#else QString tempValue = QString("0x%1").arg(AntKeyMapper::getInstance()->returnQtKey(finalvirtual), 0, 16); +#endif ui->antimicroKeyLabel->setText(tempValue); } diff --git a/src/simplekeygrabberbutton.cpp b/src/simplekeygrabberbutton.cpp index 92b506b05..18695d833 100644 --- a/src/simplekeygrabberbutton.cpp +++ b/src/simplekeygrabberbutton.cpp @@ -31,6 +31,10 @@ #include #include +#ifdef Q_OS_WIN + #include "winextras.h" +#endif + SimpleKeyGrabberButton::SimpleKeyGrabberButton(QWidget *parent) : QPushButton(parent) { @@ -85,7 +89,15 @@ bool SimpleKeyGrabberButton::eventFilter(QObject *obj, QEvent *event) int finalvirtual = 0; int checkalias = 0; -#if defined(WITH_X11) +#ifdef Q_OS_WIN + BACKEND_ELSE_IF(handler->getIdentifier() == "sendinput") + { + // Find more specific virtual key (VK_SHIFT -> VK_LSHIFT) + // by checking for extended bit in scan code. + finalvirtual = WinExtras::correctVirtualKey(tempcode, virtualactual); + checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual, tempcode); + } +#elif defined(WITH_X11) if (QApplication::platformName() == QStringLiteral("xcb")) { diff --git a/src/winappprofiletimerdialog.cpp b/src/winappprofiletimerdialog.cpp new file mode 100755 index 000000000..aad3ffc33 --- /dev/null +++ b/src/winappprofiletimerdialog.cpp @@ -0,0 +1,22 @@ +#include "winappprofiletimerdialog.h" +#include "ui_winappprofiletimerdialog.h" + +WinAppProfileTimerDialog::WinAppProfileTimerDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::WinAppProfileTimerDialog) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); + + connect(&appTimer, SIGNAL(timeout()), this, SLOT(accept())); + connect(ui->capturePushButton, SIGNAL(clicked()), this, SLOT(startTimer())); + connect(ui->cancelPushButton, SIGNAL(clicked()), this, SLOT(close())); +} + +WinAppProfileTimerDialog::~WinAppProfileTimerDialog() { delete ui; } + +void WinAppProfileTimerDialog::startTimer() +{ + appTimer.start(ui->intervalSpinBox->value() * 1000); + this->setEnabled(false); +} diff --git a/src/winappprofiletimerdialog.h b/src/winappprofiletimerdialog.h new file mode 100755 index 000000000..6a44c03f5 --- /dev/null +++ b/src/winappprofiletimerdialog.h @@ -0,0 +1,32 @@ +#ifndef WINAPPPROFILETIMERDIALOG_H +#define WINAPPPROFILETIMERDIALOG_H + +#include +#include + +namespace Ui { +class WinAppProfileTimerDialog; +} + +class WinAppProfileTimerDialog : public QDialog +{ + Q_OBJECT + + public: + explicit WinAppProfileTimerDialog(QWidget *parent = 0); + ~WinAppProfileTimerDialog(); + + protected: + QTimer appTimer; + + // slots: + // void + + private: + Ui::WinAppProfileTimerDialog *ui; + + private slots: + void startTimer(); +}; + +#endif // WINAPPPROFILETIMERDIALOG_H diff --git a/src/winappprofiletimerdialog.ui b/src/winappprofiletimerdialog.ui new file mode 100755 index 000000000..ebe7e4a60 --- /dev/null +++ b/src/winappprofiletimerdialog.ui @@ -0,0 +1,96 @@ + + + WinAppProfileTimerDialog + + + + 0 + 0 + 420 + 178 + + + + Capture Application + + + true + + + + + + After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. + + + false + + + true + + + + + + + + + Timer: + + + + + + + 1 + + + 60 + + + + + + + Seconds + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Capture Application + + + + + + + Cancel + + + + + + + + + + diff --git a/src/winextras.cpp b/src/winextras.cpp index 4e6c5be4b..72e4524ea 100644 --- a/src/winextras.cpp +++ b/src/winextras.cpp @@ -250,6 +250,49 @@ unsigned int WinExtras::scancodeFromVirtualKey(unsigned int virtualkey, unsigned return scancode; } +/** + * @brief Check foreground window (window in focus) and obtain the + * corresponding exe file path. + * @return File path of executable + */ +QString WinExtras::getForegroundWindowExePath() +{ + QString exePath; + HWND foreground = GetForegroundWindow(); + HANDLE windowProcess = NULL; + if (foreground) + { + DWORD processId; + GetWindowThreadProcessId(foreground, &processId); + windowProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, true, processId); + } + + if (windowProcess != NULL) + { + TCHAR filename[MAX_PATH]; + memset(filename, 0, sizeof(filename)); + // qDebug() << QString::number(sizeof(filename)/sizeof(TCHAR)); + if (pQueryFullProcessImageNameW) + { + // Windows Vista and later + DWORD pathLength = MAX_PATH * sizeof(TCHAR); + pQueryFullProcessImageNameW(windowProcess, 0, filename, &pathLength); + // qDebug() << pathLength; + } else + { + // Windows XP + GetModuleFileNameEx(windowProcess, NULL, filename, MAX_PATH * sizeof(TCHAR)); + // qDebug() << pathLength; + } + + exePath = QString(filename); + // qDebug() << QString::fromWCharArray(filename); + CloseHandle(windowProcess); + } + + return exePath; +} + bool WinExtras::containsFileAssociationinRegistry() { bool result = false; @@ -301,6 +344,28 @@ void WinExtras::removeFileAssociationFromRegistry() SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0); } +/** + * @brief Attempt to elevate process using runas + * @return Execution status + */ +bool WinExtras::elevateAntiMicro() +{ + QString antiProgramLocation = QDir::toNativeSeparators(qApp->applicationFilePath()); + QByteArray temp = antiProgramLocation.toUtf8(); + SHELLEXECUTEINFO sei = {sizeof(sei)}; + char tempverb[6] = "runas"; + QByteArray ba = antiProgramLocation.toLocal8Bit(); + char *tempfile = ba.data(); + tempverb[5] = '\0'; + tempfile[antiProgramLocation.length()] = '\0'; + sei.lpVerb = tempverb; + sei.lpFile = tempfile; + sei.hwnd = NULL; + sei.nShow = SW_NORMAL; + BOOL result = ShellExecuteEx(&sei); + return result; +} + /** * @brief Check if the application is running with administrative privileges. * @return Status indicating administrative privileges @@ -387,6 +452,38 @@ void WinExtras::grabCurrentPointerPrecision() originalMouseAccel = mouseInfo[2]; } +/** + * @brief Get the window text of the window currently in focus. + * @return Window title of application in focus. + */ +QString WinExtras::getCurrentWindowText() +{ + QString windowText; + + HWND foreground = GetForegroundWindow(); + + if (foreground != NULL) + { + wchar_t foundWindowTitle[256]; + memset(foundWindowTitle, 0, sizeof(foundWindowTitle)); + GetWindowTextW(foreground, foundWindowTitle, 255); + QString temp = QString::fromWCharArray(foundWindowTitle); + if (temp.isEmpty()) + { + memset(foundWindowTitle, 0, sizeof(foundWindowTitle)); + SendMessageA(foreground, WM_GETTEXT, 255, (LPARAM)foundWindowTitle); + temp = QString::fromWCharArray(foundWindowTitle); + } + + if (!temp.isEmpty()) + { + windowText = temp; + } + } + + return windowText; +} + bool WinExtras::raiseProcessPriority() { bool result = false; diff --git a/src/winextras.h b/src/winextras.h index ef127c77a..0bdf469e2 100644 --- a/src/winextras.h +++ b/src/winextras.h @@ -16,14 +16,17 @@ class WinExtras : public QObject static unsigned int scancodeFromVirtualKey(unsigned int virtualkey, unsigned int alias = 0); static const unsigned int EXTENDED_FLAG; + static QString getForegroundWindowExePath(); static bool containsFileAssociationinRegistry(); static void writeFileAssocationToRegistry(); static void removeFileAssociationFromRegistry(); static bool IsRunningAsAdmin(); + static bool elevateAntiMicro(); static void disablePointerPrecision(); static void enablePointerPrecision(); static bool isUsingEnhancedPointerPrecision(); static void grabCurrentPointerPrecision(); + static QString getCurrentWindowText(); static bool raiseProcessPriority(); static QPoint getCursorPos(); diff --git a/src/xmlconfigmigration.cpp b/src/xmlconfigmigration.cpp index d93bae058..511223468 100644 --- a/src/xmlconfigmigration.cpp +++ b/src/xmlconfigmigration.cpp @@ -134,6 +134,9 @@ QString XMLConfigMigration::version0006Migration() if (slotmode == "keyboard") { int tempcode = slotcode; +#ifdef Q_OS_WIN + slotcode = AntKeyMapper::getInstance()->returnQtKey(slotcode); +#else BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); @@ -145,7 +148,7 @@ QString XMLConfigMigration::version0006Migration() slotcode = 0; tempcode = 0; } - +#endif if (slotcode > 0) { writer.writeTextElement("code", QString("0x%1").arg(slotcode, 0, 16));