diff options
Diffstat (limited to 'proto-ft')
| -rw-r--r-- | proto-ft/ftnoir_ftcontrols.ui | 293 | ||||
| -rw-r--r-- | proto-ft/ftnoir_protocol_ft.cpp | 299 | ||||
| -rw-r--r-- | proto-ft/ftnoir_protocol_ft.h | 69 | ||||
| -rw-r--r-- | proto-ft/ftnoir_protocol_ft_dialog.cpp | 53 | ||||
| -rw-r--r-- | proto-ft/lang/nl_NL.ts | 68 | ||||
| -rw-r--r-- | proto-ft/lang/ru_RU.ts | 92 | ||||
| -rw-r--r-- | proto-ft/lang/stub.ts | 68 | ||||
| -rw-r--r-- | proto-ft/lang/zh_CN.ts | 106 | ||||
| -rw-r--r-- | proto-ft/mutex.cpp | 60 | ||||
| -rw-r--r-- | proto-ft/mutex.hpp | 16 |
10 files changed, 620 insertions, 504 deletions
diff --git a/proto-ft/ftnoir_ftcontrols.ui b/proto-ft/ftnoir_ftcontrols.ui index e8098505..8edf5a9d 100644 --- a/proto-ft/ftnoir_ftcontrols.ui +++ b/proto-ft/ftnoir_ftcontrols.ui @@ -12,22 +12,10 @@ <rect> <x>0</x> <y>0</y> - <width>515</width> - <height>429</height> + <width>533</width> + <height>326</height> </rect> </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> <property name="windowTitle"> <string>freetrack protocol settings</string> </property> @@ -42,45 +30,15 @@ <bool>false</bool> </property> <layout class="QGridLayout" name="gridLayout_2"> - <item row="1" column="0"> - <widget class="QGroupBox" name="groupBox_3"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="title"> - <string>Select interface</string> - </property> - <property name="alignment"> - <set>Qt::AlignJustify|Qt::AlignTop</set> - </property> - <property name="flat"> - <bool>false</bool> + <item row="5" column="0"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <property name="spacing"> - <number>9</number> - </property> - <item> - <widget class="QComboBox" name="cbxSelectInterface"/> - </item> - <item> - <widget class="QLabel" name="label_8"> - <property name="text"> - <string>Disable one of the protocols if game is confused by presence of both at the same time.</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> </widget> </item> <item row="0" column="0"> - <widget class="QGroupBox" name="groupBox"> + <widget class="QGroupBox" name="groupBox_3"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -88,7 +46,7 @@ </sizepolicy> </property> <property name="title"> - <string>TIRViews</string> + <string>Select interface</string> </property> <property name="alignment"> <set>Qt::AlignJustify|Qt::AlignTop</set> @@ -96,33 +54,33 @@ <property name="flat"> <bool>false</bool> </property> - <layout class="QHBoxLayout" name="horizontalLayout_4"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> <property name="spacing"> <number>9</number> </property> <item> - <widget class="QCheckBox" name="chkTIRViews"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Memory hacks</string> - </property> + <widget class="QComboBox" name="cbxSelectInterface"> + <item> + <property name="text"> + <string>Enable both</string> + </property> + </item> + <item> + <property name="text"> + <string>Use freetrack, disable TrackIR</string> + </property> + </item> + <item> + <property name="text"> + <string>Use TrackIR, disable freetrack</string> + </property> + </item> </widget> </item> <item> - <widget class="QLabel" name="label_2"> + <widget class="QLabel" name="label_8"> <property name="text"> - <string>Only for very old and buggy old games such as CFS3.</string> - </property> - <property name="scaledContents"> - <bool>false</bool> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + <string>Disable one of the protocols if game is confused by presence of both at the same time.</string> </property> <property name="wordWrap"> <bool>true</bool> @@ -132,98 +90,123 @@ </layout> </widget> </item> - <item row="2" column="0"> + <item row="1" column="0" rowspan="2"> <widget class="QGroupBox" name="groupBox_4"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> <property name="title"> - <string>Repair NPClient location</string> + <string>Library location</string> </property> <property name="alignment"> <set>Qt::AlignJustify|Qt::AlignTop</set> </property> - <property name="flat"> - <bool>false</bool> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <property name="spacing"> - <number>9</number> - </property> - <item> - <widget class="QPushButton" name="bntLocateNPClient"> - <property name="text"> - <string>Locate DLL</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_10"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Replace the registry entry if you want to use other software with the NPClient protocol and it doesn't work automatically. + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QWidget" name="widget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="bntLocateNPClient"> + <property name="text"> + <string>Locate DLL</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_10"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Replace the registry entry if you want to use other software with the NPClient protocol and it doesn't work automatically. Starting tracking will again overwrite the DLL locations.</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> </widget> </item> - </layout> - </widget> - </item> - <item row="4" column="0"> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QGroupBox" name="groupBox_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="title"> - <string>Disable tracking for games on exit</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <property name="spacing"> - <number>9</number> - </property> - <item> - <widget class="QCheckBox" name="close_on_exit"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Disable on program exit</string> - </property> + <item row="1" column="0"> + <widget class="QWidget" name="widget2" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>6</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="enable_custom_location"> + <property name="toolTip"> + <string>Useful for titles like Elite: Dangerous that require the library to reside in a specified location. Use this to avoid relocating your opentrack installation.</string> + </property> + <property name="text"> + <string>Custom location</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="custom_location"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="set_custom_location"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Browse...</string> + </property> + </widget> + </item> + </layout> </widget> </item> - <item> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Use this for games that disable mouselook when opentrack isn't running, and you're not running opentrack that much. To use opentrack with this option you need to start it before the games to have it work at all.</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> + <item row="2" column="0"> + <widget class="QWidget" name="widget_2" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <property name="spacing"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QCheckBox" name="ephemeral_registry_entry"> + <property name="toolTip"> + <string>This is useful when you're only evaluating opentrack, and haven't yet decided to use it all the time.</string> + </property> + <property name="text"> + <string>Clear location when tracking is stopped</string> + </property> + </widget> + </item> + </layout> </widget> </item> </layout> @@ -231,8 +214,20 @@ Starting tracking will again overwrite the DLL locations.</string> </item> </layout> </widget> + <tabstops> + <tabstop>cbxSelectInterface</tabstop> + <tabstop>bntLocateNPClient</tabstop> + <tabstop>enable_custom_location</tabstop> + <tabstop>custom_location</tabstop> + <tabstop>set_custom_location</tabstop> + <tabstop>ephemeral_registry_entry</tabstop> + </tabstops> <resources> <include location="ft-protocol.qrc"/> + <include location="ft-protocol.qrc"/> + <include location="ft-protocol.qrc"/> + <include location="ft-protocol.qrc"/> + <include location="ft-protocol.qrc"/> </resources> <connections/> <slots> diff --git a/proto-ft/ftnoir_protocol_ft.cpp b/proto-ft/ftnoir_protocol_ft.cpp index 429ff72b..7f710621 100644 --- a/proto-ft/ftnoir_protocol_ft.cpp +++ b/proto-ft/ftnoir_protocol_ft.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015 Stanislaw Halik <sthalik@misaki.pl> +/* Copyright (c) 2013-2015, 2017 Stanislaw Halik <sthalik@misaki.pl> * Copyright (c) 2015 Wim Vriend * * Permission to use, copy, modify, and/or distribute this software for any @@ -6,190 +6,231 @@ * copyright notice and this permission notice appear in all copies. */ +#include "compat/library-path.hpp" + #include "ftnoir_protocol_ft.h" #include "csv/csv.h" -#include "opentrack-library-path.h" +#include <QDir> +#include <cstddef> #include <cmath> +#include <windows.h> + +freetrack::~freetrack() +{ + //dummyTrackIR.kill(); dummyTrackIR.waitForFinished(); + if (s.ephemeral_library_location) + { + QSettings settings_ft("Freetrack", "FreetrackClient"); + QSettings settings_npclient("NaturalPoint", "NATURALPOINT\\NPClient Location"); + + settings_ft.setValue("Path", ""); + settings_npclient.setValue("Path", ""); + + if (dummyTrackIR.state() == dummyTrackIR.Running) + { + dummyTrackIR.kill(); + dummyTrackIR.waitForFinished(100); + } + } + else + dummyTrackIR.close(); +} -check_for_first_run freetrack::runonce_check = check_for_first_run(); +static_assert(sizeof(LONG) == sizeof(std::int32_t)); +static_assert(sizeof(LONG) == 4u); -freetrack::freetrack() : - shm(FREETRACK_HEAP, FREETRACK_MUTEX, sizeof(FTHeap)), - pMemData((FTHeap*) shm.ptr()), - viewsStart(nullptr), - viewsStop(nullptr), - intGameID(0) +never_inline void store(float volatile& place, const float value) { - runonce_check.set_enabled(s.close_protocols_on_exit); - QObject::connect(&s.close_protocols_on_exit, - static_cast<void (base_value::*)(bool) const>(&value<bool>::valueChanged), - [] (bool flag) -> void { runonce_check.set_enabled(flag); }); - runonce_check.try_runonce(); + union + { + float f32; + LONG i32; + } value_ {}; + + value_.f32 = value; + + static_assert(sizeof(value_) == sizeof(float)); + static_assert(offsetof(decltype(value_), f32) == offsetof(decltype(value_), i32)); + + (void)InterlockedExchange((LONG volatile*)&place, value_.i32); } -freetrack::~freetrack() +template<typename t> +static void store(t volatile& place, t value) { - if (viewsStop != NULL) { - viewsStop(); - FTIRViewsLib.unload(); - } - dummyTrackIR.kill(); - dummyTrackIR.close(); + static_assert(sizeof(t) == 4u); + (void)InterlockedExchange((LONG volatile*) &place, (LONG)value); +} + +static std::int32_t load(std::int32_t volatile& place) +{ + return InterlockedCompareExchange((volatile LONG*) &place, 0, 0); } -void freetrack::pose(const double* headpose) +void freetrack::pose(const double* headpose, const double* raw) { - const float yaw = -degrees_to_rads(headpose[Yaw]); - const float pitch = -degrees_to_rads(headpose[Pitch]); - const float roll = degrees_to_rads(headpose[Roll]); + constexpr double d2r = M_PI/180; + + const float yaw = float(-headpose[Yaw] * d2r); + const float roll = float(headpose[Roll] * d2r); const float tx = float(headpose[TX] * 10); const float ty = float(headpose[TY] * 10); const float tz = float(headpose[TZ] * 10); - FTHeap* ft = pMemData; - FTData* data = &ft->data; - - data->RawX = 0; - data->RawY = 0; - data->RawZ = 0; - data->RawPitch = 0; - data->RawYaw = 0; - data->RawRoll = 0; - - data->X = tx; - data->Y = ty; - data->Z = tz; - data->Yaw = yaw; - data->Pitch = pitch; - data->Roll = roll; - - data->X1 = data->DataID; - data->X2 = 0; - data->X3 = 0; - data->X4 = 0; - data->Y1 = 0; - data->Y2 = 0; - data->Y3 = 0; - data->Y4 = 0; - - int32_t id = ft->GameID; + // HACK: Falcon BMS makes a "bump" if pitch is over the value -sh 20170615 + const bool is_crossing_90 = std::fabs(headpose[Pitch] - 90) < .15; + const float pitch = float(-d2r * (is_crossing_90 ? 89.86 : headpose[Pitch])); + + FTHeap* const ft = pMemData; + FTData* const data = &ft->data; + + store(data->X, tx); + store(data->Y, ty); + store(data->Z, tz); + + store(data->Yaw, yaw); + store(data->Pitch, pitch); + store(data->Roll, roll); + + store(data->RawYaw, float(-raw[Yaw] * d2r)); + store(data->RawPitch, float(raw[Pitch] * d2r)); + store(data->RawRoll, float(raw[Roll] * d2r)); + store(data->RawX, float(raw[TX] * 10)); + store(data->RawY, float(raw[TY] * 10)); + store(data->RawZ, float(raw[TZ] * 10)); + + const std::int32_t id = load(ft->GameID); if (intGameID != id) { QString gamename; - { - unsigned char table[8] = { 0,0,0,0, 0,0,0,0 }; + union { + unsigned char table[8]; + std::int32_t ints[2]; + } t {}; + + t.ints[0] = 0; t.ints[1] = 0; - (void) CSV::getGameData(id, table, gamename); + (void)CSV::getGameData(id, t.table, gamename); - for (int i = 0; i < 8; i++) - pMemData->table[i] = table[i]; + { + // FTHeap pMemData happens to be aligned on a page boundary by virtue of + // memory mapping usage (MS Windows equivalent of mmap(2)). + static_assert((offsetof(FTHeap, table) & (sizeof(LONG)-1)) == 0); + + for (unsigned k = 0; k < 2; k++) + store(pMemData->table_ints[k], t.ints[k]); } - ft->GameID2 = id; + + store(ft->GameID2, id); + store(data->DataID, 0u); + intGameID = id; + + if (gamename.isEmpty()) + gamename = tr("Unknown game"); + QMutexLocker foo(&game_name_mutex); connected_game = gamename; } - - data->DataID += 1; -} - -float freetrack::degrees_to_rads(double degrees) -{ - return float(degrees*M_PI/180); + else + (void)InterlockedAdd((LONG volatile*)&data->DataID, 1); } -void freetrack::start_tirviews() +QString freetrack::game_name() { - QString aFileName = OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH "TIRViews.dll"; - if ( QFile::exists( aFileName )) { - FTIRViewsLib.setFileName(aFileName); - FTIRViewsLib.load(); - - viewsStart = (importTIRViewsStart) FTIRViewsLib.resolve("TIRViewsStart"); - if (viewsStart == NULL) { - qDebug() << "FTServer::run() says: TIRViewsStart function not found in DLL!"; - } - else { - qDebug() << "FTServer::run() says: TIRViewsStart executed!"; - viewsStart(); - } - - // - // Load the Stop function from TIRViews.dll. Call it when terminating the thread. - // - viewsStop = (importTIRViewsStop) FTIRViewsLib.resolve("TIRViewsStop"); - if (viewsStop == NULL) { - qDebug() << "FTServer::run() says: TIRViewsStop function not found in DLL!"; - } - } + QMutexLocker foo(&game_name_mutex); + return connected_game; } void freetrack::start_dummy() { - QString program = OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH "TrackIR.exe"; + static const QString program = OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH "TrackIR.exe"; dummyTrackIR.setProgram("\"" + program + "\""); dummyTrackIR.start(); } -void freetrack::set_protocols(bool ft, bool npclient) +module_status freetrack::set_protocols() { - const QString program_dir = OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH; + static const QString program_dir = OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH; // Registry settings (in HK_USER) QSettings settings_ft("Freetrack", "FreetrackClient"); QSettings settings_npclient("NaturalPoint", "NATURALPOINT\\NPClient Location"); - if (ft) - settings_ft.setValue("Path", program_dir); - else - settings_ft.setValue("Path", ""); + QString location = *s.custom_location_pathname; + + bool use_freetrack = true, use_npclient = true; + switch (*s.used_interface) + { + case settings::enable_npclient: use_freetrack = false; break; + case settings::enable_freetrack: use_npclient = false; break; + case settings::enable_both: use_freetrack = true; use_npclient = true; break; + default: + return error(tr("proto/freetrack: wrong interface selection '%1'") + .arg(*s.used_interface)); + } - if (npclient) - settings_npclient.setValue("Path", program_dir); + if (!s.use_custom_location || s.custom_location_pathname->isEmpty() || !QDir{s.custom_location_pathname}.exists()) + location = program_dir; else - settings_npclient.setValue("Path", ""); + { + bool copy = true; + + if (use_npclient && !QFile{location + "/NPClient.dll"}.exists()) + copy &= QFile::copy(program_dir + "/NPClient.dll", location + "/NPClient.dll"); + if (use_npclient && !QFile{location + "/NPClient64.dll"}.exists()) + copy &= QFile::copy(program_dir + "/NPClient64.dll", location + "/NPClient64.dll"); + if (use_freetrack && !QFile{location + "/freetrackclient.dll"}.exists()) + copy &= QFile::copy(program_dir + "/freetrackclient.dll", location + "/freetrackclient.dll"); + if (use_freetrack && !QFile{location + "/freetrackclient64.dll"}.exists()) + copy &= QFile::copy(program_dir + "/freetrackclient64.dll", location + "/freetrackclient64.dll"); + + if (!copy) + return {tr("Can't copy library to selected custom location '%1'").arg(s.custom_location_pathname)}; + } + + location.replace('\\', '/'); + if (!location.endsWith('/')) + location += '/'; + + settings_ft.setValue("Path", use_freetrack ? location : ""); + settings_npclient.setValue("Path", use_npclient ? location : ""); + + return {}; } -bool freetrack::correct() +module_status freetrack::initialize() { if (!shm.success()) - return false; - - bool use_ft = false, use_npclient = false; - - switch (s.intUsedInterface) { - case 0: - use_ft = true; - use_npclient = true; - break; - case 1: - use_ft = true; - break; - case 2: - use_npclient = true; - break; - default: - break; - } + return error(tr("Can't load freetrack memory mapping")); - set_protocols(use_ft, use_npclient); - - if (s.useTIRViews) { - start_tirviews(); - } - - // more games need the dummy executable than previously thought - start_dummy(); + if (auto ret = set_protocols(); !ret.is_ok()) + return ret; pMemData->data.DataID = 1; pMemData->data.CamWidth = 100; pMemData->data.CamHeight = 250; - pMemData->GameID2 = 0; - for (int i = 0; i < 8; i++) - pMemData->table[i] = 0; - return true; +#if 0 + store(pMemData->data.X1, float(100)); + store(pMemData->data.Y1, float(200)); + store(pMemData->data.X2, float(300)); + store(pMemData->data.Y2, float(200)); + store(pMemData->data.X3, float(300)); + store(pMemData->data.Y3, float(100)); +#endif + + store(pMemData->GameID2, 0); + + for (unsigned k = 0; k < 2; k++) + store(pMemData->table_ints[k], 0); + + // more games need the dummy executable than previously thought + if (s.used_interface != settings::enable_freetrack) + start_dummy(); + + return status_ok(); } OPENTRACK_DECLARE_PROTOCOL(freetrack, FTControls, freetrackDll) diff --git a/proto-ft/ftnoir_protocol_ft.h b/proto-ft/ftnoir_protocol_ft.h index e5a63e17..a07747d9 100644 --- a/proto-ft/ftnoir_protocol_ft.h +++ b/proto-ft/ftnoir_protocol_ft.h @@ -9,69 +9,59 @@ #pragma once #include "ui_ftnoir_ftcontrols.h" #include "api/plugin-api.hpp" -#include <QMessageBox> -#include <QSettings> -#include <QLibrary> + #include <QProcess> -#include <QDebug> -#include <QFile> #include <QString> #include <QMutex> -#include <QMutexLocker> + +#include <QDebug> + +#include <cinttypes> +#include "freetrackclient/fttypes.h" + #include "compat/shm.h" #include "options/options.hpp" -#include "freetrackclient/fttypes.h" + #include <memory> -#include "mutex.hpp" using namespace options; struct settings : opts { - value<int> intUsedInterface; - value<bool> useTIRViews, close_protocols_on_exit; - settings() : - opts("proto-freetrack"), - intUsedInterface(b, "used-interfaces", 0), - useTIRViews(b, "use-memory-hacks", false), - close_protocols_on_exit(b, "close-protocols-on-exit", false) - {} + enum enable_status : int { enable_both, enable_freetrack, enable_npclient, }; + value<int> used_interface{b, "used-interfaces", (int)enable_both}; + value<bool> ephemeral_library_location{b, "ephemeral-library-location", false}; + value<bool> use_custom_location{b, "use-custom-location", false}; + value<QString> custom_location_pathname{b, "custom-library-location", {}}; + settings() : opts("proto-freetrack") {} }; -typedef void (__stdcall *importTIRViewsStart)(void); -typedef void (__stdcall *importTIRViewsStop)(void); - -class freetrack : public IProtocol +class freetrack : TR, public IProtocol { + Q_OBJECT + public: - freetrack(); + freetrack() = default; ~freetrack() override; - bool correct(); - void pose( const double *headpose ); - QString game_name() override { - QMutexLocker foo(&game_name_mutex); - return connected_game; - } + module_status initialize() override; + void pose(const double* pose, const double*) override; + QString game_name() override; private: settings s; - PortableLockedShm shm; - FTHeap *pMemData; + shm_wrapper shm { FREETRACK_HEAP, FREETRACK_MUTEX, sizeof(FTHeap) }; + FTHeap* pMemData { (FTHeap*) shm.ptr() }; - QLibrary FTIRViewsLib; QProcess dummyTrackIR; - importTIRViewsStart viewsStart; - importTIRViewsStop viewsStop; - int intGameID; + int intGameID = -1; QString connected_game; QMutex game_name_mutex; - static check_for_first_run runonce_check; - void start_tirviews(); void start_dummy(); - static float degrees_to_rads(double degrees); public: - static void set_protocols(bool ft, bool npclient); + enum class status { starting, stopping }; + [[nodiscard]] module_status set_protocols(); + void clear_protocols(); }; class FTControls: public IProtocolDialog @@ -88,11 +78,14 @@ private slots: void selectDLL(); void doOK(); void doCancel(); + void set_custom_location(); }; class freetrackDll : public Metadata { + Q_OBJECT + public: - QString name() { return QString(QCoreApplication::translate("freetrackDll", "freetrack 2.0 Enhanced")); } + QString name() { return tr("freetrack 2.0 Enhanced"); } QIcon icon() { return QIcon(":/images/freetrack.png"); } }; diff --git a/proto-ft/ftnoir_protocol_ft_dialog.cpp b/proto-ft/ftnoir_protocol_ft_dialog.cpp index 36846273..90ff059a 100644 --- a/proto-ft/ftnoir_protocol_ft_dialog.cpp +++ b/proto-ft/ftnoir_protocol_ft_dialog.cpp @@ -8,6 +8,8 @@ * purpose with or without fee is hereby granted, provided that the above * * copyright notice and this permission notice appear in all copies. * */ + +#include "compat/library-path.hpp" #include "ftnoir_protocol_ft.h" #include <QDebug> #include <QFileDialog> @@ -20,26 +22,16 @@ FTControls::FTControls() connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); connect(ui.bntLocateNPClient, SIGNAL(clicked()), this, SLOT(selectDLL())); - tie_setting(s.useTIRViews, ui.chkTIRViews); - tie_setting(s.close_protocols_on_exit, ui.close_on_exit); - - ui.cbxSelectInterface->addItem("Enable both"); - ui.cbxSelectInterface->addItem("Use FreeTrack, hide TrackIR"); - ui.cbxSelectInterface->addItem("Use TrackIR, hide FreeTrack"); - - tie_setting(s.intUsedInterface, ui.cbxSelectInterface); + tie_setting(s.used_interface, ui.cbxSelectInterface); + tie_setting(s.ephemeral_library_location, ui.ephemeral_registry_entry); + tie_setting(s.custom_location_pathname, ui.custom_location); + tie_setting(s.use_custom_location, ui.enable_custom_location); - QFile memhacks_pathname(QCoreApplication::applicationDirPath() + "/TIRViews.dll"); - if (!memhacks_pathname.exists()) { - ui.chkTIRViews->setChecked( false ); - ui.chkTIRViews->setEnabled ( false ); - } - else { - ui.chkTIRViews->setEnabled ( true ); - } + connect(ui.set_custom_location, &QAbstractButton::clicked, this, &FTControls::set_custom_location); } -void FTControls::doOK() { +void FTControls::doOK() +{ s.b->save(); close(); } @@ -49,13 +41,30 @@ void FTControls::doCancel() close(); } -void FTControls::selectDLL() { - QString filename = QFileDialog::getOpenFileName( this, tr("Select the desired NPClient DLL"), QCoreApplication::applicationDirPath() + "/NPClient.dll", tr("Dll file (*.dll);;All Files (*)")); +void FTControls::selectDLL() +{ + QString filename = QFileDialog::getOpenFileName(this, + tr("Select the desired NPClient DLL"), + OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH "/NPClient.dll", + tr("Dll file (*.dll);;All Files (*)")); - if (! filename.isEmpty() ) { + if (!filename.isEmpty()) + { QSettings node("NaturalPoint", "NATURALPOINT\\NPClient Location"); QFileInfo dllname(filename); - node.setValue( "Path" , dllname.dir().path() ); + node.setValue("Path", dllname.dir().path()); } } - +void FTControls::set_custom_location() +{ + static const auto program_directory = OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH; + auto previous_location = *s.custom_location_pathname; + if (!s.use_custom_location || previous_location.isEmpty() || !QDir{previous_location}.exists()) + previous_location = program_directory; + auto dir = QFileDialog::getExistingDirectory(this, tr("Select library location"), previous_location); + if (dir.isEmpty() || !QDir{dir}.exists()) + dir = QString{}; + else + ui.enable_custom_location->setEnabled(true); + ui.custom_location->setText(dir); +} diff --git a/proto-ft/lang/nl_NL.ts b/proto-ft/lang/nl_NL.ts index 2ee2afff..c8603973 100644 --- a/proto-ft/lang/nl_NL.ts +++ b/proto-ft/lang/nl_NL.ts @@ -4,85 +4,101 @@ <context> <name>FTControls</name> <message> - <location filename="../ftnoir_protocol_ft_dialog.cpp" line="+53"/> <source>Select the desired NPClient DLL</source> <translation type="unfinished"></translation> </message> <message> - <location line="+0"/> <source>Dll file (*.dll);;All Files (*)</source> <translation type="unfinished"></translation> </message> + <message> + <source>Select library location</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UICFTControls</name> <message> - <location filename="../ftnoir_ftcontrols.ui" line="+32"/> <source>freetrack protocol settings</source> <translation type="unfinished"></translation> </message> <message> - <location line="+22"/> <source>Select interface</source> <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> <source>Disable one of the protocols if game is confused by presence of both at the same time.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> - <source>TIRViews</source> + <source>Locate DLL</source> <translation type="unfinished"></translation> </message> <message> - <location line="+21"/> - <source>Memory hacks</source> + <source>Replace the registry entry if you want to use other software with the NPClient protocol and it doesn't work automatically. + +Starting tracking will again overwrite the DLL locations.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> - <source>Only for very old and buggy old games such as CFS3.</source> + <source>Enable both</source> <translation type="unfinished"></translation> </message> <message> - <location line="+25"/> - <source>Repair NPClient location</source> + <source>Use freetrack, disable TrackIR</source> <translation type="unfinished"></translation> </message> <message> - <location line="+15"/> - <source>Locate DLL</source> + <source>Use TrackIR, disable freetrack</source> <translation type="unfinished"></translation> </message> <message> - <location line="+13"/> - <source>Replace the registry entry if you want to use other software with the NPClient protocol and it doesn't work automatically. - -Starting tracking will again overwrite the DLL locations.</source> + <source>Library location</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Custom location</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Browse...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>This is useful when you're only evaluating opentrack, and haven't yet decided to use it all the time.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Clear location when tracking is stopped</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Useful for titles like Elite: Dangerous that require the library to reside in a specified location. Use this to avoid relocating your opentrack installation.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>freetrack</name> + <message> + <source>Unknown game</source> <translation type="unfinished"></translation> </message> <message> - <location line="+28"/> - <source>Disable tracking for games on exit</source> + <source>Can't load freetrack memory mapping</source> <translation type="unfinished"></translation> </message> <message> - <location line="+15"/> - <source>Disable on program exit</source> + <source>Can't copy library to selected custom location '%1'</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> - <source>Use this for games that disable mouselook when opentrack isn't running, and you're not running opentrack that much. To use opentrack with this option you need to start it before the games to have it work at all.</source> + <source>proto/freetrack: wrong interface selection '%1'</source> <translation type="unfinished"></translation> </message> </context> <context> <name>freetrackDll</name> <message> - <location filename="../ftnoir_protocol_ft.h" line="+96"/> <source>freetrack 2.0 Enhanced</source> <translation type="unfinished"></translation> </message> diff --git a/proto-ft/lang/ru_RU.ts b/proto-ft/lang/ru_RU.ts index e5984c77..a6433fd5 100644 --- a/proto-ft/lang/ru_RU.ts +++ b/proto-ft/lang/ru_RU.ts @@ -4,60 +4,37 @@ <context> <name>FTControls</name> <message> - <location filename="../ftnoir_protocol_ft_dialog.cpp" line="+53"/> <source>Select the desired NPClient DLL</source> <translation>Укажите путь до файла NPClient DLL </translation> </message> <message> - <location line="+0"/> <source>Dll file (*.dll);;All Files (*)</source> <translation></translation> </message> + <message> + <source>Select library location</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UICFTControls</name> <message> - <location filename="../ftnoir_ftcontrols.ui" line="+32"/> <source>freetrack protocol settings</source> <translation>Настройки протокола Freetrack</translation> </message> <message> - <location line="+22"/> <source>Select interface</source> <translation>Выберите интерфейс</translation> </message> <message> - <location line="+18"/> <source>Disable one of the protocols if game is confused by presence of both at the same time.</source> <translation>Отключите один из протоколов в случае, если при включении обоих интерфейсов игра не корректно определяет их.</translation> </message> <message> - <location line="+19"/> - <source>TIRViews</source> - <translation></translation> - </message> - <message> - <location line="+21"/> - <source>Memory hacks</source> - <translation>Взлом памяти</translation> - </message> - <message> - <location line="+7"/> - <source>Only for very old and buggy old games such as CFS3.</source> - <translation>Только для очень старых игр, например таких как CFS3 </translation> - </message> - <message> - <location line="+25"/> - <source>Repair NPClient location</source> - <translation>Решение проблем с расположением NPClient'а </translation> - </message> - <message> - <location line="+15"/> <source>Locate DLL</source> <translation>Укажите DLL</translation> </message> <message> - <location line="+13"/> <source>Replace the registry entry if you want to use other software with the NPClient protocol and it doesn't work automatically. Starting tracking will again overwrite the DLL locations.</source> @@ -66,27 +43,66 @@ Starting tracking will again overwrite the DLL locations.</source> Запуск отслеживания в opentrack приведет к перезаписи расположения DLL-файла.</translation> </message> <message> - <location line="+28"/> - <source>Disable tracking for games on exit</source> - <translation>Отключить работы интерфейсов после закрытия Opentrack </translation> + <source>Enable both</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Use freetrack, disable TrackIR</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Use TrackIR, disable freetrack</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Library location</source> + <translation type="unfinished"></translation> </message> <message> - <location line="+15"/> - <source>Disable on program exit</source> - <translation>Отключить по закрытию</translation> + <source>Custom location</source> + <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> - <source>Use this for games that disable mouselook when opentrack isn't running, and you're not running opentrack that much. To use opentrack with this option you need to start it before the games to have it work at all.</source> - <translation>По умолчанию протокол opentrack'а работает постоянно, благодаря чему возможно запускать opentrack на любой стадии загрузки игр. При активации данного пункта необходимо запускать opentrack перед запуском игры.</translation> + <source>Browse...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>This is useful when you're only evaluating opentrack, and haven't yet decided to use it all the time.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Clear location when tracking is stopped</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Useful for titles like Elite: Dangerous that require the library to reside in a specified location. Use this to avoid relocating your opentrack installation.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>freetrack</name> + <message> + <source>Unknown game</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Can't load freetrack memory mapping</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Can't copy library to selected custom location '%1'</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>proto/freetrack: wrong interface selection '%1'</source> + <translation type="unfinished"></translation> </message> </context> <context> <name>freetrackDll</name> <message> - <location filename="../ftnoir_protocol_ft.h" line="+96"/> <source>freetrack 2.0 Enhanced</source> - <translation></translation> + <translation type="unfinished"></translation> </message> </context> </TS> diff --git a/proto-ft/lang/stub.ts b/proto-ft/lang/stub.ts index af1a167d..ac88d895 100644 --- a/proto-ft/lang/stub.ts +++ b/proto-ft/lang/stub.ts @@ -4,85 +4,101 @@ <context> <name>FTControls</name> <message> - <location filename="../ftnoir_protocol_ft_dialog.cpp" line="+53"/> <source>Select the desired NPClient DLL</source> <translation type="unfinished"></translation> </message> <message> - <location line="+0"/> <source>Dll file (*.dll);;All Files (*)</source> <translation type="unfinished"></translation> </message> + <message> + <source>Select library location</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UICFTControls</name> <message> - <location filename="../ftnoir_ftcontrols.ui" line="+32"/> <source>freetrack protocol settings</source> <translation type="unfinished"></translation> </message> <message> - <location line="+22"/> <source>Select interface</source> <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> <source>Disable one of the protocols if game is confused by presence of both at the same time.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> - <source>TIRViews</source> + <source>Locate DLL</source> <translation type="unfinished"></translation> </message> <message> - <location line="+21"/> - <source>Memory hacks</source> + <source>Replace the registry entry if you want to use other software with the NPClient protocol and it doesn't work automatically. + +Starting tracking will again overwrite the DLL locations.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> - <source>Only for very old and buggy old games such as CFS3.</source> + <source>Enable both</source> <translation type="unfinished"></translation> </message> <message> - <location line="+25"/> - <source>Repair NPClient location</source> + <source>Use freetrack, disable TrackIR</source> <translation type="unfinished"></translation> </message> <message> - <location line="+15"/> - <source>Locate DLL</source> + <source>Use TrackIR, disable freetrack</source> <translation type="unfinished"></translation> </message> <message> - <location line="+13"/> - <source>Replace the registry entry if you want to use other software with the NPClient protocol and it doesn't work automatically. - -Starting tracking will again overwrite the DLL locations.</source> + <source>Library location</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Custom location</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Browse...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>This is useful when you're only evaluating opentrack, and haven't yet decided to use it all the time.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Clear location when tracking is stopped</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Useful for titles like Elite: Dangerous that require the library to reside in a specified location. Use this to avoid relocating your opentrack installation.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>freetrack</name> + <message> + <source>Unknown game</source> <translation type="unfinished"></translation> </message> <message> - <location line="+28"/> - <source>Disable tracking for games on exit</source> + <source>Can't load freetrack memory mapping</source> <translation type="unfinished"></translation> </message> <message> - <location line="+15"/> - <source>Disable on program exit</source> + <source>Can't copy library to selected custom location '%1'</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> - <source>Use this for games that disable mouselook when opentrack isn't running, and you're not running opentrack that much. To use opentrack with this option you need to start it before the games to have it work at all.</source> + <source>proto/freetrack: wrong interface selection '%1'</source> <translation type="unfinished"></translation> </message> </context> <context> <name>freetrackDll</name> <message> - <location filename="../ftnoir_protocol_ft.h" line="+96"/> <source>freetrack 2.0 Enhanced</source> <translation type="unfinished"></translation> </message> diff --git a/proto-ft/lang/zh_CN.ts b/proto-ft/lang/zh_CN.ts new file mode 100644 index 00000000..7706d27c --- /dev/null +++ b/proto-ft/lang/zh_CN.ts @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="zh_CN"> +<context> + <name>FTControls</name> + <message> + <source>Select the desired NPClient DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Dll file (*.dll);;All Files (*)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Select library location</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>UICFTControls</name> + <message> + <source>freetrack protocol settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Locate DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Replace the registry entry if you want to use other software with the NPClient protocol and it doesn't work automatically. + +Starting tracking will again overwrite the DLL locations.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Select interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Disable one of the protocols if game is confused by presence of both at the same time.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable both</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Use freetrack, disable TrackIR</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Use TrackIR, disable freetrack</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Library location</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Custom location</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Browse...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>This is useful when you're only evaluating opentrack, and haven't yet decided to use it all the time.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Clear location when tracking is stopped</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Useful for titles like Elite: Dangerous that require the library to reside in a specified location. Use this to avoid relocating your opentrack installation.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>freetrack</name> + <message> + <source>Unknown game</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Can't load freetrack memory mapping</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Can't copy library to selected custom location '%1'</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>proto/freetrack: wrong interface selection '%1'</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>freetrackDll</name> + <message> + <source>freetrack 2.0 Enhanced</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/proto-ft/mutex.cpp b/proto-ft/mutex.cpp deleted file mode 100644 index a012ba90..00000000 --- a/proto-ft/mutex.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "ftnoir_protocol_ft.h" -#include "mutex.hpp" -#include <windows.h> -#include <QDebug> - -check_for_first_run::check_for_first_run() : checked_for_first_run(false), is_first_instance(false), enabled(false) -{ -} - -bool check_for_first_run::is_first_run() -{ - return checked_for_first_run && is_first_instance; -} - -void check_for_first_run::set_enabled(bool flag) -{ - enabled = flag; -} - -void check_for_first_run::try_runonce() -{ - constexpr const char* name = "opentrack-freetrack-runonce"; - - if (checked_for_first_run) - return; - - // just leak it, no issue - HANDLE h = CreateMutexA(nullptr, false, name); - - switch (WaitForSingleObject(h, 0)) - { - case WAIT_OBJECT_0: - is_first_instance = true; - checked_for_first_run = true; - break; - case WAIT_TIMEOUT: - checked_for_first_run = true; - break; - default: - checked_for_first_run = false; - break; - } - - if (checked_for_first_run && !is_first_instance) - CloseHandle(h); -} - -check_for_first_run::~check_for_first_run() -{ - try_exit(); -} - -void check_for_first_run::try_exit() -{ - if (is_first_instance && enabled) - { - qDebug() << "ft runonce: removing registry keys"; - freetrack::set_protocols(false, false); - } -} diff --git a/proto-ft/mutex.hpp b/proto-ft/mutex.hpp deleted file mode 100644 index f92a14bf..00000000 --- a/proto-ft/mutex.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -class check_for_first_run final -{ - bool checked_for_first_run; - bool is_first_instance; - bool enabled; - - void try_exit(); -public: - check_for_first_run(); - bool is_first_run(); - void set_enabled(bool flag); - void try_runonce(); - ~check_for_first_run(); -}; |
