summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2015-05-22 17:00:10 +0200
committerStanislaw Halik <sthalik@misaki.pl>2015-05-22 17:00:10 +0200
commit0148b26e427d7a5bbe24cdff14f3e035dc19bd1c (patch)
tree2ba08da225039948586aee8b17d87c4ed3aa6d36
parent65bad699fc8472b49189a412f730409eb2e96311 (diff)
main: allow automatically run profiles when executables run
Issue: #160
-rw-r--r--facetracknoir/keyboard.ui19
-rw-r--r--facetracknoir/process_detector.cpp243
-rw-r--r--facetracknoir/process_detector.h93
-rw-r--r--facetracknoir/process_widget.ui109
-rw-r--r--facetracknoir/shortcut-dialog.cpp2
-rw-r--r--facetracknoir/ui.cpp41
-rw-r--r--facetracknoir/ui.h9
7 files changed, 504 insertions, 12 deletions
diff --git a/facetracknoir/keyboard.ui b/facetracknoir/keyboard.ui
index cdfc0657..4ec3ce49 100644
--- a/facetracknoir/keyboard.ui
+++ b/facetracknoir/keyboard.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>461</width>
- <height>181</height>
+ <height>413</height>
</rect>
</property>
<property name="sizePolicy">
@@ -289,6 +289,16 @@
</widget>
</item>
<item>
+ <widget class="process_detector" name="game_detector">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
@@ -297,6 +307,13 @@
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>process_detector</class>
+ <extends>QWidget</extends>
+ <header>facetracknoir/process_detector.h</header>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
<slots>
diff --git a/facetracknoir/process_detector.cpp b/facetracknoir/process_detector.cpp
new file mode 100644
index 00000000..3ac6329b
--- /dev/null
+++ b/facetracknoir/process_detector.cpp
@@ -0,0 +1,243 @@
+#include "process_detector.h"
+#include "facetracknoir/ui.h"
+#include <QList>
+#include <QFileDialog>
+#include <QComboBox>
+#include <QString>
+#include <QHash>
+#include <QPushButton>
+
+void settings::set_game_list(const QString &game_list)
+{
+ QSettings settings(group::org);
+ settings.setValue("executable-list", game_list);
+}
+
+QString settings::get_game_list()
+{
+ QSettings settings(group::org);
+ return settings.value("executable-list").toString();
+}
+
+bool settings::is_enabled()
+{
+ QSettings settings(group::org);
+ return settings.value("executable-detector-enabled", false).toBool();
+}
+
+void settings::set_is_enabled(bool enabled)
+{
+ QSettings settings(group::org);
+ settings.setValue("executable-detector-enabled", enabled);
+}
+
+QHash<QString, QString> settings::split_process_names()
+{
+ QHash<QString, QString> ret;
+ QString str = get_game_list();
+ QStringList pairs = str.split('|');
+ for (auto pair : pairs)
+ {
+ QList<QString> tmp = pair.split(':');
+ if (tmp.count() != 2)
+ continue;
+ ret[tmp[0]] = tmp[1];
+ }
+ return ret;
+}
+
+void BrowseButton::browse()
+{
+ QFileDialog dialog(this);
+ dialog.setFileMode(QFileDialog::ExistingFile);
+ QString dir_path = QFileInfo(group::ini_pathname()).absolutePath();
+ QString filename = dialog.getOpenFileName(
+ this,
+ tr("Set executable name"),
+ dir_path,
+ tr("Executable (*.exe);;All Files (*)"));
+ MainWindow::set_working_directory();
+ filename = QFileInfo(filename).fileName();
+ twi->setText(filename);
+}
+
+process_detector::add_row(QString exe_name, QString profile)
+{
+ int i = ui.tableWidget->rowCount();
+ ui.tableWidget->insertRow(i);
+
+ QComboBox* cb = new QComboBox();
+ cb->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum);
+ cb->addItems(group::ini_list());
+ ui.tableWidget->setCellWidget(i, 1, cb);
+
+ QTableWidgetItem* twi = new QTableWidgetItem(exe_name);
+ ui.tableWidget->setItem(i, 0, twi);
+
+ {
+ BrowseButton* b = new BrowseButton(twi);
+ b->setText("...");
+ QObject::connect(b, SIGNAL(pressed()), b, SLOT(browse()));
+ ui.tableWidget->setCellWidget(i, 2, b);
+ }
+
+ cb->setCurrentText(profile);
+
+ return i;
+}
+
+void process_detector::add_items()
+{
+ auto names = s.split_process_names();
+ ui.tableWidget->clearContents();
+ auto keys = names.keys();
+ qSort(keys);
+ for (auto n : keys)
+ add_row(n, names[n]);
+}
+
+process_detector::process_detector(QWidget* parent) : QWidget(parent)
+{
+ ui.setupUi(this);
+ connect(ui.add, SIGNAL(pressed()), this, SLOT(add()));
+ connect(ui.remove, SIGNAL(pressed()), this, SLOT(remove()));
+
+ add_items();
+
+ QResizeEvent e(ui.tableWidget->size(), ui.tableWidget->size());
+ ui.tableWidget->resizeEvent(&e);
+
+ settings s;
+
+ ui.enabled->setChecked(s.is_enabled());
+}
+
+void process_detector::save()
+{
+ QString str;
+
+ for (int i = 0; i < ui.tableWidget->rowCount(); i++)
+ {
+ auto exe = ui.tableWidget->item(i, 0)->text();
+ auto profile = reinterpret_cast<QComboBox*>(ui.tableWidget->cellWidget(i, 1))->currentText();
+ str += "|" + exe + ":" + profile;
+ }
+
+ s.set_game_list(str);
+ s.set_is_enabled(ui.enabled->isChecked());
+}
+
+void process_detector::revert()
+{
+}
+
+void process_detector::add()
+{
+ add_row();
+}
+
+void process_detector::remove()
+{
+ int r = ui.tableWidget->currentRow();
+ if (r != -1)
+ ui.tableWidget->removeRow(r);
+}
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include <TlHelp32.h>
+
+bool process_detector_worker::should_stop()
+{
+ if (last_exe_name == "")
+ return false;
+
+ settings s;
+
+ if (!s.is_enabled())
+ {
+ last_exe_name = "";
+ return false;
+ }
+
+ HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (h == INVALID_HANDLE_VALUE)
+ return false;
+
+ PROCESSENTRY32 e;
+
+ if (Process32First(h, &e) == TRUE)
+ {
+ QString exe_name(e.szExeFile);
+ if (exe_name == last_exe_name)
+ {
+ CloseHandle(h);
+ return false;
+ }
+ }
+
+ while (Process32Next(h, &e) == TRUE)
+ {
+ QString exe_name(e.szExeFile);
+ if (exe_name == last_exe_name)
+ {
+ CloseHandle(h);
+ return false;
+ }
+ }
+
+ last_exe_name = "";
+ CloseHandle(h);
+
+ return true;
+}
+
+bool process_detector_worker::config_to_start(QString& str)
+{
+ settings s;
+ if (!s.is_enabled())
+ {
+ last_exe_name = "";
+ return false;
+ }
+
+ auto filenames = s.split_process_names();
+
+ HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (h == INVALID_HANDLE_VALUE)
+ return false;
+
+ PROCESSENTRY32 e;
+
+ if (Process32First(h, &e) == TRUE)
+ {
+ QString exe_name(e.szExeFile);
+ if (filenames.contains(exe_name))
+ {
+ str = filenames[exe_name];
+ last_exe_name = str;
+ CloseHandle(h);
+ return true;
+ }
+ }
+
+ while (Process32Next(h, &e) == TRUE)
+ {
+ QString exe_name(e.szExeFile);
+ if (filenames.contains(exe_name))
+ {
+ str = filenames[exe_name];
+ last_exe_name = str;
+ CloseHandle(h);
+ return true;
+ }
+ }
+
+ CloseHandle(h);
+
+ return false;
+}
+
+
+#endif
diff --git a/facetracknoir/process_detector.h b/facetracknoir/process_detector.h
new file mode 100644
index 00000000..2333ecc6
--- /dev/null
+++ b/facetracknoir/process_detector.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include <QObject>
+#include <QWidget>
+#include <QTableWidget>
+#include <QResizeEvent>
+
+#include "opentrack/options.hpp"
+using namespace options;
+
+class FancyTable : public QTableWidget
+{
+ Q_OBJECT
+public:
+ void resizeEvent(QResizeEvent* e) override
+ {
+ QTableView::resizeEvent(e);
+ int w = width();
+ setColumnWidth(2, 32);
+ w -= 48;
+ setColumnWidth(0, w / 2);
+ setColumnWidth(1, w / 2);
+ }
+public:
+ FancyTable(QWidget* parent = nullptr) : QTableWidget(parent) {}
+};
+
+struct settings
+{
+ QHash<QString, QString> split_process_names();
+ QString get_game_list();
+ void set_game_list(const QString& game_list);
+ bool is_enabled();
+ void set_is_enabled(bool enabled);
+};
+
+#include "ui_process_widget.h"
+
+class process_detector : public QWidget
+{
+ Q_OBJECT
+
+ Ui_Dialog ui;
+ settings s;
+
+ int add_row(QString exe_name = "...", QString profile = "");
+ void add_items();
+public:
+ process_detector(QWidget* parent = nullptr);
+public slots:
+ void save();
+ void revert();
+private slots:
+ void add();
+ void remove();
+};
+
+class BrowseButton : public QPushButton
+{
+ Q_OBJECT
+ QTableWidgetItem* twi;
+public:
+ BrowseButton(QTableWidgetItem* twi) : twi(twi)
+ {}
+public slots:
+ void browse();
+};
+
+#ifdef _WIN32
+
+class process_detector_worker : QObject
+{
+ Q_OBJECT
+ settings s;
+ QString last_exe_name;
+public:
+ bool config_to_start(QString& s);
+ bool should_stop();
+};
+
+#else
+
+class process_detector_worker : QObject
+{
+ Q_OBJECT
+public:
+ bool config_to_start(QString&)
+ {
+ return false;
+ }
+};
+
+#endif
diff --git a/facetracknoir/process_widget.ui b/facetracknoir/process_widget.ui
new file mode 100644
index 00000000..ff0ace71
--- /dev/null
+++ b/facetracknoir/process_widget.ui
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QWidget" name="Dialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>327</width>
+ <height>346</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Game detector</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="FancyTable" name="tableWidget">
+ <column>
+ <property name="text">
+ <string>Executable</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Profile</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string/>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="add">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>14</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>+</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="remove">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>14</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="enabled">
+ <property name="text">
+ <string>Start profiles from game executable names in this list</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>FancyTable</class>
+ <extends>QTableWidget</extends>
+ <header>facetracknoir/process_detector.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/facetracknoir/shortcut-dialog.cpp b/facetracknoir/shortcut-dialog.cpp
index c157078e..b4c236c6 100644
--- a/facetracknoir/shortcut-dialog.cpp
+++ b/facetracknoir/shortcut-dialog.cpp
@@ -36,6 +36,7 @@ KeyboardShortcutDialog::KeyboardShortcutDialog()
void KeyboardShortcutDialog::doOK() {
s.b->save();
s.s_main.b->save();
+ ui.game_detector->save();
this->close();
emit reload();
}
@@ -43,5 +44,6 @@ void KeyboardShortcutDialog::doOK() {
void KeyboardShortcutDialog::doCancel() {
s.b->reload();
s.s_main.b->reload();
+ ui.game_detector->revert();
close();
}
diff --git a/facetracknoir/ui.cpp b/facetracknoir/ui.cpp
index 4c6c694c..fb28c3c6 100644
--- a/facetracknoir/ui.cpp
+++ b/facetracknoir/ui.cpp
@@ -79,6 +79,9 @@ MainWindow::MainWindow() :
connect(&pose_update_timer, SIGNAL(timeout()), this, SLOT(showHeadPose()));
connect(&kbd_quit, SIGNAL(activated()), this, SLOT(exit()));
kbd_quit.setEnabled(true);
+
+ connect(&det_timer, SIGNAL(timeout()), this, SLOT(maybe_start_profile_from_executable()));
+ det_timer.start(3000);
ensure_tray();
}
@@ -179,16 +182,13 @@ extern "C" volatile const char* opentrack_version;
void MainWindow::fill_profile_combobox()
{
- QString currentFile = group::ini_pathname();
- qDebug() << "Config file now" << currentFile;
- QFileInfo pathInfo ( currentFile );
- setWindowTitle(QString( const_cast<const char*>(opentrack_version) + QStringLiteral(" :: ")) + pathInfo.fileName());
- QDir settingsDir( pathInfo.dir() );
- auto iniFileList = settingsDir.entryList( QStringList { "*.ini" } , QDir::Files, QDir::Name );
+ QStringList ini_list = group::ini_list();
+ QString current = QFileInfo(group::ini_pathname()).fileName();
+ setWindowTitle(QString( const_cast<const char*>(opentrack_version) + QStringLiteral(" :: ")) + current);
ui.iconcomboProfile->clear();
- for (auto x : iniFileList)
+ for (auto x : ini_list)
ui.iconcomboProfile->addItem(QIcon(":/images/settings16.png"), x);
- ui.iconcomboProfile->setCurrentText(pathInfo.fileName());
+ ui.iconcomboProfile->setCurrentText(current);
}
void MainWindow::updateButtonState(bool running, bool inertialp)
@@ -486,3 +486,28 @@ void MainWindow::changeEvent(QEvent* e)
}
QMainWindow::changeEvent(e);
}
+
+void MainWindow::maybe_start_profile_from_executable()
+{
+ if (!work)
+ {
+ QString prof;
+ if (det.config_to_start(prof))
+ {
+ QString profile = QFileInfo(group::ini_pathname()).absolutePath() + "/" + prof;
+ set_profile(profile);
+ startTracker();
+ }
+ }
+ else
+ {
+ if (det.should_stop())
+ stopTracker();
+ }
+}
+
+void MainWindow::set_profile(const QString &profile)
+{
+ QSettings settings(group::org);
+ settings.setValue(group::filename_key, MainWindow::remove_app_path(profile));
+}
diff --git a/facetracknoir/ui.h b/facetracknoir/ui.h
index aea4991d..d0ea4e75 100644
--- a/facetracknoir/ui.h
+++ b/facetracknoir/ui.h
@@ -55,6 +55,7 @@
#include "opentrack/state.hpp"
#include "curve-config.h"
#include "shortcut-dialog.hpp"
+#include "process_detector.h"
using namespace options;
@@ -65,6 +66,7 @@ class MainWindow : public QMainWindow, private State
Ui::OpentrackUI ui;
mem<QSystemTrayIcon> tray;
QTimer pose_update_timer;
+ QTimer det_timer;
mem<KeyboardShortcutDialog> shortcuts_widget;
mem<MapWidget> mapping_widget;
QShortcut kbd_quit;
@@ -72,6 +74,7 @@ class MainWindow : public QMainWindow, private State
mem<IFilterDialog> pFilterDialog;
mem<IProtocolDialog> pProtocolDialog;
mem<ITrackerDialog> pTrackerDialog;
+ process_detector_worker det;
mem<dylib> current_tracker()
{
@@ -94,7 +97,6 @@ class MainWindow : public QMainWindow, private State
void fill_profile_combobox();
void display_pose(const double* mapped, const double* raw);
void ensure_tray();
- void set_working_directory();
public slots:
void shortcutRecentered();
void shortcutToggled();
@@ -115,15 +117,16 @@ private slots:
void showHeadPose();
void restore_from_tray(QSystemTrayIcon::ActivationReason);
-
+ void maybe_start_profile_from_executable();
public slots:
void startTracker();
void stopTracker();
-
public:
MainWindow();
~MainWindow();
void save_mappings();
void load_mappings();
static QString remove_app_path(const QString full_path);
+ static void set_working_directory();
+ static void set_profile(const QString& profile);
};