diff --git a/HGInstaller64/HGInstaller64.cpp b/HGInstaller64/HGInstaller64.cpp deleted file mode 100644 index c5e4557..0000000 Binary files a/HGInstaller64/HGInstaller64.cpp and /dev/null differ diff --git a/HGInstaller64/HGInstaller64.vcxproj b/HGInstaller64/HGInstaller64.vcxproj deleted file mode 100644 index 4cbe537..0000000 --- a/HGInstaller64/HGInstaller64.vcxproj +++ /dev/null @@ -1,170 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8} - Win32Proj - HGInstaller64 - 10.0 - - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - Use - Level3 - Disabled - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - setupapi.lib;%(AdditionalDependencies) - RequireAdministrator - - - - - Use - Level3 - Disabled - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - setupapi.lib;%(AdditionalDependencies) - - - - - Use - Level3 - MaxSpeed - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - setupapi.lib;%(AdditionalDependencies) - - - - - Use - Level3 - MaxSpeed - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - setupapi.lib;%(AdditionalDependencies) - - - - - - - - - - Create - Create - Create - Create - - - - - - \ No newline at end of file diff --git a/HGInstaller64/HGInstaller64.vcxproj.filters b/HGInstaller64/HGInstaller64.vcxproj.filters deleted file mode 100644 index bcf616b..0000000 --- a/HGInstaller64/HGInstaller64.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ -п»ї - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/HGInstaller64/stdafx.cpp b/HGInstaller64/stdafx.cpp deleted file mode 100644 index e994575..0000000 Binary files a/HGInstaller64/stdafx.cpp and /dev/null differ diff --git a/HGInstaller64/stdafx.h b/HGInstaller64/stdafx.h deleted file mode 100644 index a9a4557..0000000 Binary files a/HGInstaller64/stdafx.h and /dev/null differ diff --git a/HGInstaller64/targetver.h b/HGInstaller64/targetver.h deleted file mode 100644 index 567cd34..0000000 Binary files a/HGInstaller64/targetver.h and /dev/null differ diff --git a/HidGuardian_signed_Win7-10_x86_x64_latest.zip b/HidGuardian_signed_Win7-10_x86_x64_latest.zip deleted file mode 100644 index dbfa569..0000000 Binary files a/HidGuardian_signed_Win7-10_x86_x64_latest.zip and /dev/null differ diff --git a/README.md b/README.md index 928c719..4caaf91 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,6 @@ irFFB can feed the 360 Hz steering column torque data recently made available in iRacing telemetry to your wheel, upsample and apply low-latency digital filters to the standard (60 Hz) iRacing FFB output and modify the feedback via a number of effects based on live telemetry. -It can also drive a 'Jetseat' and fans if you have them. +This version is a stripped version of Rob C's. Where jetseat/hidguradian/fan has been taken out so its FFB only. There's more detail in the wiki.. diff --git a/irFFB.sln b/irFFB.sln index fc65b8e..faa1219 100644 --- a/irFFB.sln +++ b/irFFB.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.29709.97 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "irFFB", "irFFB\irFFB.vcxproj", "{8BC973E0-815D-4BA3-A461-E09201F29869}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HGInstaller64", "HGInstaller64\HGInstaller64.vcxproj", "{0F49720F-1BB0-4ECC-A255-3474201F8FC8}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -28,16 +26,6 @@ Global {8BC973E0-815D-4BA3-A461-E09201F29869}.Release|x64.Build.0 = Release|x64 {8BC973E0-815D-4BA3-A461-E09201F29869}.Release|x86.ActiveCfg = Release|Win32 {8BC973E0-815D-4BA3-A461-E09201F29869}.Release|x86.Build.0 = Release|Win32 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Debug|Win32.ActiveCfg = Debug|Win32 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Debug|Win32.Build.0 = Debug|Win32 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Debug|x64.ActiveCfg = Debug|x64 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Debug|x64.Build.0 = Debug|x64 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Debug|x86.ActiveCfg = Debug|x64 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Debug|x86.Build.0 = Debug|x64 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Release|Win32.ActiveCfg = Release|Win32 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Release|x64.ActiveCfg = Release|x64 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Release|x64.Build.0 = Release|x64 - {0F49720F-1BB0-4ECC-A255-3474201F8FC8}.Release|x86.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/irFFB/HGInstaller64.dat b/irFFB/HGInstaller64.dat deleted file mode 100644 index f91790c..0000000 Binary files a/irFFB/HGInstaller64.dat and /dev/null differ diff --git a/irFFB/IUberwoorf.h b/irFFB/IUberwoorf.h deleted file mode 100644 index d22dbcd..0000000 --- a/irFFB/IUberwoorf.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef __IUBERURF_INTERFACE_DEFINED__ -#define __IUBERURF_INTERFACE_DEFINED__ - -#include "unknwn.h" - - -#define UW_STATUS_IN_USE 0 // Используется -#define UW_STATUS_READY 1 // Подключена -#define UW_STATUS_NOT_CONNECTED 2 // Не подключена -#define UW_STATUS_TIMER_ERROR 3 // Ошибка создания таймера -#define UW_STATUS_UNSUPPORTED_PROTOCOL 4 // Ошибка: устройство запрашивает длину протокола больше предусмотренной - -#define UW_SIT_LEFT 0x200 // Сиденье – слева -#define UW_SIT_RIGHT 0x002 // Сиденье – справа -#define UW_BACK_LOW_LEFT 0x400 // Низ спины – слева -#define UW_BACK_LOW_RIGHT 0x004 // Низ спины – справа -#define UW_BACK_MID_LEFT 0x800 // Середина спины – слева -#define UW_BACK_MID_RIGHT 0x008 // Середина спины – справа -#define UW_LEFT 0xE00 // Левая сторона накидки -#define UW_RIGHT 0x00E // Правая сторона накидки -#define UW_SIT 0x202 // Сиденье -#define UW_BACK_LOW 0x404 // Низ спины -#define UW_BACK_MID 0x808 // Середина спины -#define UW_ALL_ZONES 0xE0E // Все зоны - -// FLE - FILE LOAD ERROR -#define UW_FLE_NO_ERROR 0 // Нет ошибки загрузки эффекта из файла XML -#define UW_FLE_XML 1 // Ошибка при загрузке эффекта из файла XML -#define UW_FLE_FILE_OPEN 2 // Не удалось открыть файл -#define UW_FLE_XML_PARSE 3 // Ошибка разбора XML -#define UW_FLE_XML_ELEMENT_NAME 4 // Ошибка с именем элемента XML -#define UW_FLE_XML_ELEMENT_VALUE 5 // Ошибка со значением элемента XML -#define UW_FLE_XML_ATTRIBUTE 6 // Ошибка с атрибутом XML -#define UW_FLE_XML_EMPTY_TAG 7 // Пустой тег -#define UW_FLE_XML_CLOSING_TAG 8 // Не найден закрывающий тег -#define UW_FLE_XML_TAG_DEFINITION 9 // Ошибка с оформлением тега -#define UW_FLE_XML_COMMENT 10 // Ошибка с комментарием -#define UW_FLE_XML_DECLARATION 11 // Ошибка с заголовком XML-документа -#define UW_FLE_XML_EMPTY_DOCUMENT 12 // Пустой XML документ -#define UW_FLE_XML_EOF_OR_NULL 13 // Ошибка конца файла или нулевого символа -#define UW_FLE_XML_CDATA 14 // Ошибка секции CDATA - -#define UW_FLE_PATH_CHAR_CONVERSION 50 // Ошибка преобразования заданного пути к однобайтовой строке -#define UW_FLE_ROOT 51 // Неверный корневой элемент (не 'uberwoorf_vibro_effect') -#define UW_FLE_ZONES_MISSING 52 // Атрибут виброзон не найден -#define UW_FLE_ZONES_INCORRECT 53 // Значение атрибута виброзон не распознано -#define UW_FLE_VPOINT_INCORRECT 54 // Элемент точки вибрации не распознан -#define UW_FLE_VPOINT_NOT_UNIQUE 55 // Элемент точки вибрации не уникален -#define UW_FLE_AMPL_TIME_MISSING 56 // Атрибут амплитуды и/или времени не найден -#define UW_FLE_AMPL_TIME_INCORRECT 57 // Значение атрибута амплитуды и/или времени не распознано -#define UW_FLE_VPOINT_UNKNOWN_TAG 58 // Неизвестный тег в описании точки вибрации -#define UW_FLE_VPOINT_MISSING 59 // Элемент одной из точек вибрации не найден -#define UW_FLE_VIBRATION_UNKNOWN_TAG 60 // Неизвестный тег в описании вибрации -#define UW_FLE_NO_VIBRATIONS 61 // Эффект не содержит вибраций -#define UW_FLE_EFFECT_NOT_FOUND 62 // Эффект с таким дескриптором не найден -#define UW_FLE_EFFECT_ZERO_LENGTH 63 // Эффект имеет нулевую длительность - -#define UW_VALIDATION_NO_ERROR 0 // Нет ошибки проверки вибрации -#define UW_VALIDATION_FAILURE 80 // Ошибка (exception) в процессе проверки вибрации -#define UW_VALIDATION_NO_ZONES 81 // Для вибрации не указано ни одной виброзоны -#define UW_VALIDATION_ZERO_LENGTH 82 // Нулевая длительность вибрации -#define UW_VALIDATION_LESS_THAN_2_POINTS_OR_1_INFINITE 83 // Должно быть минимум 2 точки вибрации, или 1 со временем бесконечность -#define UW_VALIDATION_INFINITY_NOT_LAST_OR_SINGLE 84 // Бесконечность может быть последней или единственной засечкой времени -#define UW_VALIDATION_INFINITY_AMPLITUDE_NOT_AS_PREVIOUS 85 // Если бесконечность есть, то амплитуда должна быть такой же, как на предыдущей засечке -#define UW_VALIDATION_INFINITY_AMPLITUDE_ZERO 86 // Амплитуда у бесконечной вибрации нулевая -#define UW_VALIDATION_NEXT_TIME_NOT_EQUAL_OR_MORE 87 // Последующая засечка должна быть равной предыдущей или больше ее -#define UW_VALIDATION_THREE_OR_MORE_EQUAL_TIMES 88 // Не допускается подряд три и более одинаковых засечек времени -#define UW_VALIDATION_TIME_OUT_OF_RANGE 89 // Время вне диапазона (0... 1 000 000 мс) - -#define UW_LANG_RUSSIAN 0x0419 // Код русского языка - - - -struct IUberwoorf : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE uwGetApiVersion(UINT *version) = 0; - virtual HRESULT STDMETHODCALLTYPE uwGetStatus(UINT *status) = 0; - virtual HRESULT STDMETHODCALLTYPE uwGetSerialNumber(char *serialBuffer, UINT serialBufferSize) = 0; - virtual HRESULT STDMETHODCALLTYPE uwOpen(UINT *status) = 0; - virtual HRESULT STDMETHODCALLTYPE uwReset() = 0; - virtual HRESULT STDMETHODCALLTYPE uwSetGain(UINT gain) = 0; - virtual HRESULT STDMETHODCALLTYPE uwCreateEffect(UINT *effectHandle) = 0; - virtual HRESULT STDMETHODCALLTYPE uwSetSimpleVibration(UINT effectHandle, UINT zones, - UINT startDelay, UINT duration, BYTE amplitude, UINT *vibrationHandle) = 0; - virtual HRESULT STDMETHODCALLTYPE uwSetVibration(UINT effectHandle, UINT zones, - UINT *durations, BYTE *amplitudes, UINT count, UINT *vibrationHandle) = 0; - virtual HRESULT STDMETHODCALLTYPE uwStartEffect(UINT effectHandle, UINT count) = 0; - virtual HRESULT STDMETHODCALLTYPE uwStopEffect(UINT effectHandle) = 0; - virtual HRESULT STDMETHODCALLTYPE uwPauseEffect(UINT effectHandle) = 0; - virtual HRESULT STDMETHODCALLTYPE uwResumeEffect(UINT effectHandle) = 0; - virtual HRESULT STDMETHODCALLTYPE uwUpdateSimpleVibration(UINT effectHandle, UINT vibrationHandle, - UINT zones, UINT startDelay, UINT duration, BYTE amplitude) = 0; - virtual HRESULT STDMETHODCALLTYPE uwUpdateVibration(UINT effectHandle, UINT vibrationHandle, - UINT zones, UINT *durations, BYTE *amplitudes, UINT count) = 0; - virtual HRESULT STDMETHODCALLTYPE uwUpdateEffectAmplitudes(UINT effectHandle, UINT coefficient) = 0; - virtual HRESULT STDMETHODCALLTYPE uwDeleteEffectVibration(UINT vibrationHandle) = 0; - virtual HRESULT STDMETHODCALLTYPE uwDeleteEffect(UINT effectHandle) = 0; - virtual HRESULT STDMETHODCALLTYPE uwClose() = 0; - virtual HRESULT STDMETHODCALLTYPE uwLoadEffectFromFile(UINT effectHandle, - const wchar_t *effectFilePath, UINT *errorCode) = 0; - virtual HRESULT STDMETHODCALLTYPE uwGetEffectLength(UINT effectHandle, UINT *nonInifinitePartMs, bool *isInfinite) = 0; - virtual HRESULT STDMETHODCALLTYPE uwValidateVibration(UINT *validationResult, UINT zones, UINT count, - UINT *durations, BYTE *amplitudes) = 0; - virtual HRESULT STDMETHODCALLTYPE uwGetErrorDescriptionByCode(UINT errorCode, UINT languageCode, wchar_t *errDescr) = 0; - - virtual HRESULT STDMETHODCALLTYPE uwGetEffectInfo(UINT effectHandle, UINT *gain, UINT *vibrationCount) = 0; - virtual HRESULT STDMETHODCALLTYPE uwGetEffectVibrations(UINT effectHandle, UINT *vibrationCount, UINT *vibrationHandles) = 0; - virtual HRESULT STDMETHODCALLTYPE uwGetVibrationInfo(UINT vibrationHandle, UINT *zones, UINT *vibrationPointCount) = 0; - virtual HRESULT STDMETHODCALLTYPE uwGetVibrationPoints(UINT vibrationHandle, UINT *vibrationPointCount, UINT *durationPoints, BYTE *amplitudes) = 0; - - virtual HRESULT STDMETHODCALLTYPE uwCloneEffect(UINT effectHandle, UINT *clonedEffectHandle) = 0; - - virtual HRESULT STDMETHODCALLTYPE uwSetEffectGain(UINT effectHandle, UINT effectGain) = 0; - - virtual HRESULT STDMETHODCALLTYPE uwSetVibrationEx(UINT effectHandle, UINT zones, UINT looped, - UINT *durations, BYTE *amplitudes, UINT count, UINT *vibrationHandle) = 0; - virtual HRESULT STDMETHODCALLTYPE uwGetVibrationInfoEx(UINT vibrationHandle, UINT *zones, UINT *looped, UINT *vibrationPointCount) = 0; - virtual HRESULT STDMETHODCALLTYPE uwLoadEffectFromString(UINT effectHandle, const char *content, UINT *errorCode) = 0; -}; - -// {0AC11AE4-C1F7-4fa8-B85B-3789EDAA583A} -DEFINE_GUID(IID_IUberwoorf, 0xac11ae4, 0xc1f7, 0x4fa8, 0xb8, 0x5b, 0x37, 0x89, 0xed, 0xaa, 0x58, 0x3a); - -// {22420DBA-2927-4d71-B6B8-028982A62B72} -DEFINE_GUID(CLSID_Uberwoorf, 0x22420dba, 0x2927, 0x4d71, 0xb6, 0xb8, 0x2, 0x89, 0x82, 0xa6, 0x2b, 0x72); - - -#endif // __IUBERURF_INTERFACE_DEFINED__ - - - diff --git a/irFFB/Resource.h b/irFFB/Resource.h index 3e62833..86b1fae 100644 --- a/irFFB/Resource.h +++ b/irFFB/Resource.h @@ -7,18 +7,19 @@ #define IDS_APP_TITLE 103 #define IDD_ABOUTBOX 103 #define IDM_ABOUT 104 +#define IDS_APP_TITLE_64 104 #define IDM_EXIT 105 #define IDI_IRFFB 107 #define IDI_SMALL 108 #define IDC_IRFFB 109 #define IDR_MAINFRAME 128 +#define IDC_SYSLINK1 1001 #define IDR_HIDG64 8192 #define ID_SETTINGS_JETSEAT 32774 #define ID_SETTINGS_FAN 32775 #define ID_SETTINGS_HIDGUARDIAN 32778 #define ID_SETTINGS_TRACTIONLOSS 32779 #define IDC_STATIC -1 -#define IDC_SYSLINK1 1001 // Next default values for new objects // diff --git a/irFFB/Settings.h b/irFFB/Settings.h index c0c2fcb..dc6c995 100644 --- a/irFFB/Settings.h +++ b/irFFB/Settings.h @@ -35,6 +35,15 @@ class Settings { sWins_t *getUndersteerWnd() { return understeerWnd; }; void setUndersteerOffsetWnd(sWins_t *); sWins_t *getUndersteerOffsetWnd() { return understeerOffsetWnd; }; + + void setUndersteerYawRateMultWnd(sWins_t*); + sWins_t* getUndersteerYawRateMultWnd() { return understeerYawRateMultWnd; }; + void setUndersteerlatAccelDivWnd(sWins_t*); + sWins_t* getUndersteerlatAccelDivWnd() { return understeerlatAccelDivWnd; }; + + void setOverlayTransparencyWnd(sWins_t*); + sWins_t* getOverlayTransparencyWnd() { return overlayTransparencyWnd; }; + void setUse360Wnd(HWND); HWND getUse360Wnd() { return use360Wnd; }; void setCarSpecificWnd(HWND); @@ -47,6 +56,12 @@ class Settings { HWND getStartMinimisedWnd() { return startMinimisedWnd; }; void setDebugWnd(HWND); HWND getDebugWnd() { return debugWnd; }; + void setAltTimerWnd(HWND); + HWND getAltTimerWnd() { return altTimerWnd; }; + void setForceOverlayWnd(HWND); + HWND getForceOverlayWnd() { return forceOverlayWnd; }; + void setOverlayMaxForceWnd(HWND); + HWND getOverlayMaxForceWnd() { return overlayMaxForceWnd; }; void clearFfbDevices(); void addFfbDevice(GUID dev, const wchar_t *); @@ -72,6 +87,14 @@ class Settings { float getUndersteerFactor() { return understeerFactor; }; bool setUndersteerOffset(float, HWND); float getUndersteerOffset() { return understeerOffset; }; + bool setUndersteerYawRateMult(float, HWND); + float getUndersteerYawRateMult() { return understeerYawRateMult; }; + bool setUndersteerlatAccelDiv(float, HWND); + float getUndersteerlatAccelDiv() { return understeerlatAccelDiv; }; + bool setOverlayTransparency(float, HWND); + float getOverlayTransparency() { return overlayTransparency; }; + void enableOverlayTransparencyWnd(); + void disableOverlayTransparencyWnd(); void setUse360ForDirect(bool); bool getUse360ForDirect() { return use360ForDirect; }; void setUseCarSpecific(bool, char *); @@ -82,8 +105,20 @@ class Settings { bool getRunOnStartup() { return runOnStartup; }; void setStartMinimised(bool); bool getStartMinimised() { return startMinimised; }; + void setWindowPosX(int X) { windowPosX = X; }; + int getWindowPosX(){ return windowPosX; }; + void setWindowPosY(int Y) { windowPosY = Y; }; + int getWindowPosY() { return windowPosY; }; + void setDebug(bool); bool getDebug() { return debug; }; + + void setUseAltTimer(bool); + bool getUseAltTimer() { return useAltTimer; }; + void setShowForceOverlay(bool); + bool getShowForceOverlay() { return showForceOverlay; }; + + float getBumpsSetting(); int getMinForceSetting(); float getSopOffsetSetting(); @@ -95,23 +130,29 @@ class Settings { void writeGenericSettings(); void readSettingsForCar(char *); void writeSettingsForCar(char *); - PWSTR getLogPath(); + std::wstring getLogPath(); private: - HWND devWnd, ffbWnd; - sWins_t *minWnd, *maxWnd, *bumpsWnd, *dampingWnd, *sopWnd, *sopOffsetWnd, *understeerWnd, *understeerOffsetWnd; - HWND use360Wnd, carSpecificWnd, reduceWhenParkedWnd; + HWND devWnd, ffbWnd, overlayMaxForceWnd; + sWins_t *minWnd, *maxWnd, *bumpsWnd, *dampingWnd, *sopWnd, *sopOffsetWnd, + *understeerWnd, *understeerOffsetWnd, *understeerYawRateMultWnd, *understeerlatAccelDivWnd, + *overlayTransparencyWnd; + HWND use360Wnd, carSpecificWnd, reduceWhenParkedWnd, altTimerWnd, forceOverlayWnd; HWND runOnStartupWnd, startMinimisedWnd, debugWnd; int ffbType, ffdeviceIdx, minForce, maxForce; - float scaleFactor, bumpsFactor, dampingFactor, sopFactor, sopOffset, understeerFactor, understeerOffset; - bool use360ForDirect, useCarSpecific, debug; + float scaleFactor, bumpsFactor, dampingFactor, sopFactor, sopOffset, + understeerFactor, understeerOffset, understeerYawRateMult, understeerlatAccelDiv, + overlayTransparency; + bool use360ForDirect, useCarSpecific, debug, useAltTimer, showForceOverlay; bool reduceWhenParked, runOnStartup, startMinimised; GUID devGuid = GUID_NULL, ffdevices[MAX_FFB_DEVICES]; wchar_t strbuf[64]; HANDLE debugHnd; + int windowPosX, windowPosY; + wchar_t *ffbTypeString(int); - PWSTR getIniPath(); + std::wstring getIniPath(); void writeWithNewline(std::ofstream &, char *); }; \ No newline at end of file diff --git a/irFFB/fan.cpp b/irFFB/fan.cpp deleted file mode 100644 index 40447b1..0000000 --- a/irFFB/fan.cpp +++ /dev/null @@ -1,491 +0,0 @@ -#include - -#include "fan.h" - -Fan *Fan::instance = nullptr; - -Fan *Fan::init() { - return new Fan(); -} - -Fan::Fan() { - - instance = this; - - if (FAILED(CoInitializeEx(0, COINIT_MULTITHREADED))) - return; - - CoInitializeSecurity( - NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, - RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL - ); - - readSettings(); - enumSerialPorts(); - -} - -ATOM Fan::registerClass(HINSTANCE hInstance) { - - WNDCLASSEXW wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = wndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_IRFFB)); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = windowClass; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); - - return RegisterClassExW(&wcex); - -} - -void Fan::createWindow(HINSTANCE hInst) { - - if (!classIsRegistered) { - registerClass(hInst); - classIsRegistered = true; - } - - mainWnd = CreateWindowW( - windowClass, windowClass, WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, - CW_USEDEFAULT, CW_USEDEFAULT, 432, 380, - NULL, NULL, hInst, NULL - ); - - if (!mainWnd) - return; - - windSimFormatWnd = checkbox(mainWnd, L"Use WindSim format?", 40, 20); - portWnd = combo(mainWnd, L"Fan controller port:", 40, 80); - - CreateWindowW( - L"STATIC", L"Maximum car speed: (0 = auto)", - WS_CHILD | WS_VISIBLE, - 40, 160, 300, 20, mainWnd, NULL, hInst, NULL - ); - maxSpeedWnd = CreateWindowEx( - WS_EX_CLIENTEDGE, L"EDIT", L"0", - WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_OVERLAPPED | ES_NUMBER, - 52, 184, 188, 24, mainWnd, NULL, hInst, NULL - ); - speedUnitsWnd = CreateWindowW( - L"COMBOBOX", nullptr, - CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | WS_TABSTOP, - 240, 184, 112, 200, mainWnd, nullptr, hInst, nullptr - ); - SendMessage(speedUnitsWnd, CB_ADDSTRING, 0, LPARAM(unitStrings[MPH])); - SendMessage(speedUnitsWnd, CB_ADDSTRING, 0, LPARAM(unitStrings[KPH])); - - manualWnd = slider(mainWnd, L"Manual fan speed:", 40, 234, L"0", L"100", false); - - setManualSpeed((int)manualSpeed); - ShowWindow(mainWnd, SW_SHOWNORMAL); - UpdateWindow(mainWnd); - enumSerialPorts(); - readSettings(); - - return; - -} - -LRESULT CALLBACK Fan::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - - HWND wnd = (HWND)lParam; - - switch (message) { - - case WM_COMMAND: { - int wmId = LOWORD(wParam); - switch (wmId) { - case IDM_EXIT: - DestroyWindow(hWnd); - break; - default: - if (HIWORD(wParam) == CBN_SELCHANGE) { - if (wnd == instance->portWnd) { - int idx = (int)SendMessage(wnd, CB_GETCURSEL, 0, 0); - if (idx >= 0 && idx < instance->numPorts) { - instance->fanPort = instance->ports[idx].dev; - instance->initFanPort(); - } - } - else if (wnd == instance->speedUnitsWnd) { - instance->setSpeedUnits(SendMessage(wnd, CB_GETCURSEL, 0, 0)); - } - } - else if (HIWORD(wParam) == BN_CLICKED) { - bool oldValue = SendMessage(wnd, BM_GETCHECK, 0, 0) == BST_CHECKED; - if (wnd == instance->windSimFormatWnd) - instance->setWindSimFormat(!oldValue); - } - break; - } - } - break; - - case WM_HSCROLL: { - if (wnd == instance->manualWnd->trackbar) { - wchar_t strbuf[8]; - int spd = SendMessage(wnd, TBM_GETPOS, 0, 0); - swprintf_s(strbuf, L"%d", spd); - instance->setManualSpeed(spd); - SendMessage(instance->manualWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); - } - } - break; - - case WM_EDIT_VALUE: { - if (wnd == instance->manualWnd->value) { - instance->setManualSpeed(wParam); - SendMessage(instance->manualWnd->trackbar, TBM_SETPOS, true, wParam); - } - } - break; - - case WM_CTLCOLORSTATIC: { - SetBkColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); - return (LRESULT)CreateSolidBrush(RGB(0xff, 0xff, 0xff)); - } - break; - - case WM_PAINT: { - PAINTSTRUCT ps; - BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - break; - - case WM_DESTROY: { - wchar_t buf[16]; - SendMessage(instance->maxSpeedWnd, WM_GETTEXT, 16, LPARAM(buf)); - instance->setMaxSpeed(StrToInt(buf)); - instance->writeSettings(); - } - break; - - default: - return DefWindowProc(hWnd, message, wParam, lParam); - - } - - return 0; - -} - -void Fan::setSpeedUnits(int u) { - - if (u < 0 || u > 1) - return; - - units = u; - if (SendMessageW(instance->maxSpeedWnd, WM_GETTEXT, 16, LPARAM(strbuf))) - maxSpeed = StrToInt(strbuf); - setMaxSpeed(maxSpeed); - SendMessage(speedUnitsWnd, CB_SETCURSEL, u, 0); - -} - -void Fan::setMaxSpeed(int s) { - - maxSpeed = s; - - if (s == 0) { - maxSpeedMs = 53; - goto UPDATE; - } - - if (units == MPH) - maxSpeedMs = (float)s / 2.237f; - else - maxSpeedMs = (float)s / 3.6f; - -UPDATE: - _itow_s(s, strbuf, 10); - SendMessage(maxSpeedWnd, WM_SETTEXT, 0, LPARAM(strbuf)); - -} - -void Fan::setManualSpeed(int s) { - - SendMessage(manualWnd->trackbar, TBM_SETPOS, TRUE, s); - swprintf_s(strbuf, L"%d", s); - SendMessage(manualWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); - manualSpeed = (float)s; - setSpeed(manualSpeed * maxSpeedMs / 100); - -} - -void Fan::setWindSimFormat(bool ws) { - - SendMessage(windSimFormatWnd, BM_SETCHECK, ws ? BST_CHECKED : BST_UNCHECKED, NULL); - bool reInit = windSimFormat != ws; - windSimFormat = ws; - if (reInit) - initFanPort(); - -} - -void Fan::enumSerialPorts() { - - UINT portsSize = numPorts = 0; - - IWbemLocator *locator = NULL; - if ( - FAILED( - CoCreateInstance( - CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, - IID_IWbemLocator, reinterpret_cast(&locator) - ) - ) - ) { - text(L"Failed to CoCreateInstance of WbemLocator"); - return; - } - - IWbemServices *services = NULL; - if ( - FAILED( - locator->ConnectServer( - _bstr_t("\\\\.\\root\\cimv2"), NULL, NULL, NULL, 0, NULL, NULL, &services - ) - ) - ) { - text(L"Failed to connect to cimv2 server"); - locator->Release(); - return; - } - - IEnumWbemClassObject *classObject = NULL; - HRESULT hr = services->ExecQuery( - _bstr_t("WQL"), _bstr_t("SELECT * FROM Win32_SerialPort"), - WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &classObject - ); - - if (FAILED(hr)) { - _com_error err(hr); - text(L"SerialPort query failed: %s", err.ErrorMessage()); - services->Release(); - locator->Release(); - return; - } - - hr = WBEM_S_NO_ERROR; - - while (hr == WBEM_S_NO_ERROR) { - - ULONG num = 0; - IWbemClassObject *obj[16]; - - if ( - SUCCEEDED( - classObject->Next( - WBEM_INFINITE, 16, reinterpret_cast(obj), &num - ) - ) - ) { - - UINT i = 0; - - if (num == 0) - break; - - portsSize += sizeof(port) * num; - ports = (port *)realloc(ports, portsSize); - - for (ULONG n = 0; n < num; n++) { - - VARIANT name; - HRESULT hrGet = obj[n]->Get(L"DeviceID", 0, &name, NULL, NULL); - - if ( - SUCCEEDED(hrGet) && (name.vt == VT_BSTR) && (wcslen(name.bstrVal) > 3) - ) { - - if (_wcsnicmp(name.bstrVal, L"COM", 3) != 0) - continue; - - VARIANT fname; - ports[numPorts + i].dev = (wchar_t *)malloc((lstrlen(name.bstrVal) + 5) * sizeof(wchar_t)); - lstrcpy(ports[numPorts + i].dev, L"\\\\.\\"); - lstrcat(ports[numPorts + i].dev, name.bstrVal); - if ( - FAILED(obj[n]->Get(L"Name", 0, &fname, NULL, NULL)) || - fname.vt != VT_BSTR - ) - ports[numPorts + i].name = StrDupW(name.bstrVal); - else - ports[numPorts + i].name = StrDupW(fname.bstrVal); - - SendMessage( - portWnd, CB_ADDSTRING, 0, - LPARAM(ports[numPorts + i].name) - ); - - if (fanPort != nullptr && _wcsnicmp(ports[numPorts + i].dev, fanPort, 128) == 0) { - SendMessage((HWND)portWnd, CB_SETCURSEL, numPorts + i, 0); - if (fanHandle == INVALID_HANDLE_VALUE) - initFanPort(); - } - - i++; - - } - - obj[n]->Release(); - - } - - numPorts += i; - - } - } - - classObject->Release(); - services->Release(); - locator->Release(); - -} - -void Fan::initFanPort() { - - if (fanPort == nullptr) - return; - - wchar_t *settings = windSimFormat ? L"9600,n,8,1" : L"115200,n,8,1"; - - if (fanHandle != INVALID_HANDLE_VALUE) - CloseHandle(fanHandle); - - fanHandle = CreateFile( - fanPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0 - ); - - DCB dcb; - - memset(&dcb, 0, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); - if (!BuildCommDCB(settings, &dcb)) { - text(L"Error building fan control port parameters"); - CloseHandle(fanHandle); - fanHandle = INVALID_HANDLE_VALUE; - return; - } - - dcb.fAbortOnError = FALSE; - - if (!SetCommState(fanHandle, &dcb)) { - text(L"Error setting fan control port parameters"); - CloseHandle(fanHandle); - fanHandle = INVALID_HANDLE_VALUE; - return; - } - - COMMTIMEOUTS timeouts; - memset(&timeouts, 0, sizeof(timeouts)); - timeouts.WriteTotalTimeoutConstant = 10; - SetCommTimeouts(fanHandle, &timeouts); - - text(L"Connected to fan control port"); - -} - -void Fan::setSpeed(float speed) { - - if (fanHandle == INVALID_HANDLE_VALUE) - return; - - if (maxSpeed == 0 && speed > maxSpeedMs) - maxSpeedMs = speed; - - byte buf[4]; - - speed *= 100 / maxSpeedMs; - speed = minf(speed, 100.0f); - speed *= windSimFormat ? 2.55f : 1.6f; - - int ispeed = (int)speed; - - buf[0] = (byte)(ispeed); - DWORD written; - DWORD toWrite = 1; - - if (windSimFormat) { - buf[3] = buf[0]; - buf[0] = buf[2] = 255; - buf[1] = 88; - toWrite = 4; - } - - COMSTAT comstat; - DWORD errors; - - if (!WriteFile(fanHandle, buf, toWrite, &written, NULL)) - if (GetLastError() != ERROR_IO_PENDING) - ClearCommError(fanHandle, &errors, &comstat); - -} - -void Fan::setManualSpeed() { - setSpeed(manualSpeed * maxSpeedMs / 100); -} - -void Fan::readSettings() { - - HKEY key = Settings::getSettingsRegKey(); - - if (fanPort != nullptr) - delete[] fanPort; - - if (key == NULL) { - setWindSimFormat(true); - delete[] fanPort; - fanPort = nullptr; - setMaxSpeed(120); - setSpeedUnits(MPH); - return; - } - - fanPort = new wchar_t[128]; - DWORD fanPortSize = 128 * sizeof(wchar_t); - - if (RegGetValueW(key, nullptr, L"fanPort", RRF_RT_REG_SZ, nullptr, fanPort, &fanPortSize)) { - delete[] fanPort; - fanPort = nullptr; - } - - setWindSimFormat(Settings::getRegSetting(key, L"fanWindSimFormat", true)); - setMaxSpeed(Settings::getRegSetting(key, L"fanMaxSpeed", 120)); - setSpeedUnits(Settings::getRegSetting(key, L"fanMaxSpeedUnits", MPH)); - - RegCloseKey(key); - -} - -void Fan::writeSettings() { - - HKEY key = Settings::getSettingsRegKey(); - DWORD fanPortSz = 0; - - if (key == NULL) - return; - - if (fanPort) { - fanPortSz = (lstrlen(fanPort) + 1) * sizeof(wchar_t); - RegSetValueEx(key, L"fanPort", 0, REG_SZ, (BYTE *)fanPort, fanPortSz); - } - - Settings::setRegSetting(key, L"fanWindSimFormat", windSimFormat); - Settings::setRegSetting(key, L"fanMaxSpeed", maxSpeed); - Settings::setRegSetting(key, L"fanMaxSpeedUnits", units); - - RegCloseKey(key); - -} \ No newline at end of file diff --git a/irFFB/fan.h b/irFFB/fan.h deleted file mode 100644 index e8d39ab..0000000 --- a/irFFB/fan.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include -#include - -#include "stdafx.h" -#include "irFFB.h" -#include "Settings.h" - -typedef struct { - wchar_t *name; - wchar_t *dev; -} port; - -#define MPH 0 -#define KPH 1 - -class Fan { - - public: - static Fan *init(); - void createWindow(HINSTANCE); - void setSpeed(float); - void setManualSpeed(); - - private: - Fan(); - ATOM registerClass(HINSTANCE); - static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); - void enumSerialPorts(); - void initFanPort(); - void setSpeedUnits(int); - void setMaxSpeed(int); - void setManualSpeed(int); - void setWindSimFormat(bool); - void readSettings(); - void writeSettings(); - - static Fan *instance; - - wchar_t *windowClass = L"Fan settings"; - wchar_t *unitStrings[2] = { L"mph", L"kph" }; - HWND mainWnd, portWnd, maxSpeedWnd, speedUnitsWnd, windSimFormatWnd; - sWins_t *manualWnd; - bool classIsRegistered = false, windSimFormat = true; - float maxSpeedMs = 0, manualSpeed = 0; - int numPorts = 0, maxSpeed = 0, units = MPH; - wchar_t *fanPort = nullptr; - port *ports = nullptr; - HANDLE fanHandle = INVALID_HANDLE_VALUE; - wchar_t strbuf[64]; - -}; - diff --git a/irFFB/hidguardian.cpp b/irFFB/hidguardian.cpp deleted file mode 100644 index 2102d39..0000000 --- a/irFFB/hidguardian.cpp +++ /dev/null @@ -1,1743 +0,0 @@ -#include "hidguardian.h" - -HidGuardian *HidGuardian::instance = nullptr; -SERVICE_STATUS_HANDLE HidGuardian::svcStatusHandle; -SERVICE_STATUS HidGuardian::svcStatus; -HANDLE HidGuardian::svcStopEvent; - -HidGuardian *HidGuardian::init(DWORD pid) { - return new HidGuardian(pid); -} - -HidGuardian::HidGuardian(DWORD pid) { - - instance = this; - readSettings(); - refreshStatus(); - if (enabled && hgStatus == STATUS_ENABLED) { - if (queryService() == SERVICE_STOPPED) - startService(); - Sleep(500); - whitelist(pid); - } - -} - -ATOM HidGuardian::registerClass(HINSTANCE hInstance) { - - WNDCLASSEXW wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = wndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_IRFFB)); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = windowClass; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); - - hInst = hInstance; - - return RegisterClassExW(&wcex); - -} - -void HidGuardian::createWindow(HINSTANCE hInst) { - - if (!classIsRegistered) { - registerClass(hInst); - classIsRegistered = true; - } - - mainWnd = CreateWindowW( - windowClass, windowClass, WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, - CW_USEDEFAULT, CW_USEDEFAULT, 400, 180, - NULL, NULL, hInst, NULL - ); - - if (!mainWnd) - return; - - statusWnd = CreateWindowW( - L"STATIC", L"Status: not installed", - WS_CHILD | WS_VISIBLE, - 40, 30, 150, 40, mainWnd, NULL, hInst, NULL - ); - - svcWnd = CreateWindowW( - L"STATIC", L"Service: not installed", - WS_CHILD | WS_VISIBLE, - 220, 30, 300, 40, mainWnd, NULL, hInst, NULL - ); - - installWnd = CreateWindowW( - L"BUTTON", L"Install", - WS_CHILD | WS_VISIBLE, - 40, 70, 100, 30, mainWnd, NULL, hInst, NULL - ); - - enabledWnd = checkbox(mainWnd, L"Enable", 220, 56); - - ShowWindow(mainWnd, SW_SHOWNORMAL); - UpdateWindow(mainWnd); - refreshStatus(); - setSvcStatus(queryService()); - return; - -} - -LRESULT CALLBACK HidGuardian::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - - switch (message) { - - case WM_COMMAND: { - int wmId = LOWORD(wParam); - switch (wmId) { - case IDM_EXIT: - DestroyWindow(hWnd); - break; - default: - if (HIWORD(wParam) == BN_CLICKED) { - if ((HWND)lParam == instance->installWnd) { - if (instance->hgStatus == STATUS_NOTINSTALLED) - instance->install(); - else if (instance->serviceStatus == SERVICE_STOPPED) - instance->repairService(); - } - else if ((HWND)lParam == instance->enabledWnd) { - bool oldValue = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED; - instance->setEnabled(!oldValue); - } - } - break; - } - } - break; - - case WM_CTLCOLORSTATIC: { - SetBkColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); - return (LRESULT)CreateSolidBrush(RGB(0xff, 0xff, 0xff)); - } - break; - - case WM_PAINT: { - PAINTSTRUCT ps; - BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - break; - - case WM_DESTROY: - instance->writeSettings(); - break; - - default: - return DefWindowProc(hWnd, message, wParam, lParam); - - } - - return 0; - -} - -void HidGuardian::install() { - - BOOL wow64; - wchar_t *infPath = nullptr; - - IsWow64Process(GetCurrentProcess(), &wow64); - - if (!isElevated()) { - elevate(CMDLINE_HGINST); - return; - } - - if (hgStatus != STATUS_NOTINSTALLED) { - text(L"HG: already installed"); - goto installSvc; - } - - wchar_t *hidZip = download(); - - if (hidZip == nullptr) - return; - - wchar_t *hidFld = unzip(hidZip); - - if (hidFld == nullptr) - goto cleanup; - - int infPathLen = wcslen(hidFld) + 64; - infPath = new wchar_t[infPathLen]; - StringCchCopyW(infPath, infPathLen, hidFld); - if (wow64) - StringCchCatW(infPath, infPathLen, L"\\x64\\HidGuardian.inf"); - else - StringCchCatW(infPath, infPathLen, L"\\x86\\HidGuardian.inf"); - - if (!wow64) { - text(L"HG: Installing..."); - if (!doInstall(infPath)) - goto del; - else if (!updateDriver(infPath)) - goto del; - } - else { - - wchar_t *tmpFile = unpackInstaller64(); - - if (tmpFile == nullptr) - goto del; - - exInstaller64(tmpFile, infPath); - DeleteFileW(tmpFile); - delete[] tmpFile; - - } - - if (!installFilter()) - goto del; - - refreshStatus(); - -installSvc: - if (queryService() == -1) - if (!installService()) { - text(L"HG: Failed to install service"); - goto del; - } - - setStatus(hgStatus); - -del: - if (infPath != nullptr) - delete[] infPath; -cleanup: - cleanupInstall(); - -} - -bool HidGuardian::isEnabled() { - return hgStatus == STATUS_ENABLED; -} - -void HidGuardian::setDevice(WORD vid, WORD pid) { - - pipeMsg msg; - - currentVid = vid; - currentPid = pid; - - if (hgStatus != STATUS_ENABLED) - return; - - msg.cmd = HG_CMD_DEVICE_ADD; - StringCchPrintf(msg.id.hwid, 32, HG_HWID_FMT, vid, pid); - UINT resp = sendSvcMsg(&msg); - if (resp == HG_SVC_RET_SUCCESS) - text(L"HG: *** Dev change - unplug/replug or reboot ***"); - else if (resp == HG_SVC_RET_ERROR) - text(L"HG: Failed to set device"); - -} - -void HidGuardian::removeDevice(WORD vid, WORD pid, bool warn) { - - pipeMsg msg; - - if (hgStatus != STATUS_ENABLED) - return; - - msg.cmd = HG_CMD_DEVICE_DEL; - StringCchPrintf(msg.id.hwid, 32, HG_HWID_FMT, vid, pid); - if (sendSvcMsg(&msg) == HG_SVC_RET_ERROR) { - text(L"HG: Failed to remove device"); - return; - } - if (warn) - text(L"HG: *** Dev unmasked - unplug/replug or reboot ***"); - -} - -void HidGuardian::whitelist(DWORD pid) { - - pipeMsg msg; - - if (hgStatus != STATUS_ENABLED || serviceStatus != SERVICE_RUNNING) - return; - - msg.cmd = HG_CMD_WHITELIST_ADD; - msg.id.pid = pid; - if (sendSvcMsg(&msg) == HG_SVC_RET_ERROR) - text(L"HG: Failed to add to whitelist"); - -} - -void HidGuardian::unWhitelist(DWORD pid) { - - pipeMsg msg; - - msg.cmd = HG_CMD_WHITELIST_DEL; - msg.id.pid = pid; - sendSvcMsg(&msg); - -} - -void HidGuardian::stop(DWORD pid) { - unWhitelist(pid); - stopService(); -} - -int HidGuardian::getStatus() { - return hgStatus; -} - -void HidGuardian::setStatus(int s) { - - wchar_t buf[64]; - - if (s < STATUS_NOTINSTALLED || s > STATUS_ENABLED) - return; - - if (s == STATUS_ENABLED && queryService() == SERVICE_STOPPED) { - hgStatus = s; - if (startService()) { - whitelist(GetCurrentProcessId()); - if (currentVid != 0) - setDevice(currentVid, currentPid); - } - else { - text(L"HG: Service failed to start"); - text(L"HG: Open HidGuardian settings to attempt repair"); - SetWindowTextW(installWnd, L"Repair"); - EnableWindow(installWnd, true); - goto updatestatus; - } - } - else if (s == STATUS_DISABLED && queryService() == SERVICE_RUNNING) { - unWhitelist(GetCurrentProcessId()); - if (currentVid != 0) - removeDevice(currentVid, currentPid, true); - stopService(); - hgStatus = s; - } - - EnableWindow(installWnd, s == STATUS_NOTINSTALLED); - updatestatus: - StringCchPrintfW(buf, 64, L"Status: %s", statuses[hgStatus]); - SendMessage(statusWnd, WM_SETTEXT, NULL, (LPARAM)buf); - SendMessage(enabledWnd, BM_SETCHECK, s == STATUS_ENABLED ? BST_CHECKED : BST_UNCHECKED, NULL); - EnableWindow(svcWnd, s > STATUS_NOTINSTALLED); - EnableWindow(enabledWnd, s > STATUS_NOTINSTALLED); - - -} - -int HidGuardian::refreshStatus() { - - ULONG s, problem; - GUID classGuid = GUID_DEVCLASS_SYSTEM; - - hgStatus = STATUS_NOTINSTALLED; - - HDEVINFO devInfo = SetupDiGetClassDevsW(&classGuid, NULL, NULL, DIGCF_PRESENT); - - if (devInfo == INVALID_HANDLE_VALUE) - return hgStatus; - - SP_DEVINFO_DATA devInfoData = { 0 }; - devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); - - int idx = 0; - bool found = false; - wchar_t buf[64]; - DWORD type, required; - - for (idx = 0; SetupDiEnumDeviceInfo(devInfo, idx, &devInfoData); idx++) { - if ( - !SetupDiGetDeviceRegistryPropertyW( - devInfo, &devInfoData, SPDRP_HARDWAREID, &type, - (PBYTE)buf, sizeof(buf), &required - ) - ) - continue; - - if (wcscmp(buf, HG_HARDWARE_ID) == 0) { - found = true; - break; - } - - } - - if (!found) - goto release; - - if (CM_Get_DevNode_Status(&s, &problem, devInfoData.DevInst, 0) != CR_SUCCESS) { - text(L"HG: Failed to get status"); - goto release; - } - - if (s & DN_STARTED) { - if (enabled) - hgStatus = STATUS_ENABLED; - else - hgStatus = STATUS_DISABLED; - } - -release: - - SetupDiDestroyDeviceInfoList(devInfo); - setStatus(hgStatus); - return hgStatus; - -} - -void HidGuardian::setEnabled(bool en) { - - enabled = en; - - if (en && hgStatus == STATUS_DISABLED) - setStatus(STATUS_ENABLED); - else if (!en && hgStatus == STATUS_ENABLED) - setStatus(STATUS_DISABLED); - -} - -wchar_t *HidGuardian::unpackInstaller64() { - - HRSRC hrsrc = FindResourceW(hInst, (LPCWSTR)IDR_HIDG64, RT_RCDATA); - - if (hrsrc == NULL) { - text(L"HG: Failed to locate 64 bit installer resource"); - return nullptr; - } - - DWORD size = SizeofResource(hInst, hrsrc); - HGLOBAL hGlb = LoadResource(hInst, hrsrc); - - if (hGlb == NULL) { - text(L"HG: Failed to load 64 bit installer resource"); - return nullptr; - } - - BYTE *rbuf = (BYTE *)LockResource(hGlb); - - if (rbuf == NULL) { - text(L"HG: Failed to lock 64 bit installer resource"); - return nullptr; - } - - wchar_t tmpPath[MAX_PATH]; - - if (!GetTempPathW(MAX_PATH, tmpPath)) - return nullptr; - - wchar_t *tmpFile = new wchar_t[MAX_PATH]; - StringCchPrintf(tmpFile, MAX_PATH, L"%s%s", tmpPath, HG_INSTALLER_NAME); - - HANDLE file = - CreateFile( - tmpFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL - ); - - if (file == INVALID_HANDLE_VALUE) { - text(L"HG: Failed to create temp file at %s", tmpFile); - goto delTmpFile; - } - - DWORD written; - if (!WriteFile(file, rbuf, size, &written, NULL)) { - text(L"HG: Failed to write to temp file at %s", tmpFile); - CloseHandle(file); - goto delTmpFile; - } - - CloseHandle(file); - return tmpFile; - -delTmpFile: - delete[] tmpFile; - return nullptr; - -} - -bool HidGuardian::exInstaller64(wchar_t *path, wchar_t *infPath) { - - wchar_t cmdLine[MAX_PATH]; - StringCchCopyW(cmdLine, MAX_PATH, infPath); - - text(L"HG: Launching install helper..."); - - SHELLEXECUTEINFOW sei = { 0 }; - sei.cbSize = sizeof(SHELLEXECUTEINFOW); - sei.lpVerb = L"runas"; - sei.lpFile = path; - sei.lpParameters = cmdLine; - sei.nShow = SW_NORMAL; - sei.fMask = SEE_MASK_NOCLOSEPROCESS; - - if (!ShellExecuteExW(&sei)) { - if (GetLastError() == ERROR_CANCELLED) - text(L"HG: Install cancelled"); - else - text(L"HG: ShellExecute failed: %d", GetLastError()); - return false; - } - - DWORD exitcode = 0; - - WaitForSingleObject(sei.hProcess, INFINITE); - GetExitCodeProcess(sei.hProcess, &exitcode); - CloseHandle(sei.hProcess); - - if (exitcode != 0) { - if (exitcode > INSTALLER_MAX_ERRORCODE) - text(L"HG: Unknown error from installer"); - else { - wchar_t msg[128]; - StringCchPrintfW(msg, 128, L"HG: %s", installerErrors[exitcode]); - text(msg); - } - return false; - } - - text(L"HG: Installed"); - return true; - -} - -wchar_t *HidGuardian::download() { - - DWORD size = 0, inBuf = 0, written = 0; - wchar_t tmpPath[MAX_PATH]; - HANDLE file; - BYTE *buf; - wchar_t *ret = nullptr, *tmpFile = nullptr; - - HINTERNET session = - WinHttpOpen( - L"irFFB/1.4", - WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ); - - if (session == NULL) { - text(L"HG: Failed to open http session"); - return nullptr; - } - - HINTERNET connect = - WinHttpConnect(session, HG_DOWNLOAD_SITE, INTERNET_DEFAULT_HTTPS_PORT, 0); - - if (connect == NULL) { - text(L"HG: Failed to connect"); - return nullptr; - } - - HINTERNET request = - WinHttpOpenRequest( - connect, L"GET", - HG_DOWNLOAD_PATH, - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_SECURE - ); - - if (request == NULL) { - text(L"HG: Failed to open request"); - return nullptr; - } - - if ( - !WinHttpSendRequest( - request, - WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, - 0, NULL - ) - ) { - text(L"HG: Failed to send request"); - return nullptr; - } - - if ( - !WinHttpReceiveResponse(request, NULL) - ) { - text(L"HG: Failed to receive response"); - return nullptr; - } - - if (!GetTempPathW(MAX_PATH, tmpPath)) - return nullptr; - - tmpFile = new wchar_t[MAX_PATH]; - srand(GetTickCount()); - StringCchPrintf(tmpFile, MAX_PATH, L"%shidg%x.zip", tmpPath, rand()); - - file = - CreateFile( - tmpFile, GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL - ); - - if (file == INVALID_HANDLE_VALUE) { - text(L"HG: Failed to create temp file at %s", tmpFile); - return nullptr; - } - - text(L"HG: Dowloading.."); - - do { - - size = 0; - - if (!WinHttpQueryDataAvailable(request, &size)) - goto close; - - if (size == 0) - break; - - buf = new BYTE[size + 1]; - - if (buf == NULL) - goto close; - - ZeroMemory(buf, size + 1); - - if (!WinHttpReadData(request, buf, size, &inBuf)) - goto close; - - WriteFile(file, buf, inBuf, &written, NULL); - - delete[] buf; - - } while (size > 0); - - zipPath = tmpFile; - -close: - CloseHandle(file); - - if (zipPath == nullptr && tmpFile != nullptr) - delete[] tmpFile; - - return zipPath; - -} - -wchar_t *HidGuardian::unzip(wchar_t *zipPath) { - - IShellDispatch *isd = nullptr; - - VARIANT zipFile, folder, item, options; - - Folder *zipFileFolder = nullptr, *destFolder = nullptr; - FolderItems *zipItems = nullptr; - - IDispatch *itemI; - - wchar_t tmpPath[MAX_PATH], *ret = nullptr, *tmpFile = nullptr; - - CoInitialize(NULL); - if ( - CoCreateInstance( - CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void **)&isd - ) != S_OK - ) { - text(L"HG: Failed to cocreateinstance of shell server"); - return false; - } - - zipFile.vt = VT_BSTR; - zipFile.bstrVal = _bstr_t(zipPath); - isd->NameSpace(zipFile, &zipFileFolder); - - if (!zipFileFolder) { - text(L"HG: Failed to set folder NS to %s", zipPath); - goto releaseIsd; - } - - if (!GetTempPathW(MAX_PATH, tmpPath)) - goto releaseZipFolder; - - int len = wcslen(tmpPath) + 32; - tmpFile = new wchar_t[len]; - StringCchPrintf(tmpFile, len, L"%shidg%x", tmpPath, rand()); - - if (!CreateDirectoryW(tmpFile, NULL)) { - text(L"HG: Failed to create dir at %s", tmpFile); - goto releaseZipFolder; - } - - folder.vt = VT_BSTR; - folder.bstrVal = _bstr_t(tmpFile); - isd->NameSpace(folder, &destFolder); - - if (!destFolder) { - text(L"HG: Failed to set folder NS to %s", tmpFile); - goto releaseZipFolder; - } - - zipFileFolder->Items(&zipItems); - - if (!zipItems) { - text(L"HG: Failed to enum zip items"); - goto releaseDestFolder; - } - - zipItems->QueryInterface(IID_IDispatch, (void **)&itemI); - - item.vt = VT_DISPATCH; - item.pdispVal = itemI; - - options.vt = VT_I4; - options.lVal = 1024 | 512 | 16 | 4; - - text(L"HG: Decompressing..."); - - if (destFolder->CopyHere(item, options) == S_OK) - fldPath = tmpFile; - - itemI->Release(); - zipItems->Release(); -releaseDestFolder: - destFolder->Release(); -releaseZipFolder: - zipFileFolder->Release(); -releaseIsd: - isd->Release(); - - if (fldPath == nullptr && tmpFile != nullptr) - delete[] tmpFile; - - return fldPath; - -} - -bool HidGuardian::doInstall(wchar_t *infPath) { - - GUID classGuid; - wchar_t hwIds[64], className[MAX_CLASS_NAME_LEN]; - HDEVINFO devInfo; - SP_DEVINFO_DATA devInfoData; - bool ret = false; - - ZeroMemory(hwIds, sizeof(hwIds)); - StringCchCopy(hwIds, 64, HG_HARDWARE_ID); - - if (!SetupDiGetINFClass(infPath, &classGuid, className, MAX_CLASS_NAME_LEN, 0)) { - text(L"HG: Failed to get INF class from %s", infPath); - return false; - } - - devInfo = SetupDiCreateDeviceInfoList(&classGuid, NULL); - if (devInfo == INVALID_HANDLE_VALUE) { - text(L"HG: Failed to create DeviceInfoList"); - return false; - } - - devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); - if ( - !SetupDiCreateDeviceInfoW( - devInfo, className, &classGuid, NULL, NULL, DICD_GENERATE_ID, &devInfoData - ) - ) { - text(L"HG: Failed to create DeviceInfo"); - goto end; - } - - if ( - !SetupDiSetDeviceRegistryProperty( - devInfo, &devInfoData, SPDRP_HARDWAREID, (LPBYTE)hwIds, - (wcslen(hwIds) + 2) * sizeof(wchar_t) - ) - ) { - text(L"HG: Failed to set device registry property"); - goto end; - } - - if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfo, &devInfoData)) { - text(L"HG: Class installer failed"); - goto end; - } - - text(L"HG: className is %s", className); - - ret = true; - -end: - SetupDiDestroyDeviceInfoList(devInfo); - return ret; - -} - -bool HidGuardian::installFilter() { - - GUID classGuid; - DWORD numGuids; - bool ret = false; - - if (!SetupDiClassGuidsFromNameEx(L"HIDClass", &classGuid, 1, &numGuids, NULL, NULL)) { - text(L"HG: Error getting HIDClass GUID"); - return false; - } - - HKEY key = SetupDiOpenClassRegKeyExW(&classGuid, KEY_WRITE, DIOCR_INSTALLER, NULL, NULL); - - if (key == INVALID_HANDLE_VALUE) { - text(L"HG: Failed to open class reg key"); - return false; - } - - wchar_t *multiSz = getRegMultiSz(key, REGSTR_VAL_UPPERFILTERS); - wchar_t *newMultiSz = prependToMultiSz(multiSz, HG_FILTER_NAME); - - if (newMultiSz != nullptr) - ret = ( - RegSetValueExW( - key, REGSTR_VAL_UPPERFILTERS, 0, REG_MULTI_SZ, - (LPBYTE)newMultiSz, multiSzLen(newMultiSz) - ) == NO_ERROR - ); - else - ret = true; - - if (multiSz != nullptr) - delete[] multiSz; - if (newMultiSz != nullptr) - delete[] newMultiSz; - RegCloseKey(key); - return ret; - -} - -bool HidGuardian::updateDriver(wchar_t *infPath) { - - HMODULE newDevMod = LoadLibrary(L"newdev.dll"); - UpdateDriverProto updateFn; - - if (!newDevMod) { - text(L"HG: Failed to LoadLibrary newdev.dll"); - return false; - } - - updateFn = (UpdateDriverProto)GetProcAddress(newDevMod, "UpdateDriverForPlugAndPlayDevicesW"); - - if (!updateFn) { - text(L"HG: Failed to find UpdateDriverForPlugAndPlayDevicesW"); - return false; - } - - if (!updateFn(NULL, HG_HARDWARE_ID, infPath, INSTALLFLAG_FORCE, NULL)) { - text(L"HG: Failed to update HG driver"); - return false; - } - - return true; - -} - -void HidGuardian::cleanupInstall() { - - if (zipPath != nullptr) - DeleteFileW(zipPath); - - if (fldPath == nullptr) - return; - - *(fldPath + wcslen(fldPath) + 1) = '\0'; - - SHFILEOPSTRUCT sfo = { 0 }; - sfo.wFunc = FO_DELETE; - sfo.pFrom = fldPath; - sfo.fFlags = FOF_NO_UI; - SHFileOperationW(&sfo); - -} - -bool HidGuardian::installService() { - - SC_HANDLE scm, svc; - wchar_t path[MAX_PATH]; - SERVICE_DESCRIPTIONW desc = { L"irFFB HidGuardian service" }; - PSECURITY_DESCRIPTOR sd; - bool ret = false; - - wchar_t *sddl = - L"D:" - L"(A;;CCLCSWRPWPDTLOCRRC;;;SY)" // default permissions for local system - L"(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)" // default permissions for administrators - L"(A;;CCLCSWLOCRRC;;;AU)" // default permissions for authenticated users - L"(A;;CCLCSWRPWPDTLOCRRC;;;PU)" // default permissions for power users - L"(A;;RPWP;;;IU)"; // allow interactive users to start and stop - - StringCchCopy(path, MAX_PATH, L"\""); - - if (!GetModuleFileNameW(NULL, path + 1, MAX_PATH - 1)) { - text(L"HG: Service install - failed to locate module"); - return ret; - } - - StringCchCatW(path, MAX_PATH, L"\" service"); - - scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); - - if (scm == nullptr) { - text(L"HG: Failed to open service manager"); - return ret; - } - - svc = - CreateServiceW( - scm, SVCNAME, L"irFFB HG Service", SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, - SERVICE_ERROR_NORMAL, path, - NULL, NULL, NULL, NULL, NULL - ); - - if (svc == nullptr) { - text(L"HG: Failed to create service"); - goto closeScm; - } - - ChangeServiceConfig2W(svc, SERVICE_CONFIG_DESCRIPTION, &desc); - - if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl, SDDL_REVISION_1, &sd, NULL)) { - text(L"HG: Failed to convert security descriptor"); - goto closeSvc; - } - - if (!SetServiceObjectSecurity(svc, DACL_SECURITY_INFORMATION, sd)) { - text(L"HG: Failed to set service DACLs"); - goto freeSd; - } - - ret = true; - - text(L"HG: irFFB HG service installed"); - -freeSd: - LocalFree(sd); -closeSvc: - CloseServiceHandle(svc); -closeScm: - CloseServiceHandle(scm); - setSvcStatus(queryService()); - return ret; - -} - -void HidGuardian::repairService() { - - HKEY regKey; - wchar_t path[MAX_PATH]; - - if (!isElevated()) { - elevate(CMDLINE_HGREPAIR); - return; - } - - StringCbCopyW(path, MAX_PATH, L"\""); - - GetModuleFileNameW(NULL, path + 1, MAX_PATH - 2); - - StringCchCatW(path, MAX_PATH, L"\" "); - StringCchCatW(path, MAX_PATH, CMDLINE_HGSVC); - - DWORD len = wcslen(path) + 1;; - - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, HG_SERVICE_KEY, 0, KEY_WRITE, ®Key)) { - text(L"HG: Failed to open irFFBsvc registry key"); - return; - } - - - if (RegSetValueExW(regKey, L"ImagePath", 0, REG_EXPAND_SZ, (BYTE *)&path, len * sizeof(wchar_t))) { - text(L"HG: Failed to update irFFBsvc registry key"); - return; - } - - text(L"HG: Repairing service image path"); - - RegCloseKey(regKey); - SetWindowTextW(installWnd, L"Install"); - EnableWindow(installWnd, false); - setStatus(hgStatus); - -} - -int HidGuardian::queryService() { - - SC_HANDLE scm, svc; - SERVICE_STATUS_PROCESS status; - DWORD needed; - int ret = -1; - - scm = OpenSCManagerW(NULL, NULL, STANDARD_RIGHTS_READ); - - if (scm == nullptr) { - text(L"HG: Failed to open service manager"); - return ret; - } - - svc = OpenServiceW(scm, SVCNAME, SERVICE_QUERY_STATUS); - - if (svc == nullptr) { - - if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) - goto closeScm; - else { - text(L"HG: Failed to open service"); - goto closeScm; - } - - } - - if ( - !QueryServiceStatusEx( - svc, SC_STATUS_PROCESS_INFO, (LPBYTE)&status, sizeof(status), &needed - ) - ) { - text(L"HG: Failed to query service"); - goto closeSvc; - } - - ret = status.dwCurrentState; - -closeSvc: - CloseServiceHandle(svc); -closeScm: - CloseServiceHandle(scm); - return ret; - -} - -bool HidGuardian::startService() { - - SC_HANDLE scm, svc; - LPCWSTR arg = CMDLINE_HGSVC; - bool ret = false; - - if (queryService() != SERVICE_STOPPED) - return true; - - scm = OpenSCManagerW(NULL, NULL, STANDARD_RIGHTS_READ|STANDARD_RIGHTS_EXECUTE); - - if (scm == nullptr) { - text(L"HG: Failed to open service manager"); - return false; - } - - svc = OpenServiceW(scm, SVCNAME, SERVICE_START); - - if (svc == nullptr) { - - if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) - goto closeScm; - else { - text(L"HG: Failed to open service"); - goto closeScm; - } - - } - - if (StartService(svc, 1, &arg)) { - for (int i = 0; i < 10; i++) { - if (queryService() == SERVICE_RUNNING) { - ret = true; - break; - } - Sleep(200); - } - Sleep(500); - } - - setSvcStatus(queryService()); - - CloseServiceHandle(svc); -closeScm: - CloseServiceHandle(scm); - return ret; - -} - -void HidGuardian::stopService() { - - SC_HANDLE scm, svc; - SERVICE_STATUS status; - wchar_t *arg = L"service"; - - if (queryService() != SERVICE_RUNNING) - return; - - scm = OpenSCManagerW(NULL, NULL, STANDARD_RIGHTS_READ|STANDARD_RIGHTS_EXECUTE); - - if (scm == nullptr) { - text(L"HG: Failed to open service manager"); - return; - } - - svc = OpenServiceW(scm, SVCNAME, SERVICE_STOP); - - if (svc == nullptr) { - - if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) - goto closeScm; - else { - text(L"HG: Failed to open service"); - goto closeScm; - } - - } - - Sleep(500); - - if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) - text(L"HG: Failed to stop service"); - else { - for (int i = 0; i < 10; i++) { - if (queryService() == SERVICE_STOPPED) - break; - Sleep(500); - } - } - - setSvcStatus(queryService()); - - CloseServiceHandle(svc); -closeScm: - CloseServiceHandle(scm); - -} - -void HidGuardian::setSvcStatus(int status) { - - wchar_t buf[64]; - wchar_t *sTxt; - - serviceStatus = status; - - switch (status) { - case -1: sTxt = L"Not installed"; break; - case SERVICE_STOP_PENDING: sTxt = L"Stopping"; break; - case SERVICE_STOPPED: sTxt = L"Stopped"; break; - case SERVICE_START_PENDING: sTxt = L"Starting"; break; - case SERVICE_RUNNING: sTxt = L"Running"; break; - default: sTxt = L"Unknown"; - } - - StringCchPrintfW(buf, 64, L"Service: %s", sTxt); - SendMessage(svcWnd, WM_SETTEXT, NULL, (LPARAM)buf); - -} - -UINT HidGuardian::sendSvcMsg(pipeMsg *msg) { - - DWORD written, mode = PIPE_READMODE_MESSAGE; - UINT ret = HG_SVC_RET_ERROR; - UINT resp; - - if (msg == nullptr) { - text(L"HG: null service pipe msg"); - return HG_SVC_RET_ERROR; - } - - if (serviceStatus != SERVICE_RUNNING) - return HG_SVC_RET_ERROR; - - DWORD size = - ( - msg->cmd == HG_CMD_WHITELIST_ADD || - msg->cmd == HG_CMD_WHITELIST_DEL - ) ? - PIPE_MSG_SIZE_PID : PIPE_MSG_SIZE_HWID; - - HANDLE pipe = - CreateFileW( - HG_SVC_PIPE, - GENERIC_READ|GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - 0, - NULL - ); - - if (pipe == INVALID_HANDLE_VALUE) { - text(L"HG: Error opening service pipe: %d", GetLastError()); - return HG_SVC_RET_ERROR; - } - - if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) { - text(L"HG: Error setting service pipe mode"); - goto closePipe; - } - - if (!WriteFile(pipe, msg, size, &written, NULL)) { - text(L"HG: Error writing to service pipe"); - goto closePipe; - } - - for (int i = 0; i < 10; i++) { - - if (!PeekNamedPipe(pipe, NULL, 0, NULL, &written, NULL)) { - text(L"HG: Error peeking service pipe"); - goto closePipe; - } - - if (written >= sizeof(resp)) - break; - - Sleep(50); - - } - - if (written < sizeof(resp)) { - text(L"HG: Timed out reading from service pipe"); - goto closePipe; - } - - if (!ReadFile(pipe, &resp, sizeof(resp), &written, NULL)) { - text(L"HG: Error reading from service pipe"); - goto closePipe; - } - - ret = resp; - -closePipe: - CloseHandle(pipe); - return ret; - -} - -bool HidGuardian::isElevated() { - - HANDLE token; - TOKEN_ELEVATION elevation; - DWORD retSize = sizeof(TOKEN_ELEVATION); - bool ret = false; - - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { - if ( - GetTokenInformation( - token, TokenElevation, &elevation, sizeof(elevation), &retSize - ) - ) { - if (elevation.TokenIsElevated) - ret = true; - } - CloseHandle(token); - } - - return ret; - -} - -void HidGuardian::elevate(wchar_t *param) { - - wchar_t modPath[MAX_PATH]; - - if (!GetModuleFileNameW(NULL, modPath, MAX_PATH)) - return; - - SHELLEXECUTEINFOW sei; - ZeroMemory(&sei, sizeof(SHELLEXECUTEINFOW)); - sei.cbSize = sizeof(SHELLEXECUTEINFOW); - sei.lpVerb = L"runas"; - sei.lpFile = modPath; - sei.lpParameters = param; - sei.nShow = SW_NORMAL; - - if (!ShellExecuteExW(&sei)) { - if (GetLastError() == ERROR_CANCELLED) - text(L"HG: Installation cancelled"); - else - text(L"HG: ShellExecute failed"); - } - else - exit(0); - -} - -void HidGuardian::readSettings() { - - HKEY key = Settings::getSettingsRegKey(); - - if (key == NULL) { - enabled = true; - return; - } - - enabled = Settings::getRegSetting(key, L"hgEnabled", true); - RegCloseKey(key); - -} - -void HidGuardian::writeSettings() { - - HKEY key = Settings::getSettingsRegKey(); - - if (key == NULL) - return; - - Settings::setRegSetting(key, L"hgEnabled", enabled); - RegCloseKey(key); - -} - -// Static reg helpers - -wchar_t *HidGuardian::getRegMultiSz(HKEY key, LPCTSTR val) { - - wchar_t *buf = new wchar_t[1024]; - LONG ret; - DWORD type, len = 1022 * sizeof(wchar_t); - - ret = RegQueryValueEx(key, val, NULL, &type, (PBYTE)buf, &len); - while (ret != NO_ERROR) { - if (GetLastError() != ERROR_MORE_DATA) - goto fail; - if (type != REG_MULTI_SZ) - goto fail; - delete[] buf; - buf = new wchar_t[len / sizeof(wchar_t) + 2]; - ret = RegQueryValueEx(key, val, NULL, &type, (PBYTE)buf, &len); - } - - buf[len / sizeof(wchar_t)] = '\0'; - buf[len / sizeof(wchar_t) + 1] = '\0'; - - return buf; - -fail: - delete[] buf; - return nullptr; - -} - -wchar_t *HidGuardian::prependToMultiSz(wchar_t *multiSz, wchar_t *value) { - - wchar_t *ptr, *scan, *buf = nullptr; - size_t len, bufLen; - - if (multiSz == NULL) { - bufLen = wcslen(value) + 2; - buf = new wchar_t[bufLen]; - StringCchCopyW(buf, bufLen, value); - ptr = buf + bufLen - 1; - } - else { - - for (scan = multiSz; scan[0]; scan += wcslen(scan) + 1) - if (!wcscmp(value, scan)) - return nullptr; - - bufLen = scan - multiSz + wcslen(value) + 2; - buf = new wchar_t[bufLen]; - ptr = buf; - - StringCchCopyW(ptr, bufLen, value); - len = wcslen(value) + 1; - ptr += len; - bufLen -= len; - - for (scan = multiSz; scan[0]; scan += len) { - StringCchCopy(ptr, bufLen, scan); - len = wcslen(ptr) + 1; - ptr += len; - bufLen -= len; - } - - } - - *ptr = '\0'; - - return buf; - -} - -wchar_t *HidGuardian::removeFromMultiSz(wchar_t *multiSz, wchar_t *value) { - - wchar_t *buf, *ptr, *scan; - bool matched = false; - size_t len, oldlen = multiSzLen(multiSz); - - if (!oldlen) - return nullptr; - - ptr = buf = new wchar_t[oldlen]; - - for (scan = multiSz; scan[0]; scan += len) { - - len = wcslen(scan) + 1; - - if (wcscmp(value, scan)) { - StringCchCopy(ptr, oldlen, scan); - oldlen -= len; - ptr += len; - } - else - matched = true; - - } - - if (!matched) { - delete[] buf; - return nullptr; - } - - *ptr = '\0'; - return buf; - -} - -size_t HidGuardian::multiSzLen(wchar_t *multiSz) { - - wchar_t *scan; - - if (multiSz == nullptr) - return 0; - - for (scan = multiSz; scan[0]; scan += wcslen(scan) + 1) {}; - return (++scan - multiSz) * sizeof(wchar_t); - -} - -// Service stuff - -void WINAPI HidGuardian::SvcMain(DWORD argc, LPTSTR argv) { - - svcStatusHandle = RegisterServiceCtrlHandlerW(SVCNAME, svcCtrlHandler); - - if (svcStatusHandle == INVALID_HANDLE_VALUE) { - svcReportError(L"Failed to register ctrl handler"); - return; - } - - svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - svcStatus.dwServiceSpecificExitCode = 0; - svcReportStatus(SERVICE_START_PENDING, NO_ERROR, 0); - - svcStopEvent = CreateEventW(NULL, true, false, L"irFFBsvcStopEvent"); - if (svcStopEvent == INVALID_HANDLE_VALUE) { - svcReportError(L"Failed to create service stop event"); - svcReportStatus(SERVICE_STOPPED, SERVICE_ERROR_CRITICAL, 0); - return; - } - - if (!CreateThread(NULL, 0, pipeServerThread, NULL, 0, NULL)) { - svcReportError(L"Failed to start pipe server thread"); - svcReportStatus(SERVICE_STOPPED, SERVICE_ERROR_CRITICAL, 0); - return; - } - - svcReportStatus(SERVICE_RUNNING, NO_ERROR, 0); - WaitForSingleObject(svcStopEvent, INFINITE); - svcReportStatus(SERVICE_STOPPED, NO_ERROR, 0); - -} - -void WINAPI HidGuardian::svcCtrlHandler(DWORD ctrl) { - - if (ctrl != SERVICE_CONTROL_STOP) - return; - - svcReportStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); - SetEvent(svcStopEvent); - -} - -void HidGuardian::svcReportStatus(DWORD status, DWORD exitCode, DWORD waitHint) { - - svcStatus.dwCurrentState = status; - svcStatus.dwWin32ExitCode = exitCode; - svcStatus.dwWaitHint = waitHint; - svcStatus.dwControlsAccepted = (status == SERVICE_START_PENDING ? 0 : SERVICE_ACCEPT_STOP); - - SetServiceStatus(svcStatusHandle, &svcStatus); - -} - -void HidGuardian::svcReportError(wchar_t *msg) { - - HANDLE evtSrc = RegisterEventSourceW(NULL, SVCNAME); - LPCTSTR str[] = { SVCNAME, msg }; - - ReportEventW(evtSrc, EVENTLOG_ERROR_TYPE, 0, 0xC0020001L, NULL, 2, 0, str, NULL); - DeregisterEventSource(evtSrc); - -} - -UINT HidGuardian::svcAddDevice(wchar_t *dev) { - - HKEY key; - UINT ret = HG_SVC_RET_ERROR; - - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, HG_PARAMS_KEY, 0, KEY_ALL_ACCESS, &key)) { - svcReportError(L"Failed to open HG parameters key"); - return ret; - } - - wchar_t *devices = getRegMultiSz(key, HG_DEVICES_VALUE_NAME); - wchar_t *newDevices = prependToMultiSz(devices, dev); - - if (newDevices != nullptr) { - if (RegSetValueExW(key, HG_DEVICES_VALUE_NAME, 0, REG_MULTI_SZ, (BYTE *)newDevices, multiSzLen(newDevices))) - svcReportError(L"Failed to add device"); - else - ret = HG_SVC_RET_SUCCESS; - } - else - ret = HG_SVC_RET_EXISTS; - - if (devices != nullptr) - delete[] devices; - if (newDevices != nullptr) - delete[] newDevices; - - RegCloseKey(key); - return ret; - -} - -UINT HidGuardian::svcDelDevice(wchar_t *dev) { - - HKEY key; - UINT ret = HG_SVC_RET_ERROR; - - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, HG_PARAMS_KEY, 0, KEY_ALL_ACCESS, &key)) { - svcReportError(L"Failed to open HG parameters key"); - return ret; - } - - wchar_t *devices = getRegMultiSz(key, HG_DEVICES_VALUE_NAME); - - if (devices == nullptr) - goto closeKey; - - wchar_t *newDevices = removeFromMultiSz(devices, dev); - - if (newDevices == nullptr) - goto done; - - if (RegSetValueExW(key, HG_DEVICES_VALUE_NAME, 0, REG_MULTI_SZ, (BYTE *)newDevices, multiSzLen(newDevices))) { - svcReportError(L"Failed to remove device"); - goto done; - } - - ret = HG_SVC_RET_SUCCESS; - -done: - if (devices != nullptr) - delete[] devices; - if (newDevices != nullptr) - delete[] newDevices; -closeKey: - RegCloseKey(key); - return ret; - -} - -UINT HidGuardian::svcAddWlist(UINT pid) { - - HKEY key, wlKey, pidKey; - wchar_t name[MAX_PATH]; - DWORD nameLen = MAX_PATH; - int idx = 0; - UINT ret = HG_SVC_RET_ERROR; - - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, HG_PARAMS_KEY, 0, KEY_ALL_ACCESS, &key)) { - svcReportError(L"Failed to oepn HG parameters key"); - return ret; - } - - if ( - RegCreateKeyExW( - key, HG_WHITELIST_SUBKEY, 0, NULL, REG_OPTION_NON_VOLATILE, - KEY_ALL_ACCESS, NULL, &wlKey, NULL - ) - ) { - svcReportError(L"Failed to create/open whitelist key"); - RegCloseKey(key); - return ret; - } - - while (ret == ERROR_SUCCESS) { - nameLen = MAX_PATH; - ret = RegEnumKeyEx(wlKey, idx++, name, &nameLen, 0, NULL, NULL, NULL); - if (ret != ERROR_SUCCESS) - break; - if (_wtoi(name) == pid) { - ret = HG_SVC_RET_EXISTS; - goto done; - } - } - - if (_itow_s(pid, name, 10)) { - svcReportError(L"Invalid whitelist pid"); - goto done; - } - - if ( - RegCreateKeyExW( - wlKey, name, 0, NULL, REG_OPTION_NON_VOLATILE, - KEY_ALL_ACCESS, NULL, &pidKey, NULL - ) - ) { - svcReportError(L"Failed to create whitelist subkey"); - goto done; - } - - RegCloseKey(pidKey); - ret = HG_SVC_RET_SUCCESS; - -done: - RegCloseKey(wlKey); - RegCloseKey(key); - return ret; - -} - -UINT HidGuardian::svcDelWlist(UINT pid) { - - HKEY key; - UINT ret = HG_SVC_RET_ERROR; - wchar_t str[MAX_PATH]; - - StringCchCopy(str, MAX_PATH, HG_PARAMS_KEY); - StringCchCat(str, MAX_PATH, L"\\"); - StringCchCat(str, MAX_PATH, HG_WHITELIST_SUBKEY); - - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, str, 0, KEY_ALL_ACCESS, &key)) { - svcReportError(L"Failed to open HG whitelist key"); - return ret; - } - - if (_itow_s(pid, str, 10)) { - svcReportError(L"Invalid whitelist pid"); - goto done; - } - - if (!RegDeleteKeyExW(key, str, KEY_ALL_ACCESS, 0)) - ret = HG_SVC_RET_SUCCESS; - -done: - RegCloseKey(key); - return ret; - -} - - -DWORD WINAPI HidGuardian::pipeServerThread(LPVOID arg) { - - HANDLE pipe; - SECURITY_ATTRIBUTES sa; - wchar_t *sddl = - L"D:" - L"(A;;GARCSDWDWOFA;;;SY)" // full control for localsystem - L"(A;;GARCSDWDWOFA;;;BA)" // full control for admins - L"(A;;GRRCFR;;;AU)" // read for authenticated users - L"(A;;GARCFA;;;IU)"; // rwx for interactive users - - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = false; - - if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl, SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL)) { - svcReportError(L"Error converting pipe security descriptor"); - return 1; - } - - while (true) { - - pipe = - CreateNamedPipeW( - HG_SVC_PIPE, - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - sizeof(UINT), - sizeof(pipeMsg), - 0, - &sa - ); - - if (pipe == INVALID_HANDLE_VALUE) { - svcReportError(L"Error creating named pipe server"); - return 1; - } - - if (!ConnectNamedPipe(pipe, NULL)) - if (GetLastError() != ERROR_PIPE_CONNECTED) { - svcReportError(L"Error connecting named pipe"); - CloseHandle(pipe); - continue; - } - - if (!CreateThread(NULL, 0, pipeWorkerThread, (LPVOID)pipe, 0, NULL)) { - svcReportError(L"Error creating pipe worker thread"); - CloseHandle(pipe); - } - - } - - return 0; - -} - -DWORD WINAPI HidGuardian::pipeWorkerThread(LPVOID arg) { - - HANDLE pipe = (HANDLE)arg; - pipeMsg msg; - DWORD len; - UINT resp = HG_SVC_RET_ERROR; - - if (pipe == NULL) { - svcReportError(L"Pipe worker thread got NULL pipe"); - return 1; - } - - while (true) { - - if (!ReadFile(pipe, &msg, sizeof(msg), &len, NULL)) - break; - - if (len != PIPE_MSG_SIZE_PID && len != PIPE_MSG_SIZE_HWID) - break; - - switch (msg.cmd) { - - case HG_CMD_WHITELIST_ADD: - resp = svcAddWlist(msg.id.pid); - break; - case HG_CMD_WHITELIST_DEL: - resp = svcDelWlist(msg.id.pid); - break; - case HG_CMD_DEVICE_ADD: - resp = svcAddDevice(msg.id.hwid); - break; - case HG_CMD_DEVICE_DEL: - resp = svcDelDevice(msg.id.hwid); - break; - default: - svcReportError(L"Pipe worker, received unknown cmd"); - } - - if (!WriteFile(pipe, &resp, sizeof(resp), &len, NULL)) - break; - - } - - return 0; - -} - - diff --git a/irFFB/hidguardian.h b/irFFB/hidguardian.h deleted file mode 100644 index 91b337a..0000000 --- a/irFFB/hidguardian.h +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once - -#include "stdafx.h" -#include "irFFB.h" -#include "Settings.h" - -#define STATUS_NOTINSTALLED 0 -#define STATUS_DISABLED 1 -#define STATUS_ENABLED 2 - -#define HG_DOWNLOAD_SITE L"github.com" -#define HG_DOWNLOAD_PATH L"/nlp80/irFFB/raw/master/HidGuardian_signed_Win7-10_x86_x64_latest.zip" -#define HG_HARDWARE_ID L"Root\\HidGuardian" -#define HG_FILTER_NAME L"HidGuardian" -#define HG_INSTALLER_NAME L"irFFB_hg64.exe" -#define HG_PARAMS_KEY L"SYSTEM\\CurrentControlSet\\Services\\HidGuardian\\Parameters" -#define HG_SERVICE_KEY L"SYSTEM\\CurrentControlSet\\Services\\irFFBsvc" -#define HG_WHITELIST_SUBKEY L"Whitelist" -#define HG_DEVICES_VALUE_NAME L"AffectedDevices" -#define HG_HWID_FMT L"HID\\VID_%04hx&PID_%04hx" -#define HG_SVC_PIPE L"\\\\.\\pipe\\irFFB" - -#define HG_CMD_WHITELIST_ADD 1 -#define HG_CMD_WHITELIST_DEL 2 -#define HG_CMD_DEVICE_ADD 3 -#define HG_CMD_DEVICE_DEL 4 - -#define HG_SVC_RET_ERROR 0 -#define HG_SVC_RET_SUCCESS 1 -#define HG_SVC_RET_EXISTS 2 - -typedef BOOL(WINAPI *UpdateDriverProto)(HWND, LPCTSTR, LPCTSTR, DWORD, PBOOL); - -#define INSTALLER_MAX_ERRORCODE 11 - -static wchar_t *installerErrors[] = { - L"Success", - L"Missing INF path argument", - L"Failed to get class from INF", - L"Failed to create devInfo list", - L"Failed to create devInfo", - L"Failed to set dev reg property", - L"Failed to call class installer", - L"Failed to open class reg key", - L"Failed to set filter reg value", - L"Failed to loadlibrary newdev.dll", - L"Failed to locate UpdateDriverForPlugAndPlayDevices", - L"UpdateDriverForPlugAndPlayDevices failed" -}; - -static wchar_t *statuses[] = { - L"Not installed", L"Disabled", L"Enabled" -}; - -#pragma pack(push, 1) -typedef struct { - UINT cmd; - union { - UINT pid; - wchar_t hwid[32]; - } id; -} pipeMsg; -#pragma pack(pop) - -#define PIPE_MSG_SIZE_PID 2 * sizeof(UINT) -#define PIPE_MSG_SIZE_HWID sizeof(pipeMsg) - -class HidGuardian { - -public: - static HidGuardian *init(DWORD); - ATOM registerClass(HINSTANCE); - void createWindow(HINSTANCE); - static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); - void install(void); - void repairService(void); - bool isEnabled(void); - void setDevice(WORD, WORD); - void removeDevice(WORD, WORD, bool); - void whitelist(DWORD); - void unWhitelist(DWORD); - void stop(DWORD); - - static void WINAPI SvcMain(DWORD, LPTSTR); - static void svcReportError(wchar_t *); - -private: - HidGuardian(DWORD); - int getStatus(void); - void setStatus(int); - int refreshStatus(void); - void setEnabled(bool); - - wchar_t *unpackInstaller64(); - bool exInstaller64(wchar_t *, wchar_t *); - wchar_t *download(void); - wchar_t *unzip(wchar_t *); - bool doInstall(wchar_t *); - bool installFilter(void); - bool updateDriver(wchar_t *); - void cleanupInstall(void); - bool installService(void); - int queryService(void); - bool startService(void); - void stopService(void); - void setSvcStatus(int); - UINT sendSvcMsg(pipeMsg *); - bool isElevated(void); - void elevate(wchar_t *); - void readSettings(void); - void writeSettings(void); - - static wchar_t *getRegMultiSz(HKEY, LPCTSTR); - static wchar_t *prependToMultiSz(wchar_t *, wchar_t *); - static wchar_t *removeFromMultiSz(wchar_t *, wchar_t *); - static size_t multiSzLen(wchar_t *); - - static void WINAPI svcCtrlHandler(DWORD); - static void svcReportStatus(DWORD, DWORD, DWORD); - static DWORD WINAPI pipeServerThread(LPVOID); - static DWORD WINAPI pipeWorkerThread(LPVOID); - static UINT svcAddDevice(wchar_t *); - static UINT svcDelDevice(wchar_t *); - static UINT svcAddWlist(UINT); - static UINT svcDelWlist(UINT); - - static HidGuardian *instance; - - static SERVICE_STATUS_HANDLE svcStatusHandle; - static SERVICE_STATUS svcStatus; - static HANDLE svcStopEvent; - - wchar_t *windowClass = L"HidGuardian"; - wchar_t *zipPath = nullptr; - wchar_t *fldPath = nullptr; - int hgStatus = STATUS_NOTINSTALLED; - int serviceStatus = SERVICE_STOPPED; - bool classIsRegistered = false; - bool enabled = true; - WORD currentVid = 0, currentPid = 0; - - HINSTANCE hInst = nullptr; - HWND mainWnd, statusWnd, svcWnd, installWnd, enabledWnd; - -}; \ No newline at end of file diff --git a/irFFB/irFFB.cpp b/irFFB/irFFB.cpp index 001f011..bced496 100644 --- a/irFFB/irFFB.cpp +++ b/irFFB/irFFB.cpp @@ -17,13 +17,13 @@ along with this program. If not, see . #include "irFFB.h" #include "Settings.h" -#include "jetseat.h" -#include "fan.h" -#include "hidguardian.h" #include "public.h" #include "yaml_parser.h" #include "vjoyinterface.h" - +#include "shlwapi.h" +#include +#include +#include #define MAX_LOADSTRING 100 #define STATUS_CONNECTED_PART 0 @@ -52,7 +52,7 @@ CRITICAL_SECTION effectCrit; DIJOYSTATE joyState; DWORD axes[1] = { DIJOFS_X }; -LONG dir[1] = { 0 }; +LONG dir[1] = { 0 }; DIPERIODIC pforce; DIEFFECT dieff; @@ -60,75 +60,74 @@ LogiLedData logiLedData; DIEFFESCAPE logiEscape; Settings settings; -JetSeat *jetseat; -Fan *fan; -HidGuardian *hidGuardian; + float firc6[] = { - 0.1295867f, 0.2311436f, 0.2582509f, 0.1923936f, 0.1156718f, 0.0729534f + 0.1295867f, 0.2311436f, 0.2582509f, 0.1923936f, 0.1156718f, 0.0729534f }; float firc12[] = { - 0.0322661f, 0.0696877f, 0.0967984f, 0.1243019f, 0.1317534f, 0.1388793f, - 0.1129315f, 0.0844297f, 0.0699100f, 0.0567884f, 0.0430215f, 0.0392321f + 0.0322661f, 0.0696877f, 0.0967984f, 0.1243019f, 0.1317534f, 0.1388793f, + 0.1129315f, 0.0844297f, 0.0699100f, 0.0567884f, 0.0430215f, 0.0392321f }; char car[MAX_CAR_NAME]; understeerCoefs usteerCoefs[] = { - { "astonmartin dbr9", 46.0f, 78.0f }, - { "audirs3lms", 40.0f, 70.0f }, - { "audir8gt3", 52.0f, 78.0f }, - { "bmwm8gte", 46.0f, 78.0f }, - { "bmwm4gt4", 40.0f, 70.0f }, - { "bmwz4gt3", 54.0f, 80.0f }, - { "bmwm4gt3", 37.5f, 82.0f }, - { "c6r", 40.5f, 82.0f }, - { "c8rvettegte", 48.0f, 78.0f }, - { "dallaraf3", 38.0f, 102.0f }, - { "dallarair18", 44.0f, 110.0f }, - { "dallarap217", 44.0f, 110.0f }, - { "ferrari488gt3", 52.0f, 78.0f }, - { "ferrarievogt3", 54.0f, 80.0f }, - { "ferrari488gte", 44.0f, 82.0f }, - { "fordgt gt3", 52.0f, 78.0f }, - { "formulamazda", 34.5f, 96.0f }, - { "formularenault20", 34.5f, 96.0f }, - { "formularenault35", 44.0f, 110.0f }, - { "formulavee", 23.0f, 68.0f }, - { "fr500s", 40.0f, 70.0f }, - { "hondacivictyper", 40.0f, 70.0f }, - { "hpdarx01c", 44.0f, 110.0f }, - { "hyundaielantracn7", 40.0f, 70.0f }, - { "indypropm18", 34.5f, 100.0f }, - { "lamborghinievogt3", 52.0f, 78.0f }, - { "lotus49", 23.8f, 70.0f }, - { "lotus79", 27.8f, 104.0f }, - { "mclaren570sgt4", 40.0f, 70.0f }, - { "mclarenmp4", 52.0f, 78.0f }, - { "mclarenmp430", 38.0f, 110.0f }, - { "mercedesamggt3", 37.5f, 82.0f }, - { "mercedesw12", 48.0f, 120.0f }, - { "mx5 mx52016", 36.0f, 96.0f }, - { "nissangtpzxt", 44.0f, 110.0f }, - { "porsche718gt4", 40.0f, 70.0f }, - { "porsche911cup", 46.0f, 88.0f }, - { "porsche992cup", 48.0f, 90.0f }, - { "porsche911rgt3", 52.0f, 80.0f }, - { "porsche991rsr", 42.0f, 72.0f }, - { "radical sr8", 40.0f, 100.0f }, - { "rt2000", 25.0f, 86.0f }, - { "rufrt12r track", 46.0f, 88.0f }, - { "specracer", 25.0f, 86.0f }, - { "usf2000usf17", 34.5f, 96.0f }, - { "v8supercars fordmustanggt", 52.0f, 78.0f }, - { "v8supercars holden2019", 52.0f, 78.0f }, - { "williamsfw31", 38.0f, 110.0f } + { "astonmartin dbr9", 46.0f, 78.0f }, + { "audirs3lms", 40.0f, 70.0f }, + { "audir8gt3", 52.0f, 78.0f }, + { "bmwm8gte", 46.0f, 78.0f }, + { "bmwm4gt4", 40.0f, 70.0f }, + { "bmwz4gt3", 54.0f, 80.0f }, + { "bmwm4gt3", 37.5f, 82.0f }, + { "c6r", 40.5f, 82.0f }, + { "c8rvettegte", 48.0f, 78.0f }, + { "dallaraf3", 38.0f, 102.0f }, + { "dallarair18", 44.0f, 110.0f }, + { "dallarap217", 44.0f, 110.0f }, + { "ferrari488gt3", 52.0f, 78.0f }, + { "ferrarievogt3", 54.0f, 80.0f }, + { "ferrari488gte", 44.0f, 82.0f }, + { "fordgt gt3", 52.0f, 78.0f }, + { "formulamazda", 34.5f, 96.0f }, + { "formularenault20", 34.5f, 96.0f }, + { "formularenault35", 44.0f, 110.0f }, + { "formulavee", 23.0f, 68.0f }, + { "fr500s", 40.0f, 70.0f }, + { "hondacivictyper", 40.0f, 70.0f }, + { "hpdarx01c", 44.0f, 110.0f }, + { "hyundaielantracn7", 40.0f, 70.0f }, + { "indypropm18", 34.5f, 100.0f }, + { "lamborghinievogt3", 52.0f, 78.0f }, + { "lotus49", 23.8f, 70.0f }, + { "lotus79", 27.8f, 104.0f }, + { "mclaren570sgt4", 40.0f, 70.0f }, + { "mclarenmp4", 52.0f, 78.0f }, + { "mclarenmp430", 38.0f, 110.0f }, + { "mercedesamggt3", 37.5f, 82.0f }, + { "mercedesw12", 48.0f, 120.0f }, + { "mx5 mx52016", 36.0f, 96.0f }, + { "nissangtpzxt", 44.0f, 110.0f }, + { "porsche718gt4", 40.0f, 70.0f }, + { "porsche911cup", 46.0f, 88.0f }, + { "porsche992cup", 48.0f, 90.0f }, + { "porsche911rgt3", 52.0f, 80.0f }, + { "porsche991rsr", 42.0f, 72.0f }, + { "radical sr8", 40.0f, 100.0f }, + { "rt2000", 25.0f, 86.0f }, + { "rufrt12r track", 46.0f, 88.0f }, + { "specracer", 25.0f, 86.0f }, + { "usf2000usf17", 34.5f, 96.0f }, + { "v8supercars fordmustanggt", 52.0f, 78.0f }, + { "v8supercars holden2019", 52.0f, 78.0f }, + { "williamsfw31", 38.0f, 110.0f }, + { "dummy", 0.0f, 0.0f } }; int force = 0; -volatile float suspForce = 0.0f; +volatile float suspForce = 0.0f; volatile float yawForce[DIRECT_INTERP_SAMPLES]; __declspec(align(16)) volatile float suspForceST[DIRECT_INTERP_SAMPLES]; -bool onTrack = false, stopped = true, deviceChangePending = false, logiWheel = false; +bool onTrack = false, stopped = true, deviceChangePending = false, logiWheel = false, sleepSpin = false; volatile int ffbMag = 0; volatile bool nearStops = false; @@ -137,2163 +136,2499 @@ int numButtons = 0, numPov = 0, vjButtons = 0, vjPov = 0; UINT samples, clippedSamples; HANDLE wheelEvent = CreateEvent(nullptr, false, false, L"WheelEvent"); -HANDLE ffbEvent = CreateEvent(nullptr, false, false, L"FFBEvent"); +HANDLE ffbEvent = CreateEvent(nullptr, false, false, L"FFBEvent"); + +#define ID_SMOOTHPROGRESSCTRL 402 -HWND mainWnd, textWnd, statusWnd; +int progressClippingMax = 500; +HWND mainWnd, textWnd, statusWnd, overlayWnd, currentForceWnd, clippingForceWnd, currentForceOverlayWnd, clippingForceOverlayWnd, overlayMoveWnd; LARGE_INTEGER freq; int vjDev = 1; FFB_DATA ffbPacket; +RTL_OSVERSIONINFOW winVer; -float *floatvarptr(const char *data, const char *name) { - int idx = irsdk_varNameToIndex(name); - if (idx >= 0) - return (float *)(data + irsdk_getVarHeaderEntry(idx)->offset); - else - return nullptr; +DWORD windowInitialExtendedState = NULL; + + +float* floatvarptr(const char* data, const char* name) { + int idx = irsdk_varNameToIndex(name); + if (idx >= 0) + return (float*)(data + irsdk_getVarHeaderEntry(idx)->offset); + else + return nullptr; } -int *intvarptr(const char *data, const char *name) { - int idx = irsdk_varNameToIndex(name); - if (idx >= 0) - return (int *)(data + irsdk_getVarHeaderEntry(idx)->offset); - else - return nullptr; +int* intvarptr(const char* data, const char* name) { + int idx = irsdk_varNameToIndex(name); + if (idx >= 0) + return (int*)(data + irsdk_getVarHeaderEntry(idx)->offset); + else + return nullptr; } -bool *boolvarptr(const char *data, const char *name) { - int idx = irsdk_varNameToIndex(name); - if (idx >= 0) - return (bool *)(data + irsdk_getVarHeaderEntry(idx)->offset); - else - return nullptr; +bool* boolvarptr(const char* data, const char* name) { + int idx = irsdk_varNameToIndex(name); + if (idx >= 0) + return (bool*)(data + irsdk_getVarHeaderEntry(idx)->offset); + else + return nullptr; +} + +bool IsSavedDisplayActive() +{ + // Check if we have a monitor + bool has = false; + + // Iterate over all displays and check if we have a valid one. + // If the device ID contains the string default_monitor no monitor is attached. + DISPLAY_DEVICE dd; + dd.cb = sizeof(dd); + int deviceIndex = 0; + while (EnumDisplayDevices(0, deviceIndex, &dd, 0)) + { + std::wstring deviceName = dd.DeviceName; + int monitorIndex = 0; + while (EnumDisplayDevices(deviceName.c_str(), monitorIndex, &dd, 0)) + { + size_t len = _tcslen(dd.DeviceID); + for (size_t i = 0; i < len; ++i) + dd.DeviceID[i] = _totlower(dd.DeviceID[i]); + + has = has || ((len > 10 && _tcsstr(dd.DeviceID, L"default_monitor") == nullptr) && dd.StateFlags & DISPLAY_DEVICE_ACTIVE); + + ++monitorIndex; + } + ++deviceIndex; + } + + return has; +} + + +RTL_OSVERSIONINFOW GetRealOSVersion() { + HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); + if (hMod) { + RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); + if (fxPtr != nullptr) { + RTL_OSVERSIONINFOW rovi = { 0 }; + rovi.dwOSVersionInfoSize = sizeof(rovi); + if (STATUS_SUCCESS == fxPtr(&rovi)) { + return rovi; + } + } + } + RTL_OSVERSIONINFOW rovi = { 0 }; + return rovi; } // Thread that reads the wheel, writes to vJoy and updates the DI effect DWORD WINAPI readWheelThread(LPVOID lParam) { - UNREFERENCED_PARAMETER(lParam); - - HRESULT res; - JOYSTICK_POSITION vjData; - DWORD *hats[] = { &vjData.bHats, &vjData.bHatsEx1, &vjData.bHatsEx2, &vjData.bHatsEx3 }; - ResetVJD(vjDev); - LONG lastX; - LARGE_INTEGER lastTime, time, elapsed; - float vel[DIRECT_INTERP_SAMPLES] = { 0.0f }, fd[4] = { 0.0f }; - int velIdx = 0, vi = 0, fdIdx = 0; - float d = 0.0f; + UNREFERENCED_PARAMETER(lParam); - lastTime.QuadPart = 0; + HRESULT res; + JOYSTICK_POSITION vjData; + DWORD* hats[] = { &vjData.bHats, &vjData.bHatsEx1, &vjData.bHatsEx2, &vjData.bHatsEx3 }; + ResetVJD(vjDev); + LONG lastX; + LARGE_INTEGER lastTime, time, elapsed; + float vel[DIRECT_INTERP_SAMPLES] = { 0.0f }, fd[4] = { 0.0f }; + int velIdx = 0, vi = 0, fdIdx = 0; + float d = 0.0f; - while (true) { + lastTime.QuadPart = 0; - DWORD signaled = WaitForSingleObject(wheelEvent, 1); + while (true) { - if (!ffdevice) - continue; + DWORD signaled = WaitForSingleObject(wheelEvent, 1); - if (signaled == WAIT_OBJECT_0) { + if (!ffdevice) + continue; - res = ffdevice->GetDeviceState(sizeof(joyState), &joyState); - if (res != DI_OK) { - debug(L"GetDeviceState returned: 0x%x, requesting reacquire", res); - reacquireDIDevice(); - continue; - } + if (signaled == WAIT_OBJECT_0) { - vjData.wAxisX = joyState.lX; - vjData.wAxisY = joyState.lY; - vjData.wAxisZ = joyState.lZ; - vjData.wAxisXRot = joyState.lRx; - vjData.wAxisYRot = joyState.lRy; - vjData.wAxisZRot = joyState.lRz; + res = ffdevice->GetDeviceState(sizeof(joyState), &joyState); + if (res != DI_OK) { + debug(L"GetDeviceState returned: 0x%x, requesting reacquire", res); + reacquireDIDevice(); + continue; + } - if (vjButtons > 0) - for (int i = 0; i < numButtons; i++) { - if (joyState.rgbButtons[i]) - vjData.lButtons |= 1 << i; - else - vjData.lButtons &= ~(1 << i); - } + vjData.wAxisX = joyState.lX; + vjData.wAxisY = joyState.lY; + vjData.wAxisZ = joyState.lZ; + vjData.wAxisXRot = joyState.lRx; + vjData.wAxisYRot = joyState.lRy; + vjData.wAxisZRot = joyState.lRz; - // This could be wrong, untested.. - if (vjPov > 0) - for (int i = 0; i < numPov && i < 4; i++) - *hats[i] = joyState.rgdwPOV[i]; + if (vjButtons > 0) + for (int i = 0; i < numButtons; i++) { + if (joyState.rgbButtons[i]) + vjData.lButtons |= 1 << i; + else + vjData.lButtons &= ~(1 << i); + } - UpdateVJD(vjDev, (PVOID)&vjData); + // This could be wrong, untested.. + if (vjPov > 0) + for (int i = 0; i < numPov && i < 4; i++) + *hats[i] = joyState.rgdwPOV[i]; - if (effect == nullptr) - continue; + UpdateVJD(vjDev, (PVOID)&vjData); + + if (effect == nullptr) + continue; - if (settings.getDampingFactor() != 0.0f || nearStops) { + if (settings.getDampingFactor() != 0.0f || nearStops) { - QueryPerformanceCounter(&time); + QueryPerformanceCounter(&time); - if (lastTime.QuadPart != 0) { - elapsed.QuadPart = (time.QuadPart - lastTime.QuadPart) * 1000000; - elapsed.QuadPart /= freq.QuadPart; - vel[velIdx] = (float)(joyState.lX - lastX) / elapsed.QuadPart; - } + if (lastTime.QuadPart != 0) { + elapsed.QuadPart = (time.QuadPart - lastTime.QuadPart) * 1000000; + elapsed.QuadPart /= freq.QuadPart; + vel[velIdx] = (float)(joyState.lX - lastX) / elapsed.QuadPart; + } - lastTime.QuadPart = time.QuadPart; - lastX = joyState.lX; + lastTime.QuadPart = time.QuadPart; + lastX = joyState.lX; - vi = velIdx; + vi = velIdx; - if (++velIdx > DIRECT_INTERP_SAMPLES - 1) - velIdx = 0; + if (++velIdx > DIRECT_INTERP_SAMPLES - 1) + velIdx = 0; - fd[fdIdx] = vel[vi++] * firc6[0]; - for (int i = 1; i < DIRECT_INTERP_SAMPLES; i++) { - if (vi > DIRECT_INTERP_SAMPLES - 1) - vi = 0; - fd[fdIdx] += vel[vi++] * firc6[i]; - } + fd[fdIdx] = vel[vi++] * firc6[0]; + for (int i = 1; i < DIRECT_INTERP_SAMPLES; i++) { + if (vi > DIRECT_INTERP_SAMPLES - 1) + vi = 0; + fd[fdIdx] += vel[vi++] * firc6[i]; + } - if (++fdIdx > 3) - fdIdx = 0; + if (++fdIdx > 3) + fdIdx = 0; - d = (fd[0] + fd[1] + fd[2] + fd[3]) / 4.0f; + d = (fd[0] + fd[1] + fd[2] + fd[3]) / 4.0f; - if (nearStops) - d *= DAMPING_MULTIPLIER_STOPS; - else - d *= DAMPING_MULTIPLIER * settings.getDampingFactor(); + if (nearStops) + d *= DAMPING_MULTIPLIER_STOPS; + else + d *= DAMPING_MULTIPLIER * settings.getDampingFactor(); - } - else - d = 0.0f; + } + else + d = 0.0f; - } + } - pforce.lOffset = ffbMag; - pforce.lOffset += (int)d; + pforce.lOffset = ffbMag; + pforce.lOffset += (int)d; - if (pforce.lOffset > DI_MAX) - pforce.lOffset = DI_MAX; - else if (pforce.lOffset < -DI_MAX) - pforce.lOffset = -DI_MAX; + if (pforce.lOffset > DI_MAX) + pforce.lOffset = DI_MAX; + else if (pforce.lOffset < -DI_MAX) + pforce.lOffset = -DI_MAX; - EnterCriticalSection(&effectCrit); + EnterCriticalSection(&effectCrit); - if (effect == nullptr) { - LeaveCriticalSection(&effectCrit); - continue; - } + if (effect == nullptr) { + LeaveCriticalSection(&effectCrit); + continue; + } - HRESULT hr = effect->SetParameters(&dieff, DIEP_TYPESPECIFICPARAMS | DIEP_NORESTART); - if (hr != DI_OK) { - debug(L"SetParameters returned 0x%x, requesting reacquire", hr); - reacquireDIDevice(); - } + HRESULT hr = effect->SetParameters(&dieff, DIEP_TYPESPECIFICPARAMS | DIEP_NORESTART); + if (hr != DI_OK) { + debug(L"SetParameters returned 0x%x, requesting reacquire", hr); + reacquireDIDevice(); + } - LeaveCriticalSection(&effectCrit); + LeaveCriticalSection(&effectCrit); - } + } } // Calculate FFB samples for the direct modes DWORD WINAPI directFFBThread(LPVOID lParam) { - UNREFERENCED_PARAMETER(lParam); - int16_t mag; - - float s; - int r; - __declspec(align(16)) float prod[12]; - float lastSuspForce = 0, lastYawForce = 0; - LARGE_INTEGER start; - - while (true) { - - bool use360 = settings.getUse360ForDirect(); - - // Signalled when force has been updated - WaitForSingleObject(ffbEvent, INFINITE); - - if ( - settings.getFfbType() != FFBTYPE_DIRECT_FILTER && - settings.getFfbType() != FFBTYPE_DIRECT_FILTER_720 - ) - continue; - - if (((ffbPacket.data[0] & 0xF0) >> 4) != vjDev) - continue; - - mag = (ffbPacket.data[3] << 8) + ffbPacket.data[2]; - - QueryPerformanceCounter(&start); - - // sign extend - force = mag; - - s = (float)force; + UNREFERENCED_PARAMETER(lParam); + int16_t mag; + + float s; + int r; + __declspec(align(16)) float prod[12]; + float lastSuspForce = 0, lastYawForce = 0; + LARGE_INTEGER start; + + + while (true) { + + bool use360 = settings.getUse360ForDirect(); + + // Signalled when force has been updated + WaitForSingleObject(ffbEvent, INFINITE); + + if ( + settings.getFfbType() != FFBTYPE_DIRECT_FILTER && + settings.getFfbType() != FFBTYPE_DIRECT_FILTER_720 + ) + continue; + + if (((ffbPacket.data[0] & 0xF0) >> 4) != vjDev) + continue; + + mag = (ffbPacket.data[3] << 8) + ffbPacket.data[2]; + + QueryPerformanceCounter(&start); + + // sign extend + force = mag; + + s = (float)force; + + if (!use360) + s += scaleTorque(suspForce); + + if (settings.getFfbType() == FFBTYPE_DIRECT_FILTER_720) { + + prod[0] = s * firc12[0]; + { + __m128 mp0 = _mm_load_ps(prod); + __m128 mp1 = _mm_load_ps(prod + 4); + __m128 mp2 = _mm_load_ps(prod + 8); + mp0 = _mm_add_ps(_mm_add_ps(mp0, mp1), mp2); + mp0 = _mm_hadd_ps(mp0, mp0); + mp0 = _mm_hadd_ps(mp0, mp0); + r = _mm_cvttss_si32(mp0); + } + /*_asm { + movaps xmm0, xmmword ptr prod + movaps xmm1, xmmword ptr prod+16 + movaps xmm2, xmmword ptr prod+32 + addps xmm0, xmm1 + addps xmm0, xmm2 + haddps xmm0, xmm0 + haddps xmm0, xmm0 + cvttss2si eax, xmm0 + mov dword ptr r, eax + }*/ + + if (use360) + r += scaleTorque(lastSuspForce + (suspForceST[0] - lastSuspForce) / 2.0f); + + r += scaleTorque(lastYawForce + (yawForce[0] - lastYawForce) / 2.0f); + + setFFB(r); + + for (int i = 1; i < DIRECT_INTERP_SAMPLES * 2 - 1; i++) { + + prod[i] = s * firc12[i]; + { + __m128 mp0 = _mm_load_ps(prod); + __m128 mp1 = _mm_load_ps(prod + 4); + __m128 mp2 = _mm_load_ps(prod + 8); + mp0 = _mm_add_ps(_mm_add_ps(mp0, mp1), mp2); + mp0 = _mm_hadd_ps(mp0, mp0); + mp0 = _mm_hadd_ps(mp0, mp0); + r = _mm_cvttss_si32(mp0); + } + /* + _asm { + movaps xmm0, xmmword ptr prod + movaps xmm1, xmmword ptr prod + 16 + movaps xmm2, xmmword ptr prod + 32 + addps xmm0, xmm1 + addps xmm0, xmm2 + haddps xmm0, xmm0 + haddps xmm0, xmm0 + cvttss2si eax, xmm0 + mov dword ptr r, eax + } + */ + int idx = (i - 1) >> 1; + bool odd = i & 1; + + if (use360) + r += + scaleTorque( + odd ? + suspForceST[idx] : + suspForceST[idx] + (suspForceST[idx + 1] - suspForceST[idx]) / 2.0f + ); + + r += + scaleTorque( + odd ? + yawForce[idx] : + yawForce[idx] + (yawForce[idx + 1] - yawForce[idx]) / 2.0f + ); + + //nanosleep(1380 * i); + + sleepSpinUntil(&start, 1000, 1380 * i); + setFFB(r); + + } + + prod[DIRECT_INTERP_SAMPLES * 2 - 1] = s * firc12[DIRECT_INTERP_SAMPLES * 2 - 1]; + __m128 mp0 = _mm_load_ps(prod); + __m128 mp1 = _mm_load_ps(prod + 4); + __m128 mp2 = _mm_load_ps(prod + 8); + mp0 = _mm_add_ps(_mm_add_ps(mp0, mp1), mp2); + mp0 = _mm_hadd_ps(mp0, mp0); + mp0 = _mm_hadd_ps(mp0, mp0); + r = _mm_cvttss_si32(mp0); + /*_asm { + movaps xmm0, xmmword ptr prod + movaps xmm1, xmmword ptr prod + 16 + movaps xmm2, xmmword ptr prod + 32 + addps xmm0, xmm1 + addps xmm0, xmm2 + haddps xmm0, xmm0 + haddps xmm0, xmm0 + cvttss2si eax, xmm0 + mov dword ptr r, eax + }*/ + + if (use360) + r += scaleTorque(suspForceST[DIRECT_INTERP_SAMPLES - 1]); + + r += scaleTorque(yawForce[DIRECT_INTERP_SAMPLES - 1]); + + //nanosleep(1380 * (DIRECT_INTERP_SAMPLES * 2 - 1)); + sleepSpinUntil(&start, 1000, 1380 * (DIRECT_INTERP_SAMPLES * 2 - 1)); + setFFB(r); + + lastSuspForce = suspForceST[DIRECT_INTERP_SAMPLES - 1]; + lastYawForce = yawForce[DIRECT_INTERP_SAMPLES - 1]; + + continue; + + } + + prod[0] = s * firc6[0]; + r = (int)(prod[0] + prod[1] + prod[2] + prod[3] + prod[4] + prod[5]) + + scaleTorque(yawForce[0]); + + if (use360) + r += scaleTorque(suspForceST[0]); + + setFFB(r); + + for (int i = 1; i < DIRECT_INTERP_SAMPLES; i++) { + + prod[i] = s * firc6[i]; + r = (int)(prod[0] + prod[1] + prod[2] + prod[3] + prod[4] + prod[5]) + + scaleTorque(yawForce[i]); + + if (use360) + r += scaleTorque(suspForceST[i]); + + sleepSpinUntil(&start, 2000, 2760 * i); + //nanosleep(2760 * i); + setFFB(r); + } + } + + return 0; - if (!use360) - s += scaleTorque(suspForce); +} - if (settings.getFfbType() == FFBTYPE_DIRECT_FILTER_720) { +void resetForces() { + debug(L"Resetting forces"); + suspForce = 0; + for (int i = 0; i < DIRECT_INTERP_SAMPLES; i++) { + suspForceST[i] = 0; + yawForce[i] = 0; + } + force = 0; + setFFB(0); +} - prod[0] = s * firc12[0]; +boolean getCarName() { - _asm { - movaps xmm0, xmmword ptr prod - movaps xmm1, xmmword ptr prod+16 - movaps xmm2, xmmword ptr prod+32 - addps xmm0, xmm1 - addps xmm0, xmm2 - haddps xmm0, xmm0 - haddps xmm0, xmm0 - cvttss2si eax, xmm0 - mov dword ptr r, eax - } + char buf[64]; + const char* ptr; + int len = -1, carIdx = -1; - if (use360) - r += scaleTorque(lastSuspForce + (suspForceST[0] - lastSuspForce) / 2.0f); + car[0] = 0; - r += scaleTorque(lastYawForce + (yawForce[0] - lastYawForce) / 2.0f); + // Get car idx + if (!parseYaml(irsdk_getSessionInfoStr(), "DriverInfo:DriverCarIdx:", &ptr, &len)) + return false; - setFFB(r); + if (len < 0 || len > sizeof(buf) - 1) + return false; - for (int i = 1; i < DIRECT_INTERP_SAMPLES * 2 - 1; i++) { + memcpy(buf, ptr, len); + buf[len] = 0; + carIdx = atoi(buf); - prod[i] = s * firc12[i]; + // Get car path + sprintf_s(buf, "DriverInfo:Drivers:CarIdx:{%d}CarPath:", carIdx); + if (!parseYaml(irsdk_getSessionInfoStr(), buf, &ptr, &len)) + return false; + if (len < 0 || len > sizeof(car) - 1) + return false; - _asm { - movaps xmm0, xmmword ptr prod - movaps xmm1, xmmword ptr prod + 16 - movaps xmm2, xmmword ptr prod + 32 - addps xmm0, xmm1 - addps xmm0, xmm2 - haddps xmm0, xmm0 - haddps xmm0, xmm0 - cvttss2si eax, xmm0 - mov dword ptr r, eax - } + memcpy(car, ptr, len); + car[len] = 0; - int idx = (i - 1) >> 1; - bool odd = i & 1; + return true; - if (use360) - r += - scaleTorque( - odd ? - suspForceST[idx] : - suspForceST[idx] + (suspForceST[idx + 1] - suspForceST[idx]) / 2.0f - ); +} - r += - scaleTorque( - odd ? - yawForce[idx] : - yawForce[idx] + (yawForce[idx + 1] - yawForce[idx]) / 2.0f - ); +float getCarRedline() { - sleepSpinUntil(&start, 0, 1380 * i); - setFFB(r); + char buf[64]; + const char* ptr; + int len = -1; - } + if (parseYaml(irsdk_getSessionInfoStr(), "DriverInfo:DriverCarRedLine:", &ptr, &len)) { - prod[DIRECT_INTERP_SAMPLES * 2 - 1] = s * firc12[DIRECT_INTERP_SAMPLES * 2 - 1]; - _asm { - movaps xmm0, xmmword ptr prod - movaps xmm1, xmmword ptr prod + 16 - movaps xmm2, xmmword ptr prod + 32 - addps xmm0, xmm1 - addps xmm0, xmm2 - haddps xmm0, xmm0 - haddps xmm0, xmm0 - cvttss2si eax, xmm0 - mov dword ptr r, eax - } + if (len < 0 || len > sizeof(buf) - 1) + return 8000.0f; - if (use360) - r += scaleTorque(suspForceST[DIRECT_INTERP_SAMPLES - 1]); + memcpy(buf, ptr, len); + buf[len] = 0; + return strtof(buf, NULL); + } - r += scaleTorque(yawForce[DIRECT_INTERP_SAMPLES - 1]); + return 8000.0f; - sleepSpinUntil(&start, 0, 1380 * (DIRECT_INTERP_SAMPLES * 2 - 1)); - setFFB(r); +} - lastSuspForce = suspForceST[DIRECT_INTERP_SAMPLES - 1]; - lastYawForce = yawForce[DIRECT_INTERP_SAMPLES - 1]; +bool getBuildInCarUsteerCoeffs(char* car) { - continue; + if (settings.getUndersteerlatAccelDiv() > 0 && settings.getUndersteerYawRateMult() > 0) + { + return true; + } + for (int i = 0; i < sizeof(usteerCoefs) / sizeof(usteerCoefs[0]); i++) + if (!strcmp(car, usteerCoefs[i].car)) + { + debug(L"We have understeer coeffs for car %s", car); + settings.setUndersteerYawRateMult(usteerCoefs[i].yawRateMult, (HWND)-1); + settings.setUndersteerlatAccelDiv(usteerCoefs[i].latAccelDiv, (HWND)-1); + return true; + } - } - - prod[0] = s * firc6[0]; - r = (int)(prod[0] + prod[1] + prod[2] + prod[3] + prod[4] + prod[5]) + - scaleTorque(yawForce[0]); + debug(L"No understeer coeffs for car %s", car); + return false; - if (use360) - r += scaleTorque(suspForceST[0]); +} - setFFB(r); +void clippingReport() { - for (int i = 1; i < DIRECT_INTERP_SAMPLES; i++) { + float clippedPerCent = samples > 0 ? (float)clippedSamples * 100.0f / samples : 0.0f; + text(L"%.02f%% of samples were clipped", clippedPerCent); + if (clippedPerCent > 2.5f) + text(L"Consider increasing max force to reduce clipping"); + samples = clippedSamples = 0; - prod[i] = s * firc6[i]; - r = (int)(prod[0] + prod[1] + prod[2] + prod[3] + prod[4] + prod[5]) + - scaleTorque(yawForce[i]); +} - if (use360) - r += scaleTorque(suspForceST[i]); +void logiRpmLed(float* rpm, float redline) { - sleepSpinUntil(&start, 2000, 2760 * i); - setFFB(r); + logiLedData.rpmData.rpm = *rpm / (redline * 0.90f); + logiLedData.rpmData.rpmFirstLed = 0.65f; + logiLedData.rpmData.rpmRedLine = 1.0f; - } + ffdevice->Escape(&logiEscape); - } +} - return 0; +void deviceChange() { -} + debug(L"Device change notification"); + if (!onTrack) { + debug(L"Not on track, processing device change"); + deviceChangePending = false; + enumDirectInput(); + if (!settings.isFfbDevicePresent()) + releaseDirectInput(); + } + else { + debug(L"Deferring device change processing whilst on track"); + deviceChangePending = true; + } -void resetForces() { - debug(L"Resetting forces"); - suspForce = 0; - for (int i = 0; i < DIRECT_INTERP_SAMPLES; i++) { - suspForceST[i] = 0; - yawForce[i] = 0; - } - force = 0; - setFFB(0); } -boolean getCarName() { - - char buf[64]; - const char *ptr; - int len = -1, carIdx = -1; +DWORD getDeviceVidPid(LPDIRECTINPUTDEVICE8 dev) { - car[0] = 0; + DIPROPDWORD dipdw; + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; - // Get car idx - if (!parseYaml(irsdk_getSessionInfoStr(), "DriverInfo:DriverCarIdx:", &ptr, &len)) - return false; + if (dev == nullptr) + return 0; - if (len < 0 || len > sizeof(buf) - 1) - return false; - - memcpy(buf, ptr, len); - buf[len] = 0; - carIdx = atoi(buf); + if (!SUCCEEDED(dev->GetProperty(DIPROP_VIDPID, &dipdw.diph))) + return 0; - // Get car path - sprintf_s(buf, "DriverInfo:Drivers:CarIdx:{%d}CarPath:", carIdx); - if (!parseYaml(irsdk_getSessionInfoStr(), buf, &ptr, &len)) - return false; - if (len < 0 || len > sizeof(car) - 1) - return false; + return dipdw.dwData; - memcpy(car, ptr, len); - car[len] = 0; +} - return true; - +void minimise() { + debug(L"Minimising window"); + Shell_NotifyIcon(NIM_ADD, &niData); + ShowWindow(mainWnd, SW_HIDE); } -float getCarRedline() { +void restore() { + debug(L"Restoring window"); + Shell_NotifyIcon(NIM_DELETE, &niData); + ShowWindow(mainWnd, SW_SHOW); + BringWindowToTop(mainWnd); + SetForegroundWindow(mainWnd); +} - char buf[64]; - const char *ptr; - int len = -1; +int APIENTRY wWinMain( + _In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPWSTR lpCmdLine, + _In_ int nCmdShow +) { - if (parseYaml(irsdk_getSessionInfoStr(), "DriverInfo:DriverCarRedLine:", &ptr, &len)) { + UNREFERENCED_PARAMETER(hPrevInstance); + + globalMutex = CreateMutex(NULL, false, L"Global\\irFFB_Mutex"); + + if (GetLastError() == ERROR_ALREADY_EXISTS) + exit(0); + + INITCOMMONCONTROLSEX ccEx; + + HANDLE handles[1]; + char* data = nullptr; + bool irConnected = false; + MSG msg; + + float* swTorque = nullptr, * swTorqueST = nullptr, * steer = nullptr, * steerMax = nullptr; + float* speed = nullptr, * throttle = nullptr, * rpm = nullptr; + float* LFshockDeflST = nullptr, * RFshockDeflST = nullptr, * CFshockDeflST = nullptr; + float* LRshockDeflST = nullptr, * RRshockDeflST = nullptr; + float* vX = nullptr, * vY = nullptr; + float* latAccel = nullptr, * yawRate = nullptr; + float LFshockDeflLast = -10000, RFshockDeflLast = -10000, CFshockDeflLast = -10000; + float LRshockDeflLast = -10000, RRshockDeflLast = -10000; + bool* isOnTrack = nullptr; + int* trackSurface = nullptr, * gear = nullptr; + + bool inGarage = false; + int numHandles = 0, dataLen = 0, lastGear = 0; + int STnumSamples = 0, STmaxIdx = 0, lastTrackSurface = -1; + float halfSteerMax = 0, lastTorque = 0, lastSuspForce = 0, redline; + float yaw = 0.0f, yawFilter[DIRECT_INTERP_SAMPLES]; + + ccEx.dwICC = ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_STANDARD_CLASSES; + ccEx.dwSize = sizeof(ccEx); + InitCommonControlsEx(&ccEx); + + HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_IRFFB)); +#ifdef _M_X64 + LoadStringW(hInstance, IDS_APP_TITLE_64, szTitle, MAX_LOADSTRING); +#else// _M_X64 + LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); +#endif + + + LoadStringW(hInstance, IDC_IRFFB, szWindowClass, MAX_LOADSTRING); + MyRegisterClass(hInstance); + + // Setup DI FFB effect + pforce.dwMagnitude = 0; + pforce.dwPeriod = INFINITE; + pforce.dwPhase = 0; + pforce.lOffset = 0; + + ZeroMemory(&dieff, sizeof(dieff)); + dieff.dwSize = sizeof(DIEFFECT); + dieff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + dieff.dwDuration = INFINITE; + dieff.dwSamplePeriod = 0; + dieff.dwGain = DI_FFNOMINALMAX; + dieff.dwTriggerButton = DIEB_NOTRIGGER; + dieff.dwTriggerRepeatInterval = 0; + dieff.cAxes = 1; + dieff.rgdwAxes = axes; + dieff.rglDirection = dir; + dieff.lpEnvelope = NULL; + dieff.cbTypeSpecificParams = sizeof(DIPERIODIC); + dieff.lpvTypeSpecificParams = &pforce; + dieff.dwStartDelay = 0; + + ZeroMemory(&logiLedData, sizeof(logiLedData)); + logiLedData.size = sizeof(logiLedData); + logiLedData.version = 1; + ZeroMemory(&logiEscape, sizeof(logiEscape)); + logiEscape.dwSize = sizeof(DIEFFESCAPE); + logiEscape.dwCommand = 0; + logiEscape.lpvInBuffer = &logiLedData; + logiEscape.cbInBuffer = sizeof(logiLedData); + + InitializeCriticalSection(&effectCrit); + + if (!InitInstance(hInstance, nCmdShow)) + return FALSE; + + memset(car, 0, sizeof(car)); + setCarStatus(car); + setConnectedStatus(false); + setOnTrackStatus(false); + + settings.readGenericSettings(); + settings.readRegSettings(car); + // Hack! try set better sleep resulution with undocumented NtSetTimerResolution, no error checking or nothing for now + ULONG CurrentResolution = 0; + ULONG MininumResolution = 0; + ULONG MaximumResolution = 0; + if (STATUS_SUCCESS == NtQueryTimerResolution(&MininumResolution, &MaximumResolution, &CurrentResolution)) + { + NtSetTimerResolution(MaximumResolution, TRUE, &CurrentResolution); + } + else + { + text(L"Unable to set high resolution timer, reverting to old sleep routine"); + } + + sleepSpin = CurrentResolution == 0 || CurrentResolution > 10000; + + winVer = GetRealOSVersion(); + + if (winVer.dwMajorVersion < 10 || (winVer.dwMajorVersion == 10 && winVer.dwBuildNumber < 17134) || sleepSpin) + { + settings.setUseAltTimer(true); + EnableWindow(settings.getAltTimerWnd(), FALSE); + } + + if (settings.getShowForceOverlay()) + { + SetLayeredWindowAttributes(overlayWnd, 0, settings.getOverlayTransparency(), LWA_ALPHA); + SetWindowPos(overlayWnd, NULL, settings.getWindowPosX(), settings.getWindowPosY(), 200, OVERLAY_WINDOW_HEIGHT - 20, SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOACTIVATE); + EnableWindow(overlayMoveWnd, TRUE); + } + if (RegisterHotKey(mainWnd, 1, MOD_ALT | MOD_CONTROL | MOD_NOREPEAT, VK_UP)) + { + text(L"Max force+ Hotkey 'ALT + CONTROL + UP' registered"); + } + if (RegisterHotKey(mainWnd, 2, MOD_ALT | MOD_CONTROL | MOD_NOREPEAT, VK_DOWN)) + { + text(L"Max force- Hotkey 'ALT + CONTROL + DOWN' registered"); + } + + //int posX = settings.getWindowPosX(); + //int posY = settings.getWindowPosY(); + //RECT workArea; + //SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0); + //posX += workArea.left; + //posY += workArea.top; + + // make sure the window is not completely out of sight + /*int max_x = GetSystemMetrics(SM_CXSCREEN) - + GetSystemMetrics(SM_CXICON); + int max_y = GetSystemMetrics(SM_CYSCREEN) - + GetSystemMetrics(SM_CYICON); + + posX = min(posX, max_x); + posY = min(posY, max_y); + + SetWindowPos(mainWnd, nullptr, posX, posY, 864, 760, 0);*/ + + if (settings.getStartMinimised()) + minimise(); + else + { + restore(); + } + + enumDirectInput(); + + LARGE_INTEGER start; + QueryPerformanceFrequency(&freq); + + initVJD(); + SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); + + SetThreadPriority( + CreateThread(NULL, 0, readWheelThread, NULL, 0, NULL), THREAD_PRIORITY_HIGHEST + ); + SetThreadPriority( + CreateThread(NULL, 0, directFFBThread, NULL, 0, NULL), THREAD_PRIORITY_HIGHEST + ); + + debug(L"Init complete, entering mainloop"); + + while (TRUE) { + + DWORD res; + const irsdk_header* hdr = NULL; + + if ( + irsdk_startup() && (hdr = irsdk_getHeader()) && + hdr->status & irsdk_stConnected && hdr->bufLen != dataLen && hdr->bufLen != 0 + ) { + + debug(L"New iRacing session"); + + handles[0] = hDataValidEvent; + numHandles = 1; + + if (data != NULL) + free(data); + + dataLen = irsdk_getHeader()->bufLen; + data = (char*)malloc(dataLen); + setConnectedStatus(true); + + if (getCarName() && settings.getUseCarSpecific()) { + setCarStatus(car); + settings.readSettingsForCar(car); + } + else + setCarStatus(nullptr); + + redline = getCarRedline(); + debug(L"Redline is %d rpm", (int)redline); + + getBuildInCarUsteerCoeffs(car); + + // Inform iRacing of the maxForce setting + irsdk_broadcastMsg(irsdk_BroadcastFFBCommand, irsdk_FFBCommand_MaxForce, (float)settings.getMaxForce()); + + swTorque = floatvarptr(data, "SteeringWheelTorque"); + swTorqueST = floatvarptr(data, "SteeringWheelTorque_ST"); + steer = floatvarptr(data, "SteeringWheelAngle"); + steerMax = floatvarptr(data, "SteeringWheelAngleMax"); + speed = floatvarptr(data, "Speed"); + throttle = floatvarptr(data, "Throttle"); + rpm = floatvarptr(data, "RPM"); + gear = intvarptr(data, "Gear"); + isOnTrack = boolvarptr(data, "IsOnTrack"); + + trackSurface = intvarptr(data, "PlayerTrackSurface"); + vX = floatvarptr(data, "VelocityX"); + vY = floatvarptr(data, "VelocityY"); + + latAccel = floatvarptr(data, "LatAccel"); + yawRate = floatvarptr(data, "YawRate"); + + RFshockDeflST = floatvarptr(data, "RFshockDefl_ST"); + LFshockDeflST = floatvarptr(data, "LFshockDefl_ST"); + LRshockDeflST = floatvarptr(data, "LRshockDefl_ST"); + RRshockDeflST = floatvarptr(data, "RRshockDefl_ST"); + CFshockDeflST = floatvarptr(data, "CFshockDefl_ST"); + + int swTorqueSTidx = irsdk_varNameToIndex("SteeringWheelTorque_ST"); + STnumSamples = irsdk_getVarHeaderEntry(swTorqueSTidx)->count; + STmaxIdx = STnumSamples - 1; + + lastTorque = 0.0f; + onTrack = false; + resetForces(); + irConnected = true; + timeBeginPeriod(1); - if (len < 0 || len > sizeof(buf) - 1) - return 8000.0f; - - memcpy(buf, ptr, len); - buf[len] = 0; - return strtof(buf, NULL); - } - - return 8000.0f; + } + + res = MsgWaitForMultipleObjects(numHandles, handles, FALSE, 1000, QS_ALLINPUT); + + QueryPerformanceCounter(&start); + + if (numHandles > 0 && res == numHandles - 1 && irsdk_getNewData(data)) { + + if (onTrack && !*isOnTrack) { + debug(L"No longer on track"); + onTrack = false; + setOnTrackStatus(onTrack); + lastTorque = lastSuspForce = 0.0f; + resetForces(); + clippingReport(); + } + + else if (!onTrack && *isOnTrack) { + debug(L"Now on track"); + onTrack = true; + setOnTrackStatus(onTrack); + RFshockDeflLast = LFshockDeflLast = + LRshockDeflLast = RRshockDeflLast = + CFshockDeflLast = -10000.0f; + clippedSamples = samples = lastGear = 0; + memset(yawFilter, 0, DIRECT_INTERP_SAMPLES * sizeof(float)); + irsdk_broadcastMsg(irsdk_BroadcastFFBCommand, irsdk_FFBCommand_MaxForce, (float)settings.getMaxForce()); + } + + if (*trackSurface != lastTrackSurface) { + debug(L"Track surface is now: %d", *trackSurface); + lastTrackSurface = *trackSurface; + } + + if (ffdevice && logiWheel) + logiRpmLed(rpm, redline); + + yaw = 0.0f; + + if (*speed > 2.0f) { + + float bumpsFactor = settings.getBumpsFactor(); + float sopFactor = settings.getSopFactor(); + float sopOffset = settings.getSopOffset(); + + bool use360 = settings.getUse360ForDirect(); + int ffbType = settings.getFfbType(); + + if (*speed > 5.0f) { + + float halfMaxForce = (float)(settings.getMaxForce() >> 1); + float r = *vY / *vX; + float sa, asa, ar = abs(r); + float reqSteer, uSteer; + + if (*vX < 0.0f) + r = -r; + + if (ar > 1.0f) { + sa = csignf(0.785f, r); + asa = 0.785f; + yaw = minf(maxf(sa * sopFactor, -halfMaxForce), halfMaxForce); + } + else { + sa = 0.78539816339745f * r + 0.273f * r * (1.0f - ar); + asa = abs(sa); + if (asa > sopOffset) { + sa -= csignf(sopOffset, sa); + yaw = + minf( + maxf( + sa * (2.0f - asa) * sopFactor, + -halfMaxForce + ), + halfMaxForce + ); + } + } + + if (settings.getUndersteerFactor() > 0.0f && settings.getUndersteerYawRateMult() > 0 && settings.getUndersteerlatAccelDiv() > 0) { + + reqSteer = abs((*yawRate * settings.getUndersteerYawRateMult()) / *speed + *latAccel / settings.getUndersteerlatAccelDiv()); + uSteer = minf(abs(*steer) - reqSteer - USTEER_MIN_OFFSET - settings.getUndersteerOffset(), 1.0f); + + if (uSteer > 0.0f) + yaw -= uSteer * settings.getUndersteerFactor() * USTEER_MULTIPLIER * *swTorque; + + } + + } + + if (LFshockDeflST != nullptr && RFshockDeflST != nullptr && bumpsFactor != 0.0f) + { + + if (LFshockDeflLast != -10000.0f) { + + if (ffbType != FFBTYPE_DIRECT_FILTER || use360) { + + __m128 xmm0 = _mm_loadu_ps(LFshockDeflST); + __m128 xmm1 = _mm_loadu_ps(RFshockDeflST); + __m128 xmm2 = _mm_load_ps(LFshockDeflST); + __m128 xmm3 = _mm_load_ps(RFshockDeflST); + xmm0 = (__m128)_mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(xmm0), 4)); + __m128 xmm4 = _mm_load_ss(&LFshockDeflLast); + xmm1 = (__m128)_mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(xmm1), 4)); + __m128 xmm5 = _mm_load_ss(&RFshockDeflLast); + xmm0 = _mm_move_ss(xmm0, xmm4); + xmm2 = _mm_sub_ps(xmm2, xmm0); + xmm1 = _mm_move_ss(xmm1, xmm5); + xmm3 = _mm_sub_ps(xmm3, xmm1); + xmm4 = _mm_loadu_ps((float*)LFshockDeflST + 12); + xmm1 = _mm_loadl_pi(xmm1, (const __m64*)LFshockDeflST + 16); + xmm1 = _mm_sub_ps(xmm1, xmm4); + xmm5 = _mm_loadu_ps((float*)RFshockDeflST + 12); + xmm0 = _mm_loadl_pi(xmm0, (const __m64*)RFshockDeflST + 16); + xmm0 = _mm_sub_ps(xmm0, xmm4); + xmm3 = _mm_load_ss(&bumpsFactor); + xmm1 = _mm_sub_ps(xmm1, xmm0); + xmm3 = _mm_unpacklo_ps(xmm3, xmm3); + xmm3 = _mm_unpacklo_ps(xmm3, xmm3); + xmm2 = _mm_mul_ps(xmm2, xmm3); + xmm1 = _mm_mul_ps(xmm1, xmm3); + _mm_store_ps((float*)suspForceST, xmm2); + _mm_storel_pi((__m64*)suspForceST + 16, xmm1); + } + else if (bumpsFactor != 0.0f) { + suspForce = + ( + (LFshockDeflST[STmaxIdx] - LFshockDeflLast) - + (RFshockDeflST[STmaxIdx] - RFshockDeflLast) + ) * bumpsFactor * 0.25f; + } + else { + suspForce = + ( + (LFshockDeflST[STmaxIdx] - LFshockDeflLast) - + (RFshockDeflST[STmaxIdx] - RFshockDeflLast) + * 0.25f); + } + + } + + RFshockDeflLast = RFshockDeflST[STmaxIdx]; + LFshockDeflLast = LFshockDeflST[STmaxIdx]; + + } + else if (CFshockDeflST != nullptr && bumpsFactor != 0.0f) { + + if (CFshockDeflLast != -10000.0f) { + + if (ffbType != FFBTYPE_DIRECT_FILTER || use360){ + + __m128 xmm1; + __m128 xmm0 = _mm_loadu_ps(CFshockDeflST); + __m128 xmm2 = _mm_load_ps(CFshockDeflST); + __m128 xmm3 = _mm_load_ss(&bumpsFactor); + xmm0 = (__m128)_mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(xmm0), 4)); + __m128 xmm4 = _mm_load_ss(&CFshockDeflLast); + xmm3 = _mm_unpacklo_ps(xmm3, xmm3); + xmm0 = _mm_move_ss(xmm0, xmm4); + xmm2 = _mm_sub_ps(xmm2, xmm0); + xmm4 = _mm_loadu_ps((float*)CFshockDeflST + 12); + xmm1 = _mm_loadl_pi(xmm1, (const __m64*)CFshockDeflST + 16); + xmm3 = _mm_unpacklo_ps(xmm3, xmm3); + xmm1 = _mm_sub_ps(xmm1, xmm4); + xmm2 = _mm_mul_ps(xmm2, xmm3); + xmm1 = _mm_mul_ps(xmm1, xmm3); + _mm_store_ps((float*)suspForceST, xmm2); + _mm_storel_pi((__m64*)suspForceST + 16, xmm1); + } + else if(bumpsFactor != 0.0f) + suspForce = (CFshockDeflST[STmaxIdx] - CFshockDeflLast) * bumpsFactor * 0.25f; + else + CFshockDeflLast = CFshockDeflST[STmaxIdx]; + + } + + CFshockDeflLast = CFshockDeflST[STmaxIdx]; + + } + + stopped = false; + + } + else + stopped = true; + + for (int i = 0; i < DIRECT_INTERP_SAMPLES; i++) { + + yawFilter[i] = yaw * firc6[i]; + + yawForce[i] = + yawFilter[0] + yawFilter[1] + yawFilter[2] + + yawFilter[3] + yawFilter[4] + yawFilter[5]; + + } + + halfSteerMax = *steerMax / 2.0f; + if (abs(halfSteerMax) < 8.0f && abs(*steer) > halfSteerMax - STOPS_MAXFORCE_RAD * 2.0f) + nearStops = true; + else + nearStops = false; + + if ( + !*isOnTrack || + settings.getFfbType() == FFBTYPE_DIRECT_FILTER || + settings.getFfbType() == FFBTYPE_DIRECT_FILTER_720 + ) + continue; + + // Bump stops + if (abs(halfSteerMax) < 8.0f && abs(*steer) > halfSteerMax) { + + float factor, invFactor; + + if (*steer > 0) { + factor = (-(*steer - halfSteerMax)) / STOPS_MAXFORCE_RAD; + factor = maxf(factor, -1.0f); + invFactor = 1.0f + factor; + } + else { + factor = (-(*steer + halfSteerMax)) / STOPS_MAXFORCE_RAD; + factor = minf(factor, 1.0f); + invFactor = 1.0f - factor; + } + + setFFB((int)(factor * DI_MAX + scaleTorque(*swTorque) * invFactor)); + continue; + + } + + // Telemetry FFB + switch (settings.getFfbType()) { + + case FFBTYPE_360HZ: { + + for (int i = 0; i < STmaxIdx; i++) { + setFFB(scaleTorque(swTorqueST[i] + suspForceST[i] + yawForce[i])); + sleepSpinUntil(&start, 2000, 2760 * (i + 1)); + //nanosleep(2760 * (i + 1)); + } + setFFB( + scaleTorque( + swTorqueST[STmaxIdx] + suspForceST[STmaxIdx] + yawForce[STmaxIdx] + ) + ); + + } + break; + + case FFBTYPE_360HZ_INTERP: { + + float diff = (swTorqueST[0] - lastTorque) / 2.0f; + float sdiff = (suspForceST[0] - lastSuspForce) / 2.0f; + int force, iMax = STmaxIdx << 1; + + setFFB( + scaleTorque( + lastTorque + diff + lastSuspForce + sdiff + yawForce[0] + ) + ); + + for (int i = 0; i < iMax; i++) { + + int idx = i >> 1; + + if (i & 1) { + diff = (swTorqueST[idx + 1] - swTorqueST[idx]) / 2.0f; + sdiff = (suspForceST[idx + 1] - suspForceST[idx]) / 2.0f; + force = + scaleTorque( + swTorqueST[idx] + diff + suspForceST[idx] + + sdiff + yawForce[idx] + ); + } + else + force = + scaleTorque( + swTorqueST[idx] + suspForceST[idx] + yawForce[idx] + ); + + //nanosleep(1380 * (i + 1)); + sleepSpinUntil(&start, 1000, 1380 * (i + 1)); + setFFB(force); + + } + + //nanosleep(1380 * (iMax + 1)); + sleepSpinUntil(&start, 1000, 1380 * (iMax + 1)); + setFFB( + scaleTorque( + swTorqueST[STmaxIdx] + suspForceST[STmaxIdx] + yawForce[STmaxIdx] + ) + ); + lastTorque = swTorqueST[STmaxIdx]; + lastSuspForce = suspForceST[STmaxIdx]; + + } + break; + + } + + + } + + // Did we lose iRacing? + if (numHandles > 0 && !(hdr->status & irsdk_stConnected)) { + debug(L"Disconnected from iRacing"); + numHandles = 0; + dataLen = 0; + if (data != NULL) { + free(data); + data = NULL; + } + resetForces(); + onTrack = false; + setOnTrackStatus(onTrack); + setConnectedStatus(false); + timeEndPeriod(1); + if (settings.getUseCarSpecific() && car[0] != 0) + settings.writeSettingsForCar(car); + } + + // Window messages + if (res == numHandles) { + + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) + DestroyWindow(mainWnd); + if (!IsDialogMessage(mainWnd, &msg)) { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + + } + + } + + return (int)msg.wParam; } -understeerCoefs *getCarUsteerCoeffs(char *car) { - - for (int i = 0; i < sizeof(usteerCoefs) / sizeof(usteerCoefs[0]); i++) - if (!strcmp(car, usteerCoefs[i].car)) { - debug(L"We have understeer coeffs for car %s", car); - return &usteerCoefs[i]; - } +ATOM MyRegisterClass(HINSTANCE hInstance) { - debug(L"No understeer coeffs for car %s", car); - return nullptr; + WNDCLASSEXW wcex; -} + wcex.cbSize = sizeof(WNDCLASSEX); -void clippingReport() { + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_IRFFB)); + wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_IRFFB); + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); - float clippedPerCent = samples > 0 ? (float)clippedSamples * 100.0f / samples : 0.0f; - text(L"%.02f%% of samples were clipped", clippedPerCent); - if (clippedPerCent > 2.5f) - text(L"Consider increasing max force to reduce clipping"); - samples = clippedSamples = 0; + return RegisterClassExW(&wcex); } -void logiRpmLed(float *rpm, float redline) { - - logiLedData.rpmData.rpm = *rpm / (redline * 0.90f); - logiLedData.rpmData.rpmFirstLed = 0.65f; - logiLedData.rpmData.rpmRedLine = 1.0f; +LRESULT CALLBACK EditWndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR subId, DWORD_PTR rData) { - ffdevice->Escape(&logiEscape); + if (msg == WM_CHAR) { -} + wchar_t buf[8]; -void deviceChange() { + if (subId == EDIT_FLOAT) { - debug(L"Device change notification"); - if (!onTrack) { - debug(L"Not on track, processing device change"); - deviceChangePending = false; - enumDirectInput(); - if (!settings.isFfbDevicePresent()) - releaseDirectInput(); - } - else { - debug(L"Deferring device change processing whilst on track"); - deviceChangePending = true; - } + if (GetWindowTextW(wnd, buf, 8) && StrChrIW(buf, L'.') && wParam == '.') + return 0; -} + if ( + !( + (wParam >= L'0' && wParam <= L'9') || + wParam == L'.' || + wParam == VK_RETURN || + wParam == VK_DELETE || + wParam == VK_BACK + ) + ) + return 0; -DWORD getDeviceVidPid(LPDIRECTINPUTDEVICE8 dev) { + LRESULT ret = DefSubclassProc(wnd, msg, wParam, lParam); - DIPROPDWORD dipdw; - dipdw.diph.dwSize = sizeof(DIPROPDWORD); - dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; + wchar_t* end; + float val = 0.0f; - if (dev == nullptr) - return 0; + GetWindowText(wnd, buf, 8); + val = wcstof(buf, &end); + if (end - buf == wcslen(buf)) + SendMessage(GetParent(wnd), WM_EDIT_VALUE, reinterpret_cast(val), (LPARAM)wnd); - if (!SUCCEEDED(dev->GetProperty(DIPROP_VIDPID, &dipdw.diph))) - return 0; + return ret; - return dipdw.dwData; + } + else { -} + if ( + !( + (wParam >= L'0' && wParam <= L'9') || + wParam == VK_RETURN || + wParam == VK_DELETE || + wParam == VK_BACK + ) + ) + return 0; -void minimise() { - debug(L"Minimising window"); - Shell_NotifyIcon(NIM_ADD, &niData); - ShowWindow(mainWnd, SW_HIDE); -} + LRESULT ret = DefSubclassProc(wnd, msg, wParam, lParam); + GetWindowText(wnd, buf, 8); + int val = _wtoi(buf); + SendMessage(GetParent(wnd), WM_EDIT_VALUE, (WPARAM)val, (LPARAM)wnd); + return ret; -void restore() { - debug(L"Restoring window"); - Shell_NotifyIcon(NIM_DELETE, &niData); - ShowWindow(mainWnd, SW_SHOW); - BringWindowToTop(mainWnd); -} + } -int APIENTRY wWinMain( - _In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ LPWSTR lpCmdLine, - _In_ int nCmdShow -) { + } - UNREFERENCED_PARAMETER(hPrevInstance); - - if (StrStrW(lpCmdLine, CMDLINE_HGSVC)) { - - SERVICE_TABLE_ENTRYW SvcDispatchTable[] = { - { SVCNAME, (LPSERVICE_MAIN_FUNCTION)HidGuardian::SvcMain }, - { NULL, NULL } - }; - - if (!StartServiceCtrlDispatcherW(SvcDispatchTable)) { - HidGuardian::svcReportError(L"Failed to start service ctrl dispatcher"); - exit(1); - } - - exit(0); - - } - - globalMutex = CreateMutex(NULL, false, L"Global\\irFFB_Mutex"); - - if (GetLastError() == ERROR_ALREADY_EXISTS) - exit(0); - - INITCOMMONCONTROLSEX ccEx; - - HANDLE handles[1]; - char *data = nullptr; - bool irConnected = false; - MSG msg; - - float *swTorque = nullptr, *swTorqueST = nullptr, *steer = nullptr, *steerMax = nullptr; - float *speed = nullptr, *throttle = nullptr, *rpm = nullptr; - float *LFshockDeflST = nullptr, *RFshockDeflST = nullptr, *CFshockDeflST = nullptr; - float *LRshockDeflST = nullptr, *RRshockDeflST = nullptr; - float *vX = nullptr, *vY = nullptr; - float *latAccel = nullptr, *yawRate = nullptr; - float LFshockDeflLast = -10000, RFshockDeflLast = -10000, CFshockDeflLast = -10000; - float LRshockDeflLast = -10000, RRshockDeflLast = -10000; - bool *isOnTrack = nullptr; - int *trackSurface = nullptr, *gear = nullptr; - - bool inGarage = false; - int numHandles = 0, dataLen = 0, lastGear = 0; - int STnumSamples = 0, STmaxIdx = 0, lastTrackSurface = -1; - float halfSteerMax = 0, lastTorque = 0, lastSuspForce = 0, redline; - float yaw = 0.0f, yawFilter[DIRECT_INTERP_SAMPLES]; - - understeerCoefs *usCoefs; - - ccEx.dwICC = ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_STANDARD_CLASSES; - ccEx.dwSize = sizeof(ccEx); - InitCommonControlsEx(&ccEx); - - HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_IRFFB)); - - LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); - LoadStringW(hInstance, IDC_IRFFB, szWindowClass, MAX_LOADSTRING); - MyRegisterClass(hInstance); - - // Setup DI FFB effect - pforce.dwMagnitude = 0; - pforce.dwPeriod = INFINITE; - pforce.dwPhase = 0; - pforce.lOffset = 0; - - ZeroMemory(&dieff, sizeof(dieff)); - dieff.dwSize = sizeof(DIEFFECT); - dieff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - dieff.dwDuration = INFINITE; - dieff.dwSamplePeriod = 0; - dieff.dwGain = DI_FFNOMINALMAX; - dieff.dwTriggerButton = DIEB_NOTRIGGER; - dieff.dwTriggerRepeatInterval = 0; - dieff.cAxes = 1; - dieff.rgdwAxes = axes; - dieff.rglDirection = dir; - dieff.lpEnvelope = NULL; - dieff.cbTypeSpecificParams = sizeof(DIPERIODIC); - dieff.lpvTypeSpecificParams = &pforce; - dieff.dwStartDelay = 0; - - ZeroMemory(&logiLedData, sizeof(logiLedData)); - logiLedData.size = sizeof(logiLedData); - logiLedData.version = 1; - ZeroMemory(&logiEscape, sizeof(logiEscape)); - logiEscape.dwSize = sizeof(DIEFFESCAPE); - logiEscape.dwCommand = 0; - logiEscape.lpvInBuffer = &logiLedData; - logiEscape.cbInBuffer = sizeof(logiLedData); - - InitializeCriticalSection(&effectCrit); - - if (!InitInstance(hInstance, nCmdShow)) - return FALSE; - - hidGuardian = HidGuardian::init(GetCurrentProcessId()); - if (StrStrW(lpCmdLine, CMDLINE_HGINST)) - hidGuardian->install(); - else if (StrStrW(lpCmdLine, CMDLINE_HGREPAIR)) - hidGuardian->repairService(); - - fan = Fan::init(); - jetseat = JetSeat::init(); - if (!jetseat) { - DeleteMenu(GetMenu(mainWnd), ID_SETTINGS_JETSEAT, MF_BYCOMMAND); - DrawMenuBar(mainWnd); - } - - memset(car, 0, sizeof(car)); - setCarStatus(car); - setConnectedStatus(false); - setOnTrackStatus(false); - settings.readGenericSettings(); - settings.readRegSettings(car); - - if (settings.getStartMinimised()) - minimise(); - else - restore(); - - enumDirectInput(); - - LARGE_INTEGER start; - QueryPerformanceFrequency(&freq); - - initVJD(); - SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); - - SetThreadPriority( - CreateThread(NULL, 0, readWheelThread, NULL, 0, NULL), THREAD_PRIORITY_HIGHEST - ); - SetThreadPriority( - CreateThread(NULL, 0, directFFBThread, NULL, 0, NULL), THREAD_PRIORITY_HIGHEST - ); - - debug(L"Init complete, entering mainloop"); - - while (TRUE) { - - DWORD res; - const irsdk_header *hdr = NULL; - - if ( - irsdk_startup() && (hdr = irsdk_getHeader()) && - hdr->status & irsdk_stConnected && hdr->bufLen != dataLen && hdr->bufLen != 0 - ) { - - debug(L"New iRacing session"); - - handles[0] = hDataValidEvent; - numHandles = 1; - - if (data != NULL) - free(data); - - dataLen = irsdk_getHeader()->bufLen; - data = (char *)malloc(dataLen); - setConnectedStatus(true); - - if (getCarName() && settings.getUseCarSpecific()) { - setCarStatus(car); - settings.readSettingsForCar(car); - } - else - setCarStatus(nullptr); - - redline = getCarRedline(); - debug(L"Redline is %d rpm", (int)redline); - - usCoefs = getCarUsteerCoeffs(car); - EnableWindow(settings.getUndersteerWnd()->trackbar, usCoefs != nullptr); - EnableWindow(settings.getUndersteerWnd()->value, usCoefs != nullptr); - EnableWindow(settings.getUndersteerOffsetWnd()->trackbar, usCoefs != nullptr); - EnableWindow(settings.getUndersteerOffsetWnd()->value, usCoefs != nullptr); - - // Inform iRacing of the maxForce setting - irsdk_broadcastMsg(irsdk_BroadcastFFBCommand, irsdk_FFBCommand_MaxForce, (float)settings.getMaxForce()); - - swTorque = floatvarptr(data, "SteeringWheelTorque"); - swTorqueST = floatvarptr(data, "SteeringWheelTorque_ST"); - steer = floatvarptr(data, "SteeringWheelAngle"); - steerMax = floatvarptr(data, "SteeringWheelAngleMax"); - speed = floatvarptr(data, "Speed"); - throttle = floatvarptr(data, "Throttle"); - rpm = floatvarptr(data, "RPM"); - gear = intvarptr(data, "Gear"); - isOnTrack = boolvarptr(data, "IsOnTrack"); - - trackSurface = intvarptr(data, "PlayerTrackSurface"); - vX = floatvarptr(data, "VelocityX"); - vY = floatvarptr(data, "VelocityY"); - - latAccel = floatvarptr(data, "LatAccel"); - yawRate = floatvarptr(data, "YawRate"); - - RFshockDeflST = floatvarptr(data, "RFshockDefl_ST"); - LFshockDeflST = floatvarptr(data, "LFshockDefl_ST"); - LRshockDeflST = floatvarptr(data, "LRshockDefl_ST"); - RRshockDeflST = floatvarptr(data, "RRshockDefl_ST"); - CFshockDeflST = floatvarptr(data, "CFshockDefl_ST"); - - int swTorqueSTidx = irsdk_varNameToIndex("SteeringWheelTorque_ST"); - STnumSamples = irsdk_getVarHeaderEntry(swTorqueSTidx)->count; - STmaxIdx = STnumSamples - 1; - - lastTorque = 0.0f; - onTrack = false; - resetForces(); - irConnected = true; - timeBeginPeriod(1); - - } - - res = MsgWaitForMultipleObjects(numHandles, handles, FALSE, 1000, QS_ALLINPUT); - - QueryPerformanceCounter(&start); - - if (numHandles > 0 && res == numHandles - 1 && irsdk_getNewData(data)) { - - if (onTrack && !*isOnTrack) { - debug(L"No longer on track"); - onTrack = false; - setOnTrackStatus(onTrack); - lastTorque = lastSuspForce = 0.0f; - resetForces(); - fan->setManualSpeed(); - clippingReport(); - } - - else if (!onTrack && *isOnTrack) { - debug(L"Now on track"); - onTrack = true; - setOnTrackStatus(onTrack); - RFshockDeflLast = LFshockDeflLast = - LRshockDeflLast = RRshockDeflLast = - CFshockDeflLast = -10000.0f; - clippedSamples = samples = lastGear = 0; - memset(yawFilter, 0, DIRECT_INTERP_SAMPLES * sizeof(float)); - } - - if (*trackSurface != lastTrackSurface) { - debug(L"Track surface is now: %d", *trackSurface); - lastTrackSurface = *trackSurface; - } - - if (jetseat && jetseat->isEnabled()) { - if (*isOnTrack && *rpm > 0.0f) { - jetseat->startEngineEffect(); - jetseat->updateEngineEffect(*rpm * 100.0f / redline); - } - else - jetseat->stopEngineEffect(); - } - - if (ffdevice && logiWheel) - logiRpmLed(rpm, redline); - - yaw = 0.0f; - - if (*speed > 2.0f) { - - float bumpsFactor = settings.getBumpsFactor(); - float sopFactor = settings.getSopFactor(); - float sopOffset = settings.getSopOffset(); - - bool use360 = settings.getUse360ForDirect(); - int ffbType = settings.getFfbType(); - - if (*speed > 5.0f) { - - float halfMaxForce = (float)(settings.getMaxForce() >> 1); - float r = *vY / *vX; - float sa, asa, ar = abs(r); - float reqSteer, uSteer; - - if (*vX < 0.0f) - r = -r; - - if (ar > 1.0f) { - sa = csignf(0.785f, r); - asa = 0.785f; - yaw = minf(maxf(sa * sopFactor, -halfMaxForce), halfMaxForce); - } - else { - sa = 0.78539816339745f * r + 0.273f * r * (1.0f - ar); - asa = abs(sa); - if (asa > sopOffset) { - sa -= csignf(sopOffset, sa); - yaw = - minf( - maxf( - sa * (2.0f - asa) * sopFactor, - -halfMaxForce - ), - halfMaxForce - ); - } - } - - if (jetseat && jetseat->isEnabled() && asa > sopOffset) - jetseat->yawEffect(sa); - - if (usCoefs != nullptr && settings.getUndersteerFactor() > 0.0f) { - - reqSteer = abs((*yawRate * usCoefs->yawRateMult) / *speed + *latAccel / usCoefs->latAccelDiv); - uSteer = minf(abs(*steer) - reqSteer - USTEER_MIN_OFFSET - settings.getUndersteerOffset(), 1.0f); - - if (uSteer > 0.0f) - yaw -= uSteer * settings.getUndersteerFactor() * USTEER_MULTIPLIER * *swTorque; - - } - - } - - if ( - LFshockDeflST != nullptr && RFshockDeflST != nullptr && bumpsFactor != 0.0f - ) { - - if (LFshockDeflLast != -10000.0f) { - - if (ffbType != FFBTYPE_DIRECT_FILTER || use360) { - - __asm { - mov eax, LFshockDeflST - mov ecx, RFshockDeflST - movups xmm0, xmmword ptr [eax] - movups xmm1, xmmword ptr [ecx] - // xmm2 = LFdefl[0,1,2,3] - movaps xmm2, xmm0 - // xmm3 = RFdefl[0,1,2,3] - movaps xmm3, xmm1 - // xmm0 = LFdefl[-,0,1,2] - pslldq xmm0, 4 - movss xmm4, LFshockDeflLast - // xmm1 = RFdefl[-,0,1,2] - pslldq xmm1, 4 - movss xmm5, RFshockDeflLast - // xmm0 = LFdefl[LFlast,0,1,2] - movss xmm0, xmm4 - // xmm6 = LFdefl[0,1,2,3] - movaps xmm6, xmm2 - // xmm2 = LFdefl[0] - LFlast, LFdefl[1] - LFdefl[0], ... - subps xmm2, xmm0 - // xmm1 = RFdefl[RFlast,0,1,2] - movss xmm1, xmm5 - // xmm7 = RFdefl[0,1,2,3] - movaps xmm7, xmm3 - // xmm3 = RFdefl[0] - RFlast, RFdefl[1] - RFdefl[0], ... - subps xmm3, xmm1 - // xmm4 = LFdefl[3,4,5] - movups xmm4, xmmword ptr [eax + 12] - // xmm1 = LFdefl[4,5] - movlps xmm1, qword ptr [eax + 16] - // xmm1 = LFdefl[4] - LFdefl[3], LFdefl[5] - LFdefl[4] - subps xmm1, xmm4 - // xmm5 = RFdefl[3,4,5] - movups xmm5, xmmword ptr [ecx + 12] - // xmm0 = RFdefl[4,5] - movlps xmm0, qword ptr [ecx + 16] - // xmm2 = delta[0,1,2,3] - subps xmm2, xmm3 - // xmm0 = RFdefl[4] - RFdefl[3], RFdefl[5] - RFdefl[4] - subps xmm0, xmm5 - // xmm3 = susTexFactor - movss xmm3, bumpsFactor - // xmm1 = delta[4,5] - subps xmm1, xmm0 - unpcklps xmm3, xmm3 - unpcklps xmm3, xmm3 - // xmm2 = delta[0,1,2,3] * bumpsFactor - mulps xmm2, xmm3 - // xmm1 = delta[4,5] * bumpsFactor - mulps xmm1, xmm3 - // write - movaps xmmword ptr suspForceST[0], xmm2 - movlps qword ptr suspForceST[16], xmm1 - } - - } - else { - suspForce = - ( - (LFshockDeflST[STmaxIdx] - LFshockDeflLast) - - (RFshockDeflST[STmaxIdx] - RFshockDeflLast) - ) * bumpsFactor * 0.25f; - } - - if (jetseat && jetseat->isEnabled()) { - float LFd = LFshockDeflST[STmaxIdx] - LFshockDeflLast; - float RFd = RFshockDeflST[STmaxIdx] - RFshockDeflLast; - - if (LFd > 0.0025f || RFd > 0.0025f) - jetseat->fBumpEffect(LFd * 220.0f, RFd * 220.0f); - } - - } - - RFshockDeflLast = RFshockDeflST[STmaxIdx]; - LFshockDeflLast = LFshockDeflST[STmaxIdx]; - - } - else if (CFshockDeflST != nullptr && bumpsFactor != 0) { - - if (CFshockDeflLast != -10000.0f) { - - if (ffbType != FFBTYPE_DIRECT_FILTER || use360) - __asm { - mov eax, CFshockDeflST - movups xmm0, xmmword ptr[eax] - // xmm3 = bumpsFactor - movss xmm3, bumpsFactor - // xmm2 = CFdefl[0,1,2,3] - movaps xmm2, xmm0 - // xmm0 = CFdefl[-,1,2,3] - pslldq xmm0, 4 - movss xmm4, CFshockDeflLast - unpcklps xmm3, xmm3 - // xmm0 = CFdefl[CFlast,0,1,2] - movss xmm0, xmm4 - // xmm2 = CFdefl[0] - CFlast, CFdefl[1] - CFdefl[0], ... - subps xmm2, xmm0 - // xmm4 = CFdefl[3,4,5] - movups xmm4, xmmword ptr[eax + 12] - // xmm1 = CFdefl[4,5] - movlps xmm1, qword ptr[eax + 16] - unpcklps xmm3, xmm3 - // xmm1 = CFdefl[4] - CFdefl[3], CFdefl[5] - CFdefl[4] - subps xmm1, xmm4 - mulps xmm2, xmm3 - mulps xmm1, xmm3 - movaps xmmword ptr suspForceST[0], xmm2 - movlps qword ptr suspForceST[16], xmm1 - } - else - suspForce = (CFshockDeflST[STmaxIdx] - CFshockDeflLast) * bumpsFactor * 0.25f; - - if (jetseat && jetseat->isEnabled()) { - float CFd = CFshockDeflST[STmaxIdx] - CFshockDeflLast; - if (CFd > 0.0025f) - jetseat->fBumpEffect(CFd * 220.0f, CFd * 220.0f); - } - - } - - CFshockDeflLast = CFshockDeflST[STmaxIdx]; - - } - - if (jetseat && jetseat->isEnabled() && LRshockDeflST != nullptr) { - float LRd = LRshockDeflST[STmaxIdx] - LRshockDeflLast; - float RRd = RRshockDeflST[STmaxIdx] - RRshockDeflLast; - - if (LRd > 0.0025f || RRd > 0.0025f) - jetseat->rBumpEffect(LRd * 220.0f, RRd * 220.0f); - - LRshockDeflLast = LRshockDeflST[STmaxIdx]; - RRshockDeflLast = RRshockDeflST[STmaxIdx]; - } - - stopped = false; - - } - else - stopped = true; - - if (*isOnTrack) - fan->setSpeed(*speed); - - if (jetseat && jetseat->isEnabled() && *gear != lastGear) { - jetseat->gearEffect(); - lastGear = *gear; - } - - for (int i = 0; i < DIRECT_INTERP_SAMPLES; i++) { - - yawFilter[i] = yaw * firc6[i]; - - yawForce[i] = - yawFilter[0] + yawFilter[1] + yawFilter[2] + - yawFilter[3] + yawFilter[4] + yawFilter[5]; - - } - - halfSteerMax = *steerMax / 2.0f; - if (abs(halfSteerMax) < 8.0f && abs(*steer) > halfSteerMax - STOPS_MAXFORCE_RAD * 2.0f) - nearStops = true; - else - nearStops = false; - - if ( - !*isOnTrack || - settings.getFfbType() == FFBTYPE_DIRECT_FILTER || - settings.getFfbType() == FFBTYPE_DIRECT_FILTER_720 - ) - continue; - - // Bump stops - if (abs(halfSteerMax) < 8.0f && abs(*steer) > halfSteerMax) { - - float factor, invFactor; - - if (*steer > 0) { - factor = (-(*steer - halfSteerMax)) / STOPS_MAXFORCE_RAD; - factor = maxf(factor, -1.0f); - invFactor = 1.0f + factor; - } - else { - factor = (-(*steer + halfSteerMax)) / STOPS_MAXFORCE_RAD; - factor = minf(factor, 1.0f); - invFactor = 1.0f - factor; - } - - setFFB((int)(factor * DI_MAX + scaleTorque(*swTorque) * invFactor)); - continue; - - } - - // Telemetry FFB - switch (settings.getFfbType()) { - - case FFBTYPE_360HZ: { - - for (int i = 0; i < STmaxIdx; i++) { - setFFB(scaleTorque(swTorqueST[i] + suspForceST[i] + yawForce[i])); - sleepSpinUntil(&start, 2000, 2760 * (i + 1)); - } - setFFB( - scaleTorque( - swTorqueST[STmaxIdx] + suspForceST[STmaxIdx] + yawForce[STmaxIdx] - ) - ); - - } - break; - - case FFBTYPE_360HZ_INTERP: { - - float diff = (swTorqueST[0] - lastTorque) / 2.0f; - float sdiff = (suspForceST[0] - lastSuspForce) / 2.0f; - int force, iMax = STmaxIdx << 1; - - setFFB( - scaleTorque( - lastTorque + diff + lastSuspForce + sdiff + yawForce[0] - ) - ); - - for (int i = 0; i < iMax; i++) { - - int idx = i >> 1; - - if (i & 1) { - diff = (swTorqueST[idx + 1] - swTorqueST[idx]) / 2.0f; - sdiff = (suspForceST[idx + 1] - suspForceST[idx]) / 2.0f; - force = - scaleTorque( - swTorqueST[idx] + diff + suspForceST[idx] + - sdiff + yawForce[idx] - ); - } - else - force = - scaleTorque( - swTorqueST[idx] + suspForceST[idx] + yawForce[idx] - ); - - sleepSpinUntil(&start, 0, 1380 * (i + 1)); - setFFB(force); - - } - - sleepSpinUntil(&start, 0, 1380 * (iMax + 1)); - setFFB( - scaleTorque( - swTorqueST[STmaxIdx] + suspForceST[STmaxIdx] + yawForce[STmaxIdx] - ) - ); - lastTorque = swTorqueST[STmaxIdx]; - lastSuspForce = suspForceST[STmaxIdx]; - - } - break; - - } - - - } - - // Did we lose iRacing? - if (numHandles > 0 && !(hdr->status & irsdk_stConnected)) { - debug(L"Disconnected from iRacing"); - numHandles = 0; - dataLen = 0; - if (data != NULL) { - free(data); - data = NULL; - } - resetForces(); - onTrack = false; - setOnTrackStatus(onTrack); - setConnectedStatus(false); - fan->setManualSpeed(); - timeEndPeriod(1); - if (settings.getUseCarSpecific() && car[0] != 0) - settings.writeSettingsForCar(car); - } - - // Window messages - if (res == numHandles) { - - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_QUIT) - DestroyWindow(mainWnd); - if (!IsDialogMessage(mainWnd, &msg)) { - if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - } - - } - - } - - return (int)msg.wParam; + return DefSubclassProc(wnd, msg, wParam, lParam); } +bool CALLBACK SetFont(HWND child, LPARAM font) { + SendMessage(child, WM_SETFONT, font, true); + return true; +} -ATOM MyRegisterClass(HINSTANCE hInstance) { - - WNDCLASSEXW wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_IRFFB)); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_IRFFB); - wcex.lpszClassName = szWindowClass; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); +HWND combo(HWND parent, wchar_t* name, int x, int y) { - return RegisterClassExW(&wcex); + CreateWindowW( + L"STATIC", name, + WS_CHILD | WS_VISIBLE, + x, y, 300, 20, parent, NULL, hInst, NULL + ); + return + CreateWindow( + L"COMBOBOX", nullptr, + CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | WS_TABSTOP, + x, y + 20, 265, 240, parent, nullptr, hInst, nullptr + ); } -LRESULT CALLBACK EditWndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR subId, DWORD_PTR rData) { +sWins_t* slider(HWND parent, wchar_t* name, int x, int y, wchar_t* start, wchar_t* end, bool floatData) { - if (msg == WM_CHAR) { + sWins_t* wins = (sWins_t*)malloc(sizeof(sWins_t)); - wchar_t buf[8]; + wins->label = CreateWindowW( + L"STATIC", name, + WS_CHILD | WS_VISIBLE, + x, y, 100, 14, parent, NULL, hInst, NULL + ); - if (subId == EDIT_FLOAT) { + wins->value = CreateWindowW( + L"EDIT", L"", + WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | ES_CENTER, + x + 220, y, 45, 18, parent, NULL, hInst, NULL + ); - if (GetWindowTextW(wnd, buf, 8) && StrChrIW(buf, L'.') && wParam == '.') - return 0; + SetWindowSubclass(wins->value, EditWndProc, floatData ? 1 : 0, 0); - if ( - !( - (wParam >= L'0' && wParam <= L'9') || - wParam == L'.' || - wParam == VK_RETURN || - wParam == VK_DELETE || - wParam == VK_BACK - ) - ) - return 0; + SendMessage(wins->value, EM_SETLIMITTEXT, 5, 0); - LRESULT ret = DefSubclassProc(wnd, msg, wParam, lParam); + wins->trackbar = CreateWindowExW( + 0, TRACKBAR_CLASS, name, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_TOOLTIPS | TBS_TRANSPARENTBKGND, + x + 40, y + 18, 170, 20, + parent, NULL, hInst, NULL + ); - wchar_t *end; - float val = 0.0f; + wins->min = std::stof(start); + wins->max = std::stof(end); - GetWindowText(wnd, buf, 8); - val = wcstof(buf, &end); - if (end - buf == wcslen(buf)) - SendMessage(GetParent(wnd), WM_EDIT_VALUE, reinterpret_cast(val), (LPARAM)wnd); + SendMessage(wins->trackbar, TBM_SETRANGE, (WPARAM)TRUE, MAKELONG(std::stof(start), std::stof(end))); - return ret; + HWND buddyLeft = CreateWindowEx( + 0, L"STATIC", start, + SS_LEFT | WS_CHILD | WS_VISIBLE, + 0, 0, 40, 15, parent, NULL, hInst, NULL + ); + SendMessage(wins->trackbar, TBM_SETBUDDY, (WPARAM)TRUE, (LPARAM)buddyLeft); - } - else { + HWND buddyRight = CreateWindowEx( + 0, L"STATIC", end, + SS_RIGHT | WS_CHILD | WS_VISIBLE, + 0, 0, 52, 15, parent, NULL, hInst, NULL + ); + SendMessage(wins->trackbar, TBM_SETBUDDY, (WPARAM)FALSE, (LPARAM)buddyRight); - if ( - !( - (wParam >= L'0' && wParam <= L'9') || - wParam == VK_RETURN || - wParam == VK_DELETE || - wParam == VK_BACK - ) - ) - return 0; + return wins; - LRESULT ret = DefSubclassProc(wnd, msg, wParam, lParam); - GetWindowText(wnd, buf, 8); - int val = _wtoi(buf); - SendMessage(GetParent(wnd), WM_EDIT_VALUE, (WPARAM)val, (LPARAM)wnd); - return ret; +} - } +HWND slider(HWND parent, wchar_t* name, int x, int y, int width, int height, int start, int end) { - } + HWND slider = CreateWindowExW( + 0, TRACKBAR_CLASS, name, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_TOOLTIPS | TBS_TRANSPARENTBKGND | TBS_NOTICKS, + x, y, width, height, + parent, NULL, hInst, NULL + ); - return DefSubclassProc(wnd, msg, wParam, lParam); + SendMessage(slider, TBM_SETRANGE, (WPARAM)TRUE, MAKELONG(start, end)); + return slider; } -HWND combo(HWND parent, wchar_t *name, int x, int y) { +HWND checkbox(HWND parent, wchar_t* name, int x, int y, int width = 360, int height = 20) { - CreateWindowW( - L"STATIC", name, - WS_CHILD | WS_VISIBLE, - x, y, 300, 20, parent, NULL, hInst, NULL - ); - return - CreateWindow( - L"COMBOBOX", nullptr, - CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | WS_TABSTOP, - x + 12, y + 26, 300, 240, parent, nullptr, hInst, nullptr - ); + HWND whd = CreateWindowEx( + 0, L"BUTTON", name, + BS_CHECKBOX | BS_MULTILINE | WS_CHILD | WS_TABSTOP | WS_VISIBLE, + x, y, width, height, parent, nullptr, hInst, nullptr + ); + return whd; } -sWins_t *slider(HWND parent, wchar_t *name, int x, int y, wchar_t *start, wchar_t *end, bool floatData) { - - sWins_t *wins = (sWins_t *)malloc(sizeof(sWins_t)); +HWND groupox(HWND parent, wchar_t* name, int x, int y, int width, int height) { - wins->label = CreateWindowW( - L"STATIC", name, - WS_CHILD | WS_VISIBLE, - x, y, 300, 20, parent, NULL, hInst, NULL - ); + return + CreateWindowEx( + 0, L"BUTTON", name, + BS_GROUPBOX | BS_MULTILINE | WS_CHILD | WS_TABSTOP | WS_VISIBLE, + x, y, width, height, parent, nullptr, hInst, nullptr + ); - wins->value = CreateWindowW( - L"EDIT", L"", - WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | ES_CENTER, - x + 210, y, 50, 20, parent, NULL, hInst, NULL - ); +} - SetWindowSubclass(wins->value, EditWndProc, floatData ? 1 : 0, 0); +HWND progressbar(HWND parent, wchar_t* name, int x, int y, int width, int height, int max) +{ + + if (name != nullptr) + CreateWindowW( + L"STATIC", name, + WS_CHILD | WS_VISIBLE, + x, y, width, 20, parent, NULL, hInst, NULL + ); + + HWND hWnd = ::CreateWindowEx( + 0, + PROGRESS_CLASS, + name, + WS_CHILD | WS_VISIBLE | PBS_SMOOTH, + x, + name == nullptr ? y : y + 20, + width, + height, + parent, + (HMENU)ID_SMOOTHPROGRESSCTRL, + hInst, + NULL); + ::SendMessage(hWnd, PBM_SETRANGE32, 0, (WPARAM)(INT)max); + + return hWnd; +} - SendMessage(wins->value, EM_SETLIMITTEXT, 5, 0); +void ActivateOverLayWindow() +{ + if (windowInitialExtendedState == NULL) + { + windowInitialExtendedState = GetWindowLongPtr(overlayWnd, GWL_EXSTYLE); + } + SetWindowPos(overlayWnd, NULL, settings.getWindowPosX(), settings.getWindowPosY(), 200, OVERLAY_WINDOW_HEIGHT, SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOACTIVATE); + ShowWindow(settings.getOverlayMaxForceWnd(), SW_SHOW); + SetWindowLongPtr(overlayWnd, GWL_EXSTYLE, windowInitialExtendedState ^ WS_EX_LAYERED); +} - wins->trackbar = CreateWindowExW( - 0, TRACKBAR_CLASS, name, - WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_TOOLTIPS | TBS_TRANSPARENTBKGND, - x + 40, y + 26, 240, 30, - parent, NULL, hInst, NULL - ); +void DeActivateOverlayWindow() +{ + if (windowInitialExtendedState == NULL) + { + windowInitialExtendedState = GetWindowLongPtr(overlayWnd, (int)GWL_EXSTYLE); + } + SetWindowLongPtr(overlayWnd, GWL_EXSTYLE, windowInitialExtendedState); + ShowWindow(settings.getOverlayMaxForceWnd(), SW_HIDE); + SetWindowPos(overlayWnd, NULL, settings.getWindowPosX(), settings.getWindowPosY(), 200, OVERLAY_WINDOW_HEIGHT - 20, SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOACTIVATE); + SetLayeredWindowAttributes(overlayWnd, 0, settings.getOverlayTransparency(), LWA_ALPHA); +} - HWND buddyLeft = CreateWindowEx( - 0, L"STATIC", start, - SS_LEFT | WS_CHILD | WS_VISIBLE, - 0, 0, 40, 20, parent, NULL, hInst, NULL - ); - SendMessage(wins->trackbar, TBM_SETBUDDY, (WPARAM)TRUE, (LPARAM)buddyLeft); +void CreateOverlayWindow(HINSTANCE hInstance) +{ - HWND buddyRight = CreateWindowEx( - 0, L"STATIC", end, - SS_RIGHT | WS_CHILD | WS_VISIBLE, - 0, 0, 52, 20, parent, NULL, hInst, NULL - ); - SendMessage(wins->trackbar, TBM_SETBUDDY, (WPARAM)FALSE, (LPARAM)buddyRight); + DWORD extendedStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TOPMOST; + overlayWnd = CreateWindowExW(extendedStyle, + szWindowClass, L"irFFb Overlay", + WS_VISIBLE | WS_POPUP, + //WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME, + CW_USEDEFAULT, CW_USEDEFAULT, 200, OVERLAY_WINDOW_HEIGHT, + NULL, NULL, hInst, NULL + ); - return wins; + currentForceOverlayWnd = progressbar(overlayWnd, nullptr, 3, 3, 150, 15, IR_MAX); + clippingForceOverlayWnd = progressbar(overlayWnd, nullptr, 150, 3, 46, 15, progressClippingMax); -} + settings.setOverlayMaxForceWnd(slider(overlayWnd, L"max force", 4, 22, 192, 15, 5, 65)); + SendMessage(clippingForceOverlayWnd, PBM_SETSTATE, PBST_ERROR, 0); -HWND checkbox(HWND parent, wchar_t *name, int x, int y) { - - return - CreateWindowEx( - 0, L"BUTTON", name, - BS_CHECKBOX | BS_MULTILINE | WS_CHILD | WS_TABSTOP | WS_VISIBLE, - x, y, 360, 58, parent, nullptr, hInst, nullptr - ); + SetWindowSubclass(currentForceOverlayWnd, myNcHitTest, 0, 0); + SetWindowSubclass(clippingForceOverlayWnd, myNcHitTest, 0, 0); + SetWindowSubclass(overlayWnd, myPaint, 0, 0); + SetLayeredWindowAttributes(overlayWnd, 0, 255, LWA_ALPHA); + SetMenu(overlayWnd, NULL); + ShowWindow(overlayWnd, SW_HIDE); + UpdateWindow(overlayWnd); } + BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { - DEV_BROADCAST_DEVICEINTERFACE devFilter; - - hInst = hInstance; - - mainWnd = CreateWindowW( - szWindowClass, szTitle, - WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME, - CW_USEDEFAULT, CW_USEDEFAULT, 864, 720, - NULL, NULL, hInst, NULL - ); - - if (!mainWnd) - return FALSE; - - memset(&niData, 0, sizeof(niData)); - niData.uVersion = NOTIFYICON_VERSION; - niData.cbSize = NOTIFYICONDATA_V1_SIZE; - niData.hWnd = mainWnd; - niData.uID = 1; - niData.uFlags = NIF_ICON | NIF_MESSAGE; - niData.uCallbackMessage = WM_TRAY_ICON; - niData.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_SMALL)); - - settings.setDevWnd(combo(mainWnd, L"FFB device:", 44, 20)); - settings.setFfbWnd(combo(mainWnd, L"FFB type:", 44, 80)); - settings.setMinWnd(slider(mainWnd, L"Min force:", 44, 154, L"0", L"20", false)); - settings.setMaxWnd(slider(mainWnd, L"Max force:", 44, 226, L"5 Nm", L"65 Nm", false)); - settings.setDampingWnd(slider(mainWnd, L"Damping:", 44, 298, L"0", L"100", true)); - settings.setBumpsWnd(slider(mainWnd, L"Suspension bumps:", 464, 40, L"0", L"100", true)); - settings.setUndersteerWnd(slider(mainWnd, L"Understeer:", 464, 100, L"0", L"100", true)); - settings.setUndersteerOffsetWnd(slider(mainWnd, L"Understeer offset:", 464, 160, L"0", L"100", true)); - settings.setSopWnd(slider(mainWnd, L"SoP effect:", 464, 220, L"0", L"100", true)); - settings.setSopOffsetWnd(slider(mainWnd, L"SoP offset:", 464, 280, L"0", L"100", true)); - settings.setUse360Wnd( - checkbox( - mainWnd, - L" Use 360 Hz telemetry for suspension effects\r\n in direct modes?", - 460, 340 - ) - ); - settings.setCarSpecificWnd( - checkbox(mainWnd, L" Use car specific settings?", 460, 400) - ); - settings.setReduceWhenParkedWnd( - checkbox(mainWnd, L" Reduce force when parked?", 460, 440) - ); - settings.setRunOnStartupWnd( - checkbox(mainWnd, L" Run on startup?", 460, 480) - ); - settings.setStartMinimisedWnd( - checkbox(mainWnd, L" Start minimised?", 460, 520) - ); - settings.setDebugWnd( - checkbox(mainWnd, L"Debug logging?", 460, 560) - ); - - int statusParts[] = { 256, 424, 864 }; - - statusWnd = CreateWindowEx( - 0, STATUSCLASSNAME, NULL, - WS_CHILD | WS_VISIBLE, - 0, 0, 0, 0, mainWnd, NULL, hInst, NULL - ); - SendMessage(statusWnd, SB_SETPARTS, 3, LPARAM(statusParts)); - - textWnd = CreateWindowEx( - WS_EX_CLIENTEDGE, L"EDIT", L"", - WS_VISIBLE | WS_VSCROLL | WS_CHILD | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, - 32, 372, 376, 240, - mainWnd, NULL, hInst, NULL - ); - SendMessage(textWnd, EM_SETLIMITTEXT, WPARAM(256000), 0); - - ShowWindow(mainWnd, SW_HIDE); - UpdateWindow(mainWnd); - - memset(&devFilter, 0, sizeof(devFilter)); - devFilter.dbcc_classguid = GUID_DEVINTERFACE_HID; - devFilter.dbcc_size = sizeof(devFilter); - devFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - RegisterDeviceNotificationW(mainWnd, &devFilter, DEVICE_NOTIFY_WINDOW_HANDLE); - - return TRUE; + DEV_BROADCAST_DEVICEINTERFACE devFilter; + + hInst = hInstance; + + mainWnd = CreateWindowW( + szWindowClass, szTitle, + WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME, + CW_USEDEFAULT, CW_USEDEFAULT, 694, 640, + NULL, NULL, hInst, NULL + ); + + if (!mainWnd) + return FALSE; + + + memset(&niData, 0, sizeof(niData)); + niData.uVersion = NOTIFYICON_VERSION; + niData.cbSize = NOTIFYICONDATA_V1_SIZE; + niData.hWnd = mainWnd; + niData.uID = 1; + niData.uFlags = NIF_ICON | NIF_MESSAGE; + niData.uCallbackMessage = WM_TRAY_ICON; + niData.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_SMALL)); + + //left side UI + settings.setDevWnd(combo(mainWnd, L"FFB device:", 44, 20)); + settings.setFfbWnd(combo(mainWnd, L"FFB type:", 44, 70)); + settings.setMinWnd(slider(mainWnd, L"Min force:", 44, 130, L"0", L"20", false)); + settings.setMaxWnd(slider(mainWnd, L"Max force:", 44, 170, L"5 Nm", L"100 Nm", false)); + settings.setDampingWnd(slider(mainWnd, L"Damping:", 44, 210, L"0", L"100", true)); + + groupox(mainWnd, L"Overlay:", 32, 250, 295, 110); + settings.setForceOverlayWnd(checkbox(mainWnd, L"Show overlay?", 44, 270, 180)); + overlayMoveWnd = checkbox(mainWnd, L"Enable input?", 44, 290, 180); + EnableWindow(overlayMoveWnd, FALSE); + + settings.setOverlayTransparencyWnd(slider(mainWnd, L"Overlay transparency:", 44, 310, L"0", L"255", false)); + + statusWnd = CreateWindowEx( + 0, STATUSCLASSNAME, NULL, + WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, mainWnd, NULL, hInst, NULL + ); + + textWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_VISIBLE | WS_VSCROLL | WS_CHILD | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, + 32, 370, 295, 120, + mainWnd, NULL, hInst, NULL + ); + SendMessage(textWnd, EM_SETLIMITTEXT, WPARAM(256000), 0); + //right side UI + auto groupoxWnd = groupox(mainWnd, L"Understeer Effect:", 344, 20, 295, 210); + settings.setUndersteerWnd(slider(mainWnd, L"Understeer:", 364, 50, L"0", L"100", true)); + settings.setUndersteerOffsetWnd(slider(mainWnd, L"Offset:", 364, 90, L"0", L"100", true)); + settings.setUndersteerYawRateMultWnd(slider(mainWnd, L"Force multiplier:", 364, 130, L"0", L"60", true)); + settings.setUndersteerlatAccelDivWnd(slider(mainWnd, L"Release force:", 364, 170, L"60", L"130", true)); + + settings.setBumpsWnd(slider(mainWnd, L"Suspension bumps:", 364, 240, L"0", L"100", true)); + settings.setSopWnd(slider(mainWnd, L"SoP effect:", 364, 280, L"0", L"100", true)); + settings.setSopOffsetWnd(slider(mainWnd, L"SoP offset:", 364, 320, L"0", L"100", true)); + settings.setUse360Wnd(checkbox(mainWnd, L"Use 360 Hz telemetry for suspension effects\r\n in direct modes?", 360, 360, 300, 38)); + + settings.setCarSpecificWnd( + checkbox(mainWnd, L"Use car specific settings?", 360, 395) + ); + settings.setReduceWhenParkedWnd( + checkbox(mainWnd, L"Reduce force when parked?", 360, 415) + ); + settings.setRunOnStartupWnd( + checkbox(mainWnd, L"Run on startup?", 360, 435) + ); + settings.setStartMinimisedWnd( + checkbox(mainWnd, L"Start minimised?", 360, 455) + ); + settings.setDebugWnd( + checkbox(mainWnd, L"Debug logging?", 360, 475) + ); + + //spanning UI + currentForceWnd = progressbar(mainWnd, L"Current applied force", 32, 500, 480, 20, IR_MAX); + clippingForceWnd = progressbar(mainWnd, L"Clipping force", 480, 500, 160, 20, progressClippingMax); + + SendMessage(clippingForceWnd, PBM_SETSTATE, PBST_ERROR, 0); + + int statusParts[] = { 256, 424, 864 }; + SendMessage(statusWnd, SB_SETPARTS, 3, LPARAM(statusParts)); + + BOOL value = TRUE; + DwmSetWindowAttribute(mainWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); + + ShowWindow(mainWnd, SW_HIDE); + UpdateWindow(mainWnd); + + memset(&devFilter, 0, sizeof(devFilter)); + devFilter.dbcc_classguid = GUID_DEVINTERFACE_HID; + devFilter.dbcc_size = sizeof(devFilter); + devFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + RegisterDeviceNotificationW(mainWnd, &devFilter, DEVICE_NOTIFY_WINDOW_HANDLE); + + CreateOverlayWindow(hInstance); + + HFONT hFont = CreateFont(14, 0, 0, 0, FW_DONTCARE | FW_SEMIBOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, + OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + DEFAULT_PITCH | FF_DONTCARE, TEXT("Microsoft Sans Serif")); + + EnumChildWindows(mainWnd, (WNDENUMPROC)SetFont, (LPARAM)hFont); + + return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - HWND wnd = (HWND)lParam; - - switch (message) { - - case WM_COMMAND: { - - int wmId = LOWORD(wParam); - switch (wmId) { - - case IDM_ABOUT: - DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); - break; - case IDM_EXIT: - DestroyWindow(hWnd); - break; - case ID_SETTINGS_JETSEAT: - if (jetseat) - jetseat->createWindow(hInst); - break; - case ID_SETTINGS_FAN: - fan->createWindow(hInst); - break; - case ID_SETTINGS_HIDGUARDIAN: - hidGuardian->createWindow(hInst); - default: - if (HIWORD(wParam) == CBN_SELCHANGE) { - if (wnd == settings.getDevWnd()) { - GUID oldDevice = settings.getFfbDevice(); - DWORD vidpid = 0; - if (oldDevice != GUID_NULL) - vidpid = getDeviceVidPid(ffdevice); - settings.setFfbDevice(SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0)); - if (vidpid != 0 && oldDevice != settings.getFfbDevice()) - hidGuardian->removeDevice(LOWORD(vidpid), HIWORD(vidpid), false); - } - else if (wnd == settings.getFfbWnd()) - settings.setFfbType(SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0)); - } - else if (HIWORD(wParam) == BN_CLICKED) { - bool oldValue = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED; - if (wnd == settings.getUse360Wnd()) - settings.setUse360ForDirect(!oldValue); - else if (wnd == settings.getCarSpecificWnd()) { - if (!oldValue) - getCarName(); - settings.setUseCarSpecific(!oldValue, car); - } - else if (wnd == settings.getReduceWhenParkedWnd()) - settings.setReduceWhenParked(!oldValue); - else if (wnd == settings.getRunOnStartupWnd()) - settings.setRunOnStartup(!oldValue); - else if (wnd == settings.getStartMinimisedWnd()) - settings.setStartMinimised(!oldValue); - else if (wnd == settings.getDebugWnd()) { - settings.setDebug(!oldValue); - if (settings.getDebug()) { - debugHnd = CreateFileW(settings.getLogPath(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - int chars = SendMessageW(textWnd, WM_GETTEXTLENGTH, 0, 0); - wchar_t *buf = new wchar_t[chars + 1], *str = buf; - SendMessageW(textWnd, WM_GETTEXT, chars + 1, (LPARAM)buf); - wchar_t *end = StrStrW(str, L"\r\n"); - while (end) { - *end = '\0'; - debug(str); - str = end + 2; - end = StrStrW(str, L"\r\n"); - } - delete[] buf; - } - else if (debugHnd != INVALID_HANDLE_VALUE) { - CloseHandle(debugHnd); - debugHnd = INVALID_HANDLE_VALUE; - } - } - } - return DefWindowProc(hWnd, message, wParam, lParam); - } - } - break; - - case WM_EDIT_VALUE: { - if (wnd == settings.getMaxWnd()->value) - settings.setMaxForce(wParam, wnd); - else if (wnd == settings.getMinWnd()->value) - settings.setMinForce(wParam, wnd); - else if (wnd == settings.getBumpsWnd()->value) - settings.setBumpsFactor(reinterpret_cast(wParam), wnd); - else if (wnd == settings.getDampingWnd()->value) - settings.setDampingFactor(reinterpret_cast(wParam), wnd); - else if (wnd == settings.getSopWnd()->value) - settings.setSopFactor(reinterpret_cast(wParam), wnd); - else if (wnd == settings.getSopOffsetWnd()->value) - settings.setSopOffset(reinterpret_cast(wParam), wnd); - } - break; - - - case WM_HSCROLL: { - if (wnd == settings.getMaxWnd()->trackbar) - settings.setMaxForce(SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); - else if (wnd == settings.getMinWnd()->trackbar) - settings.setMinForce(SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); - else if (wnd == settings.getBumpsWnd()->trackbar) - settings.setBumpsFactor((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); - else if (wnd == settings.getDampingWnd()->trackbar) - settings.setDampingFactor((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); - else if (wnd == settings.getSopWnd()->trackbar) - settings.setSopFactor((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); - else if (wnd == settings.getSopOffsetWnd()->trackbar) - settings.setSopOffset((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); - else if (wnd == settings.getUndersteerWnd()->trackbar) - settings.setUndersteerFactor((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); - else if (wnd == settings.getUndersteerOffsetWnd()->trackbar) - settings.setUndersteerOffset((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); - } - break; - - case WM_CTLCOLORSTATIC: { - SetBkColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); - return (LRESULT)CreateSolidBrush(RGB(0xff, 0xff, 0xff)); - } - break; - - case WM_PRINTCLIENT: { - RECT r = { 0 }; - GetClientRect(hWnd, &r); - FillRect((HDC)wParam, &r, CreateSolidBrush(RGB(0xff, 0xff, 0xff))); - } - break; - - case WM_SIZE: { - SendMessage(statusWnd, WM_SIZE, wParam, lParam); - return DefWindowProc(hWnd, message, wParam, lParam); - } - break; - - case WM_POWERBROADCAST: { - int wmId = LOWORD(wParam); - switch (wmId) { - case PBT_APMSUSPEND: - debug(L"Computer is suspending, release all"); - releaseAll(); - break; - case PBT_APMRESUMESUSPEND: - debug(L"Computer is resuming, init all"); - initAll(); - break; - } - } - break; - - case WM_TRAY_ICON: { - switch (lParam) { - case WM_LBUTTONUP: - restore(); - break; - case WM_RBUTTONUP: { - HMENU trayMenu = CreatePopupMenu(); - POINT curPoint; - AppendMenuW(trayMenu, MF_STRING, ID_TRAY_EXIT, L"Exit"); - GetCursorPos(&curPoint); - SetForegroundWindow(hWnd); - if ( - TrackPopupMenu( - trayMenu, TPM_RETURNCMD | TPM_NONOTIFY, - curPoint.x, curPoint.y, 0, hWnd, NULL - ) == ID_TRAY_EXIT - ) - PostQuitMessage(0); - DestroyMenu(trayMenu); - } - break; - } - - } - break; - - case WM_DEVICECHANGE: { - DEV_BROADCAST_HDR *hdr = (DEV_BROADCAST_HDR *)lParam; - if (wParam != DBT_DEVICEARRIVAL && wParam != DBT_DEVICEREMOVECOMPLETE) - return 0; - if (hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) - return 0; - deviceChange(); - } - break; - - case WM_SYSCOMMAND: { - switch (wParam & 0xfff0) { - case SC_MINIMIZE: - minimise(); - return 0; - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - } - break; - - case WM_DESTROY: { - debug(L"Exiting"); - Shell_NotifyIcon(NIM_DELETE, &niData); - releaseAll(); - if (settings.getUseCarSpecific() && car[0] != 0) - settings.writeSettingsForCar(car); - else - settings.writeGenericSettings(); - settings.writeRegSettings(); - hidGuardian->stop(GetCurrentProcessId()); - if (debugHnd != INVALID_HANDLE_VALUE) - CloseHandle(debugHnd); - CloseHandle(globalMutex); - exit(0); - } - break; - - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - - return 0; + HWND wnd = (HWND)lParam; + + switch (message) { + + case WM_COMMAND: { + + int wmId = LOWORD(wParam); + switch (wmId) { + + case IDM_ABOUT: + DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); + break; + case IDM_EXIT: + DestroyWindow(hWnd); + break; + default: + if (HIWORD(wParam) == CBN_SELCHANGE) { + if (wnd == settings.getDevWnd()) { + GUID oldDevice = settings.getFfbDevice(); + DWORD vidpid = 0; + if (oldDevice != GUID_NULL) + vidpid = getDeviceVidPid(ffdevice); + settings.setFfbDevice(SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0)); + } + else if (wnd == settings.getFfbWnd()) + settings.setFfbType(SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0)); + } + else if (HIWORD(wParam) == BN_CLICKED) { + bool oldValue = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED; + if (wnd == settings.getUse360Wnd()) + settings.setUse360ForDirect(!oldValue); + else if (wnd == settings.getCarSpecificWnd()) { + if (!oldValue) + getCarName(); + settings.setUseCarSpecific(!oldValue, car); + } + else if (wnd == settings.getReduceWhenParkedWnd()) + settings.setReduceWhenParked(!oldValue); + else if (wnd == settings.getRunOnStartupWnd()) + settings.setRunOnStartup(!oldValue); + else if (wnd == settings.getStartMinimisedWnd()) + settings.setStartMinimised(!oldValue); + else if (wnd == settings.getForceOverlayWnd()) + { + settings.setShowForceOverlay(!oldValue); + if (!oldValue) + { + EnableWindow(overlayMoveWnd, TRUE); + ShowWindow(overlayWnd, SW_SHOW); + } + else + { + EnableWindow(overlayMoveWnd, FALSE); + ShowWindow(overlayWnd, SW_HIDE); + } + } + else if (wnd == overlayMoveWnd) + { + if (!oldValue) + ActivateOverLayWindow(); + else + DeActivateOverlayWindow(); + SendMessage(overlayMoveWnd, BM_SETCHECK, !oldValue ? BST_CHECKED : BST_UNCHECKED, NULL); + + } + + + else if (wnd == settings.getDebugWnd()) { + settings.setDebug(!oldValue); + if (settings.getDebug()) { + debugHnd = CreateFileW(settings.getLogPath().c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + int chars = SendMessageW(textWnd, WM_GETTEXTLENGTH, 0, 0); + wchar_t* buf = new wchar_t[chars + 1], * str = buf; + SendMessageW(textWnd, WM_GETTEXT, chars + 1, (LPARAM)buf); + wchar_t* end = StrStrW(str, L"\r\n"); + while (end) { + *end = '\0'; + debug(str); + str = end + 2; + end = StrStrW(str, L"\r\n"); + } + delete[] buf; + } + else if (debugHnd != INVALID_HANDLE_VALUE) { + CloseHandle(debugHnd); + debugHnd = INVALID_HANDLE_VALUE; + } + } + + } + return DefWindowProc(hWnd, message, wParam, lParam); + } + } + break; + + case WM_EDIT_VALUE: { + if (wnd == settings.getMaxWnd()->value) + settings.setMaxForce(wParam, wnd); + else if (wnd == settings.getMinWnd()->value) + settings.setMinForce(wParam, wnd); + else if (wnd == settings.getBumpsWnd()->value) + settings.setBumpsFactor(reinterpret_cast(wParam), wnd); + else if (wnd == settings.getDampingWnd()->value) + settings.setDampingFactor(reinterpret_cast(wParam), wnd); + else if (wnd == settings.getSopWnd()->value) + settings.setSopFactor(reinterpret_cast(wParam), wnd); + else if (wnd == settings.getSopOffsetWnd()->value) + settings.setSopOffset(reinterpret_cast(wParam), wnd); + else if (wnd == settings.getUndersteerYawRateMultWnd()->value) + settings.setUndersteerYawRateMult(reinterpret_cast(wParam), wnd); + else if (wnd == settings.getUndersteerlatAccelDivWnd()->value) + settings.setUndersteerlatAccelDiv(reinterpret_cast(wParam), wnd); + else if (wnd == settings.getOverlayTransparencyWnd()->value) + { + settings.setOverlayTransparency(reinterpret_cast(wParam), wnd); + SetLayeredWindowAttributes(overlayWnd, 0, settings.getOverlayTransparency(), LWA_ALPHA); + } + + } + break; + + + case WM_HSCROLL: { + if (wnd == settings.getMaxWnd()->trackbar || wnd == settings.getOverlayMaxForceWnd()) + settings.setMaxForce(SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getMinWnd()->trackbar) + settings.setMinForce(SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getBumpsWnd()->trackbar) + settings.setBumpsFactor((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getDampingWnd()->trackbar) + settings.setDampingFactor((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getSopWnd()->trackbar) + settings.setSopFactor((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getSopOffsetWnd()->trackbar) + settings.setSopOffset((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getUndersteerWnd()->trackbar) + settings.setUndersteerFactor((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getUndersteerOffsetWnd()->trackbar) + settings.setUndersteerOffset((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getUndersteerYawRateMultWnd()->trackbar) + settings.setUndersteerYawRateMult((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getUndersteerlatAccelDivWnd()->trackbar) + settings.setUndersteerlatAccelDiv((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + else if (wnd == settings.getOverlayTransparencyWnd()->trackbar) + { + settings.setOverlayTransparency((float)SendMessage(wnd, TBM_GETPOS, 0, 0), wnd); + SetLayeredWindowAttributes(overlayWnd, 0, settings.getOverlayTransparency(), LWA_ALPHA); + } + + } + break; + + case WM_CTLCOLORSTATIC: { + SetBkColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); + return (LRESULT)CreateSolidBrush(RGB(0xff, 0xff, 0xff)); + } + break; + + case WM_PRINTCLIENT: { + RECT r = { 0 }; + GetClientRect(hWnd, &r); + FillRect((HDC)wParam, &r, CreateSolidBrush(RGB(0xff, 0xff, 0xff))); + } + break; + + case WM_SIZE: { + SendMessage(statusWnd, WM_SIZE, wParam, lParam); + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + + case WM_POWERBROADCAST: { + int wmId = LOWORD(wParam); + switch (wmId) { + case PBT_APMSUSPEND: + debug(L"Computer is suspending, release all"); + releaseAll(); + break; + case PBT_APMRESUMESUSPEND: + debug(L"Computer is resuming, init all"); + initAll(); + break; + } + } + break; + + case WM_TRAY_ICON: { + switch (lParam) { + case WM_LBUTTONUP: + restore(); + break; + case WM_RBUTTONUP: { + HMENU trayMenu = CreatePopupMenu(); + POINT curPoint; + AppendMenuW(trayMenu, MF_STRING, ID_TRAY_EXIT, L"Exit"); + GetCursorPos(&curPoint); + SetForegroundWindow(hWnd); + if ( + TrackPopupMenu( + trayMenu, TPM_RETURNCMD | TPM_NONOTIFY, + curPoint.x, curPoint.y, 0, hWnd, NULL + ) == ID_TRAY_EXIT + ) + PostQuitMessage(0); + DestroyMenu(trayMenu); + } + break; + } + + } + break; + case WM_WINDOWPOSCHANGED: + { + if (hWnd == overlayWnd) + { + WINDOWPOS* winPos = (WINDOWPOS*)lParam; + settings.setWindowPosX(winPos->x); + settings.setWindowPosY(winPos->y); + } + } + break; + + case WM_DEVICECHANGE: { + DEV_BROADCAST_HDR* hdr = (DEV_BROADCAST_HDR*)lParam; + if (wParam != DBT_DEVICEARRIVAL && wParam != DBT_DEVICEREMOVECOMPLETE) + return 0; + if (hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) + return 0; + deviceChange(); + } + break; + + case WM_SYSCOMMAND: { + switch (wParam & 0xfff0) { + case SC_MINIMIZE: + minimise(); + return 0; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + } + break; + + case WM_DESTROY: { + debug(L"Exiting"); + Shell_NotifyIcon(NIM_DELETE, &niData); + releaseAll(); + if (settings.getUseCarSpecific() && car[0] != 0) + settings.writeSettingsForCar(car); + else + settings.writeGenericSettings(); + settings.writeRegSettings(); + if (debugHnd != INVALID_HANDLE_VALUE) + CloseHandle(debugHnd); + CloseHandle(globalMutex); + exit(0); + } + break; + + case WM_NCHITTEST: + { + LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam); + if (hWnd == overlayWnd && hit == HTCLIENT) + hit = HTCAPTION; + + return hit; + } + break; + case WM_HOTKEY: + { + int wmId = LOWORD(wParam); + if (wmId == ID_MAXFORCE_UP) + settings.setMaxForce(settings.getMaxForce() - 1, (HWND)-1); + + if (wmId == ID_MAXFORCE_DOWN) + settings.setMaxForce(settings.getMaxForce() + 1, (HWND)-1); + + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + + return 0; } INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { - UNREFERENCED_PARAMETER(lParam); + UNREFERENCED_PARAMETER(lParam); - switch (message) { + switch (message) { - case WM_INITDIALOG: - return (INT_PTR)TRUE; + case WM_INITDIALOG: + return (INT_PTR)TRUE; - case WM_COMMAND: - if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { - EndDialog(hDlg, LOWORD(wParam)); - return (INT_PTR)TRUE; - } - break; - } + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, LOWORD(wParam)); + return (INT_PTR)TRUE; + } + break; + } - return (INT_PTR)FALSE; + return (INT_PTR)FALSE; } +LRESULT CALLBACK myPaint(HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + switch (uMsg) + { + case WM_PAINT: + { + PAINTSTRUCT ps; + RECT rectangle; + HDC hdc = BeginPaint(hWnd, &ps); + SendMessage(hWnd, WM_ERASEBKGND, (WPARAM)GetDC(hWnd), NULL); /* Erases the background */ + GetClientRect(hWnd, &rectangle); /* Gets the toolbar's area */ + FillRect(GetDC(hWnd), &rectangle, (HBRUSH)(COLOR_WINDOW + 2)); /* Fills the toolbar's background white */ + EndPaint(hWnd, &ps); + + break; + } + } + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} +LRESULT CALLBACK myNcHitTest(HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + switch (uMsg) + { + case WM_NCHITTEST: + { + LRESULT hit = DefSubclassProc(hWnd, uMsg, wParam, lParam); + if (hit == HTCLIENT) hit = HTTRANSPARENT; + return hit; + } + } + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} -void text(wchar_t *fmt, ...) { +void text(wchar_t* fmt, ...) { - va_list argp; - wchar_t msg[512]; - va_start(argp, fmt); + va_list argp; + wchar_t msg[512]; + va_start(argp, fmt); - StringCbVPrintf(msg, sizeof(msg) - 2 * sizeof(wchar_t), fmt, argp); - va_end(argp); - StringCbCat(msg, sizeof(msg), L"\r\n"); + StringCbVPrintf(msg, sizeof(msg) - 2 * sizeof(wchar_t), fmt, argp); + va_end(argp); + StringCbCat(msg, sizeof(msg), L"\r\n"); - SendMessage(textWnd, EM_SETSEL, 0, -1); - SendMessage(textWnd, EM_SETSEL, -1, 1); - SendMessage(textWnd, EM_REPLACESEL, 0, (LPARAM)msg); - SendMessage(textWnd, EM_SCROLLCARET, 0, 0); + SendMessage(textWnd, EM_SETSEL, 0, -1); + SendMessage(textWnd, EM_SETSEL, -1, 1); + SendMessage(textWnd, EM_REPLACESEL, 0, (LPARAM)msg); + SendMessage(textWnd, EM_SCROLLCARET, 0, 0); - debug(msg); + debug(msg); } -void text(wchar_t *fmt, char *charstr) { - - int len = strlen(charstr) + 1; - wchar_t *wstr = new wchar_t[len]; - mbstowcs_s(nullptr, wstr, len, charstr, len); - text(fmt, wstr); - delete[] wstr; +void text(wchar_t* fmt, char* charstr) { + int len = strlen(charstr) + 1; + wchar_t* wstr = new wchar_t[len]; + mbstowcs_s(nullptr, wstr, len, charstr, len); + text(fmt, wstr); + delete[] wstr; + return; } -void debug(wchar_t *msg) { - - if (!settings.getDebug()) - return; - - DWORD written; - wchar_t buf[512]; - SYSTEMTIME lt; - - GetLocalTime(<); - StringCbPrintfW( - buf, sizeof(buf), L"%d-%02d-%02d %02d:%02d:%02d.%03d ", - lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds - ); - - StringCbCat(buf, sizeof(buf), msg); - StringCbCat(buf, sizeof(buf), L"\r\n"); - - if (!wcscmp(msg, debugLastMsg)) { - debugRepeat++; - return; - } - else if (debugRepeat) { - wchar_t rm[256]; - StringCbPrintfW(rm, sizeof(rm), L"-- Last message repeated %d times --\r\n", debugRepeat); - WriteFile(debugHnd, rm, wcslen(rm) * sizeof(wchar_t), &written, NULL); - debugRepeat = 0; - } - - StringCbCopy(debugLastMsg, sizeof(debugLastMsg), msg); - WriteFile(debugHnd, buf, wcslen(buf) * sizeof(wchar_t), &written, NULL); +void debug(wchar_t* msg) { + + if (!settings.getDebug()) + return; + + DWORD written; + wchar_t buf[512]; + SYSTEMTIME lt; + + GetLocalTime(<); + StringCbPrintfW( + buf, sizeof(buf), L"%d-%02d-%02d %02d:%02d:%02d.%03d ", + lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds + ); + + StringCbCat(buf, sizeof(buf), msg); + StringCbCat(buf, sizeof(buf), L"\r\n"); + + if (!wcscmp(msg, debugLastMsg)) { + debugRepeat++; + return; + } + else if (debugRepeat) { + wchar_t rm[256]; + StringCbPrintfW(rm, sizeof(rm), L"-- Last message repeated %d times --\r\n", debugRepeat); + WriteFile(debugHnd, rm, wcslen(rm) * sizeof(wchar_t), &written, NULL); + debugRepeat = 0; + } + + StringCbCopy(debugLastMsg, sizeof(debugLastMsg), msg); + WriteFile(debugHnd, buf, wcslen(buf) * sizeof(wchar_t), &written, NULL); } template -void debug(wchar_t *fmt, T... args) { +void debug(wchar_t* fmt, T... args) { - if (!settings.getDebug()) - return; + if (!settings.getDebug()) + return; - wchar_t msg[512]; - StringCbPrintf(msg, sizeof(msg), fmt, args...); - debug(msg); + wchar_t msg[512]; + StringCbPrintf(msg, sizeof(msg), fmt, args...); + debug(msg); } -void setCarStatus(char *carStr) { +void setCarStatus(char* carStr) { - if (!carStr || carStr[0] == 0) { - SendMessage(statusWnd, SB_SETTEXT, STATUS_CAR_PART, LPARAM(L"Car: generic")); - return; - } + if (!carStr || carStr[0] == 0) { + SendMessage(statusWnd, SB_SETTEXT, STATUS_CAR_PART, LPARAM(L"Car: generic")); + return; + } - int len = strlen(carStr) + 1; - wchar_t *wstr = new wchar_t[len + 5]; - lstrcpy(wstr, L"Car: "); - mbstowcs_s(nullptr, wstr + 5, len, carStr, len); - SendMessage(statusWnd, SB_SETTEXT, STATUS_CAR_PART, LPARAM(wstr)); - delete[] wstr; + int len = strlen(carStr) + 1; + wchar_t* wstr = new wchar_t[len + 5]; + lstrcpy(wstr, L"Car: "); + mbstowcs_s(nullptr, wstr + 5, len, carStr, len); + SendMessage(statusWnd, SB_SETTEXT, STATUS_CAR_PART, LPARAM(wstr)); + delete[] wstr; } void setConnectedStatus(bool connected) { - SendMessage( - statusWnd, SB_SETTEXT, STATUS_CONNECTED_PART, - LPARAM(connected ? L"iRacing connected" : L"iRacing disconnected") - ); + SendMessage( + statusWnd, SB_SETTEXT, STATUS_CONNECTED_PART, + LPARAM(connected ? L"iRacing connected" : L"iRacing disconnected") + ); } void setOnTrackStatus(bool onTrack) { - SendMessage( - statusWnd, SB_SETTEXT, STATUS_ONTRACK_PART, - LPARAM(onTrack ? L"On track" : L"Not on track") - ); + SendMessage( + statusWnd, SB_SETTEXT, STATUS_ONTRACK_PART, + LPARAM(onTrack ? L"On track" : L"Not on track") + ); - if (!onTrack && deviceChangePending) { - debug(L"Processing deferred device change notification"); - deviceChange(); - } + if (!onTrack && deviceChangePending) { + debug(L"Processing deferred device change notification"); + deviceChange(); + } } void setLogiWheelRange(WORD prodId) { - if (prodId == G25PID || prodId == DFGTPID || prodId == G27PID) { + if (prodId == G25PID || prodId == DFGTPID || prodId == G27PID) { - GUID hidGuid; - HidD_GetHidGuid(&hidGuid); + GUID hidGuid; + HidD_GetHidGuid(&hidGuid); - text(L"DFGT/G25/G27 detected, setting range using raw HID"); + text(L"DFGT/G25/G27 detected, setting range using raw HID"); - HANDLE devInfoSet = SetupDiGetClassDevsW(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (devInfoSet == INVALID_HANDLE_VALUE) { - text(L"LogiWheel: Error enumerating HID devices"); - return; - } + HANDLE devInfoSet = SetupDiGetClassDevsW(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (devInfoSet == INVALID_HANDLE_VALUE) { + text(L"LogiWheel: Error enumerating HID devices"); + return; + } - SP_DEVICE_INTERFACE_DATA intfData; - SP_DEVICE_INTERFACE_DETAIL_DATA *intfDetail; - DWORD idx = 0; - DWORD error = 0; - DWORD size; + SP_DEVICE_INTERFACE_DATA intfData; + SP_DEVICE_INTERFACE_DETAIL_DATA* intfDetail; + DWORD idx = 0; + DWORD error = 0; + DWORD size; - while (true) { + while (true) { - intfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + intfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - if (!SetupDiEnumDeviceInterfaces(devInfoSet, NULL, &hidGuid, idx++, &intfData)) { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; - continue; - } + if (!SetupDiEnumDeviceInterfaces(devInfoSet, NULL, &hidGuid, idx++, &intfData)) { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } - if (!SetupDiGetDeviceInterfaceDetailW(devInfoSet, &intfData, NULL, 0, &size, NULL)) - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - text(L"LogiWheel: Error getting intf detail"); - continue; - } + if (!SetupDiGetDeviceInterfaceDetailW(devInfoSet, &intfData, NULL, 0, &size, NULL)) + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + text(L"LogiWheel: Error getting intf detail"); + continue; + } - intfDetail = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(size); - intfDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + intfDetail = (SP_DEVICE_INTERFACE_DETAIL_DATA*)malloc(size); + intfDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - if (!SetupDiGetDeviceInterfaceDetailW(devInfoSet, &intfData, intfDetail, size, NULL, NULL)) { - free(intfDetail); - continue; - } + if (!SetupDiGetDeviceInterfaceDetailW(devInfoSet, &intfData, intfDetail, size, NULL, NULL)) { + free(intfDetail); + continue; + } - if ( - wcsstr(intfDetail->DevicePath, G25PATH) != NULL || - wcsstr(intfDetail->DevicePath, DFGTPATH) != NULL || - wcsstr(intfDetail->DevicePath, G27PATH) != NULL - ) { + if ( + wcsstr(intfDetail->DevicePath, G25PATH) != NULL || + wcsstr(intfDetail->DevicePath, DFGTPATH) != NULL || + wcsstr(intfDetail->DevicePath, G27PATH) != NULL + ) { - HANDLE file = CreateFileW( - intfDetail->DevicePath, - GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL - ); + HANDLE file = CreateFileW( + intfDetail->DevicePath, + GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL + ); - if (file == INVALID_HANDLE_VALUE) { - text(L"LogiWheel: Failed to open HID device"); - free(intfDetail); - SetupDiDestroyDeviceInfoList(devInfoSet); - return; - } + if (file == INVALID_HANDLE_VALUE) { + text(L"LogiWheel: Failed to open HID device"); + free(intfDetail); + SetupDiDestroyDeviceInfoList(devInfoSet); + return; + } - DWORD written; + DWORD written; - if (!WriteFile(file, LOGI_WHEEL_HID_CMD, LOGI_WHEEL_HID_CMD_LEN, &written, NULL)) - text(L"LogiWheel: Failed to write to HID device"); - else - text(L"LogiWheel: Range set to 900 deg via raw HID"); + if (!WriteFile(file, LOGI_WHEEL_HID_CMD, LOGI_WHEEL_HID_CMD_LEN, &written, NULL)) + text(L"LogiWheel: Failed to write to HID device"); + else + text(L"LogiWheel: Range set to 900 deg via raw HID"); - CloseHandle(file); - free(intfDetail); - SetupDiDestroyDeviceInfoList(devInfoSet); - return; + CloseHandle(file); + free(intfDetail); + SetupDiDestroyDeviceInfoList(devInfoSet); + return; - } + } - free(intfDetail); + free(intfDetail); - } + } - text(L"Failed to locate Logitech wheel HID device, can't set range"); - SetupDiDestroyDeviceInfoList(devInfoSet); - return; + text(L"Failed to locate Logitech wheel HID device, can't set range"); + SetupDiDestroyDeviceInfoList(devInfoSet); + return; - } + } - text(L"Attempting to set range via LGS"); + text(L"Attempting to set range via LGS"); - UINT msgId = RegisterWindowMessage(L"LGS_Msg_SetOperatingRange"); - if (!msgId) { - text(L"Failed to register LGS window message, can't set range.."); - return; - } + UINT msgId = RegisterWindowMessage(L"LGS_Msg_SetOperatingRange"); + if (!msgId) { + text(L"Failed to register LGS window message, can't set range.."); + return; + } - HWND LGSmsgHandler = - FindWindowW( - L"LCore_MessageHandler_{C464822E-04D1-4447-B918-6D5EB33E0E5D}", - NULL - ); + HWND LGSmsgHandler = + FindWindowW( + L"LCore_MessageHandler_{C464822E-04D1-4447-B918-6D5EB33E0E5D}", + NULL + ); - if (LGSmsgHandler == NULL) { - text(L"Failed to locate LGS msg handler, can't set range.."); - return; - } + if (LGSmsgHandler == NULL) { + text(L"Failed to locate LGS msg handler, can't set range.."); + return; + } - SendMessageW(LGSmsgHandler, msgId, prodId, 900); - text(L"Range of Logitech wheel set to 900 deg via LGS"); + SendMessageW(LGSmsgHandler, msgId, prodId, 900); + text(L"Range of Logitech wheel set to 900 deg via LGS"); } -BOOL CALLBACK EnumFFDevicesCallback(LPCDIDEVICEINSTANCE diDevInst, VOID *wnd) { +BOOL CALLBACK EnumFFDevicesCallback(LPCDIDEVICEINSTANCE diDevInst, VOID* wnd) { - UNREFERENCED_PARAMETER(wnd); + UNREFERENCED_PARAMETER(wnd); - if (lstrcmp(diDevInst->tszProductName, L"vJoy Device") == 0) - return true; + if (lstrcmp(diDevInst->tszProductName, L"vJoy Device") == 0) + return true; - settings.addFfbDevice(diDevInst->guidInstance, diDevInst->tszProductName); - debug(L"Adding DI device: %s", diDevInst->tszProductName); + settings.addFfbDevice(diDevInst->guidInstance, diDevInst->tszProductName); + debug(L"Adding DI device: %s", diDevInst->tszProductName); - return true; + return true; } -BOOL CALLBACK EnumObjectCallback(const LPCDIDEVICEOBJECTINSTANCE inst, VOID *dw) { +BOOL CALLBACK EnumObjectCallback(const LPCDIDEVICEOBJECTINSTANCE inst, VOID* dw) { - UNREFERENCED_PARAMETER(inst); + UNREFERENCED_PARAMETER(inst); - (*(int *)dw)++; - return DIENUM_CONTINUE; + (*(int*)dw)++; + return DIENUM_CONTINUE; } void enumDirectInput() { - settings.clearFfbDevices(); - - if ( - FAILED( - DirectInput8Create( - GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, - (VOID **)&pDI, nullptr - ) - ) - ) { - text(L"Failed to initialise DirectInput"); - return; - } - - pDI->EnumDevices( - DI8DEVCLASS_GAMECTRL, EnumFFDevicesCallback, settings.getDevWnd(), - DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK - ); + settings.clearFfbDevices(); + + if ( + FAILED( + DirectInput8Create( + GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, + (VOID**)&pDI, nullptr + ) + ) + ) { + text(L"Failed to initialise DirectInput"); + return; + } + + pDI->EnumDevices( + DI8DEVCLASS_GAMECTRL, EnumFFDevicesCallback, settings.getDevWnd(), + DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK + ); } void initDirectInput() { - DIDEVICEINSTANCE di; - HRESULT hr; - - numButtons = numPov = 0; - di.dwSize = sizeof(DIDEVICEINSTANCE); - - if (ffdevice && effect && ffdevice->GetDeviceInfo(&di) >= 0 && di.guidInstance == settings.getFfbDevice()) - return; - - releaseDirectInput(); - - if ( - FAILED( - DirectInput8Create( - GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, - (VOID **)&pDI, nullptr - ) - ) - ) { - text(L"Failed to initialise DirectInput"); - return; - } - - if (FAILED(pDI->CreateDevice(settings.getFfbDevice(), &ffdevice, nullptr))) { - text(L"Failed to create DI device"); - text(L"Is it connected and powered on?"); - return; - } - if (FAILED(ffdevice->SetDataFormat(&c_dfDIJoystick))) { - text(L"Failed to set DI device DataFormat!"); - return; - } - if (FAILED(ffdevice->SetCooperativeLevel(mainWnd, DISCL_EXCLUSIVE | DISCL_BACKGROUND))) { - text(L"Failed to set DI device CooperativeLevel!"); - return; - } - - if (FAILED(ffdevice->GetDeviceInfo(&di))) { - text(L"Failed to get info for DI device!"); - return; - } - - if (FAILED(ffdevice->EnumObjects(EnumObjectCallback, (VOID *)&numButtons, DIDFT_BUTTON))) { - text(L"Failed to enumerate DI device buttons"); - return; - } - - if (FAILED(ffdevice->EnumObjects(EnumObjectCallback, (VOID *)&numPov, DIDFT_POV))) { - text(L"Failed to enumerate DI device povs"); - return; - } - - if (FAILED(ffdevice->SetEventNotification(wheelEvent))) { - text(L"Failed to set event notification on DI device"); - return; - } - - DWORD vidpid = getDeviceVidPid(ffdevice); - if (LOWORD(vidpid) == 0x046d) { - logiWheel = true; - setLogiWheelRange(HIWORD(vidpid)); - } - else - logiWheel = false; - - if (FAILED(ffdevice->Acquire())) { - text(L"Failed to acquire DI device"); - return; - } - - text(L"Acquired DI device with %d buttons and %d POV", numButtons, numPov); - - EnterCriticalSection(&effectCrit); - - if (FAILED(ffdevice->CreateEffect(GUID_Sine, &dieff, &effect, nullptr))) { - text(L"Failed to create sine periodic effect"); - LeaveCriticalSection(&effectCrit); - return; - } - - if (!effect) { - text(L"Effect creation failed"); - LeaveCriticalSection(&effectCrit); - return; - } - - hr = effect->SetParameters(&dieff, DIEP_TYPESPECIFICPARAMS | DIEP_START); - if (hr == DIERR_NOTINITIALIZED || hr == DIERR_INPUTLOST || hr == DIERR_INCOMPLETEEFFECT || hr == DIERR_INVALIDPARAM) - text(L"Error setting parameters of DIEFFECT: %d", hr); - - LeaveCriticalSection(&effectCrit); - - if (vidpid != 0) - hidGuardian->setDevice(LOWORD(vidpid), HIWORD(vidpid)); + DIDEVICEINSTANCE di; + HRESULT hr; + + numButtons = numPov = 0; + di.dwSize = sizeof(DIDEVICEINSTANCE); + + if (ffdevice && effect && ffdevice->GetDeviceInfo(&di) >= 0 && di.guidInstance == settings.getFfbDevice()) + return; + + releaseDirectInput(); + + if ( + FAILED( + DirectInput8Create( + GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, + (VOID**)&pDI, nullptr + ) + ) + ) { + text(L"Failed to initialise DirectInput"); + return; + } + + if (FAILED(pDI->CreateDevice(settings.getFfbDevice(), &ffdevice, nullptr))) { + text(L"Failed to create DI device"); + text(L"Is it connected and powered on?"); + return; + } + if (FAILED(ffdevice->SetDataFormat(&c_dfDIJoystick))) { + text(L"Failed to set DI device DataFormat!"); + return; + } + if (FAILED(ffdevice->SetCooperativeLevel(mainWnd, DISCL_EXCLUSIVE | DISCL_BACKGROUND))) { + text(L"Failed to set DI device CooperativeLevel!"); + return; + } + + if (FAILED(ffdevice->GetDeviceInfo(&di))) { + text(L"Failed to get info for DI device!"); + return; + } + + if (FAILED(ffdevice->EnumObjects(EnumObjectCallback, (VOID*)&numButtons, DIDFT_BUTTON))) { + text(L"Failed to enumerate DI device buttons"); + return; + } + + if (FAILED(ffdevice->EnumObjects(EnumObjectCallback, (VOID*)&numPov, DIDFT_POV))) { + text(L"Failed to enumerate DI device povs"); + return; + } + + if (FAILED(ffdevice->SetEventNotification(wheelEvent))) { + text(L"Failed to set event notification on DI device"); + return; + } + + DWORD vidpid = getDeviceVidPid(ffdevice); + if (LOWORD(vidpid) == 0x046d) { + logiWheel = true; + setLogiWheelRange(HIWORD(vidpid)); + } + else + logiWheel = false; + + if (FAILED(ffdevice->Acquire())) { + text(L"Failed to acquire DI device"); + return; + } + + text(L"Acquired DI device with %d buttons and %d POV", numButtons, numPov); + + EnterCriticalSection(&effectCrit); + + if (FAILED(ffdevice->CreateEffect(GUID_Sine, &dieff, &effect, nullptr))) { + text(L"Failed to create sine periodic effect"); + LeaveCriticalSection(&effectCrit); + return; + } + + if (!effect) { + text(L"Effect creation failed"); + LeaveCriticalSection(&effectCrit); + return; + } + + hr = effect->SetParameters(&dieff, DIEP_TYPESPECIFICPARAMS | DIEP_START); + if (hr == DIERR_NOTINITIALIZED || hr == DIERR_INPUTLOST || hr == DIERR_INCOMPLETEEFFECT || hr == DIERR_INVALIDPARAM) + text(L"Error setting parameters of DIEFFECT: %d", hr); + + LeaveCriticalSection(&effectCrit); } void releaseDirectInput() { - if (effect) { - setFFB(0); - EnterCriticalSection(&effectCrit); - effect->Stop(); - effect->Release(); - effect = nullptr; - LeaveCriticalSection(&effectCrit); - } - if (ffdevice) { - ffdevice->Unacquire(); - ffdevice->Release(); - ffdevice = nullptr; - } - if (pDI) { - pDI->Release(); - pDI = nullptr; - } + if (effect) { + setFFB(0); + EnterCriticalSection(&effectCrit); + effect->Stop(); + effect->Release(); + effect = nullptr; + LeaveCriticalSection(&effectCrit); + } + if (ffdevice) { + ffdevice->Unacquire(); + ffdevice->Release(); + ffdevice = nullptr; + } + if (pDI) { + pDI->Release(); + pDI = nullptr; + } } void reacquireDIDevice() { - if (ffdevice == nullptr) { - debug(L"!! ffdevice was null during reacquire !!"); - return; - } + if (ffdevice == nullptr) { + debug(L"!! ffdevice was null during reacquire !!"); + return; + } - HRESULT hr; + HRESULT hr; - ffdevice->Unacquire(); - ffdevice->Acquire(); + ffdevice->Unacquire(); + ffdevice->Acquire(); - EnterCriticalSection(&effectCrit); + EnterCriticalSection(&effectCrit); - if (effect == nullptr) { - if (FAILED(ffdevice->CreateEffect(GUID_Sine, &dieff, &effect, nullptr))) { - text(L"Failed to create periodic effect during reacquire"); - LeaveCriticalSection(&effectCrit); - return; - } - } + if (effect == nullptr) { + if (FAILED(ffdevice->CreateEffect(GUID_Sine, &dieff, &effect, nullptr))) { + text(L"Failed to create periodic effect during reacquire"); + LeaveCriticalSection(&effectCrit); + return; + } + } - hr = effect->SetParameters(&dieff, DIEP_TYPESPECIFICPARAMS | DIEP_START); - if (hr == DIERR_NOTINITIALIZED || hr == DIERR_INPUTLOST || hr == DIERR_INCOMPLETEEFFECT || hr == DIERR_INVALIDPARAM) - text(L"Error setting parameters of DIEFFECT during reacquire: 0x%x", hr); + hr = effect->SetParameters(&dieff, DIEP_TYPESPECIFICPARAMS | DIEP_START); + if (hr == DIERR_NOTINITIALIZED || hr == DIERR_INPUTLOST || hr == DIERR_INCOMPLETEEFFECT || hr == DIERR_INVALIDPARAM) + text(L"Error setting parameters of DIEFFECT during reacquire: 0x%x", hr); - LeaveCriticalSection(&effectCrit); + LeaveCriticalSection(&effectCrit); } inline void sleepSpinUntil(PLARGE_INTEGER base, UINT sleep, UINT offset) { - LARGE_INTEGER time; - LONGLONG until = base->QuadPart + (offset * freq.QuadPart) / 1000000; - - std::this_thread::sleep_for(std::chrono::microseconds(sleep)); - do { - _asm { pause }; - QueryPerformanceCounter(&time); - } while (time.QuadPart < until); + if (!settings.getUseAltTimer()) { + nanosleep(offset); + } + else { + int i = 0; + LARGE_INTEGER time; + LONGLONG until = base->QuadPart + (offset * freq.QuadPart) / 1000000; + + if (!sleepSpin || sleep > 1000) + std::this_thread::sleep_for(std::chrono::microseconds(sleep)); + + QueryPerformanceCounter(&time); + while (time.QuadPart < until) { + _mm_pause(); + QueryPerformanceCounter(&time); + // i++; + } + } + //text(L"Paused for %d", i); +} +inline void nanosleep(LONGLONG ns) { + /* Declarations */ + HANDLE timer; /* Timer handle */ + LARGE_INTEGER li; /* Time defintion */ + /* Create timer */ + + if (!(timer = CreateWaitableTimerEx(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS))) { + return; + } + + li.QuadPart = -ns; + if (!SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE)) { + CloseHandle(timer); + return; + } + /* Start & wait for timer */ + WaitForSingleObject(timer, INFINITE); + /* Clean resources */ + CloseHandle(timer); + /* Slept without problems */ + return; } + inline int scaleTorque(float t) { - return (int)(t * settings.getScaleFactor()); + return (int)(t * settings.getScaleFactor()); } inline void setFFB(int mag) { - if (!effect) - return; - - if (mag <= -IR_MAX) { - mag = -IR_MAX; - clippedSamples++; - } - else if (mag >= IR_MAX) { - mag = IR_MAX; - clippedSamples++; - } - - samples++; - int minForce = settings.getMinForce(); - - if (stopped && settings.getReduceWhenParked()) - mag /= 4; - else if (minForce) { - if (mag > 0 && mag < minForce) - mag = minForce; - else if (mag < 0 && mag > -minForce) - mag = -minForce; - } - - ffbMag = mag; - + if (!effect) + return; + + int clippedAmmount = 0; + + if (mag <= -IR_MAX) + { + clippedAmmount = mag - -IR_MAX; + mag = -IR_MAX; + clippedSamples++; + } + else if (mag >= IR_MAX) { + clippedAmmount = mag - IR_MAX; + mag = IR_MAX; + clippedSamples++; + } + + samples++; + int minForce = settings.getMinForce(); + + if (stopped && settings.getReduceWhenParked()) + mag /= 4; + else if (minForce) { + if (mag > 0 && mag < minForce) + mag = minForce; + else if (mag < 0 && mag > -minForce) + mag = -minForce; + } + + ffbMag = mag; + + ::SendMessage(currentForceWnd, PBM_SETPOS, (WPARAM)(INT)abs(mag), 0); + if (clippedAmmount > progressClippingMax) + { + progressClippingMax = clippedAmmount; + ::SendMessage(clippingForceWnd, PBM_SETRANGE32, 0, (WPARAM)(INT)progressClippingMax); + ::SendMessage(clippingForceOverlayWnd, PBM_SETRANGE32, 0, (WPARAM)(INT)progressClippingMax); + } + + ::SendMessage(clippingForceWnd, PBM_SETPOS, (WPARAM)(INT)abs(clippedAmmount), 0); + + if (settings.getShowForceOverlay()) + { + ::SendMessage(currentForceOverlayWnd, PBM_SETPOS, (WPARAM)(INT)abs(mag), 0); + ::SendMessage(clippingForceOverlayWnd, PBM_SETPOS, (WPARAM)(INT)abs(clippedAmmount), 0); + } } bool initVJD() { - WORD verDrv; - int maxVjDev; - VjdStat vjdStatus = VJD_STAT_UNKN; - - if (!vJoyEnabled()) { - text(L"vJoy not enabled!"); - return false; - } - else - text(L"vJoy driver version %04x init OK", &verDrv); - - vjDev = 1; - - if (!GetvJoyMaxDevices(&maxVjDev)) { - text(L"Failed to determine max number of vJoy devices"); - return false; - } - - while (vjDev <= maxVjDev) { - - vjdStatus = GetVJDStatus(vjDev); - - if (vjdStatus == VJD_STAT_BUSY || vjdStatus == VJD_STAT_MISS) - goto NEXT; - if (!GetVJDAxisExist(vjDev, HID_USAGE_X)) - goto NEXT; - if (!IsDeviceFfb(vjDev)) - goto NEXT; - if ( - !IsDeviceFfbEffect(vjDev, HID_USAGE_CONST) || - !IsDeviceFfbEffect(vjDev, HID_USAGE_SINE) || - !IsDeviceFfbEffect(vjDev, HID_USAGE_DMPR) || - !IsDeviceFfbEffect(vjDev, HID_USAGE_FRIC) || - !IsDeviceFfbEffect(vjDev, HID_USAGE_SPRNG) - ) { - text(L"vjDev %d: Not all required FFB effects are enabled", vjDev); - text(L"Enable all FFB effects to use this device"); - goto NEXT; - } - break; - -NEXT: - vjDev++; - - } - - if (vjDev > maxVjDev) { - text(L"Failed to find suitable vJoy device!"); - text(L"Create a device with an X axis and all FFB effects enabled"); - return false; - } - - memset(&ffbPacket, 0 ,sizeof(ffbPacket)); - - if (vjdStatus == VJD_STAT_OWN) { - RelinquishVJD(vjDev); - vjdStatus = GetVJDStatus(vjDev); - } - if (vjdStatus == VJD_STAT_FREE) { - if (!AcquireVJD(vjDev, ffbEvent, &ffbPacket)) { - text(L"Failed to acquire vJoy device %d!", vjDev); - return false; - } - } - else { - text(L"ERROR: vJoy device %d status is %d", vjDev, vjdStatus); - return false; - } - - vjButtons = GetVJDButtonNumber(vjDev); - vjPov = GetVJDContPovNumber(vjDev); - vjPov += GetVJDDiscPovNumber(vjDev); - - text(L"Acquired vJoy device %d", vjDev); - ResetVJD(vjDev); - - return true; + SHORT verDrv; + int maxVjDev; + VjdStat vjdStatus = VJD_STAT_UNKN; + + if (!vJoyEnabled()) { + text(L"vJoy not enabled!"); + return false; + } + else { + verDrv = GetvJoyVersion(); + text(L"vJoy driver version %04x init OK", verDrv); + } + + + vjDev = 1; + + if (!GetvJoyMaxDevices(&maxVjDev)) { + text(L"Failed to determine max number of vJoy devices"); + return false; + } + + while (vjDev <= maxVjDev) { + + vjdStatus = GetVJDStatus(vjDev); + + if (vjdStatus == VJD_STAT_BUSY || vjdStatus == VJD_STAT_MISS) + goto NEXT; + if (!GetVJDAxisExist(vjDev, HID_USAGE_X)) + goto NEXT; + if (!IsDeviceFfb(vjDev)) + goto NEXT; + if ( + !IsDeviceFfbEffect(vjDev, HID_USAGE_CONST) || + !IsDeviceFfbEffect(vjDev, HID_USAGE_SINE) || + !IsDeviceFfbEffect(vjDev, HID_USAGE_DMPR) || + !IsDeviceFfbEffect(vjDev, HID_USAGE_FRIC) || + !IsDeviceFfbEffect(vjDev, HID_USAGE_SPRNG) + ) { + text(L"vjDev %d: Not all required FFB effects are enabled", vjDev); + text(L"Enable all FFB effects to use this device"); + goto NEXT; + } + break; + + NEXT: + vjDev++; + + } + + if (vjDev > maxVjDev) { + text(L"Failed to find suitable vJoy device!"); + text(L"Create a device with an X axis and all FFB effects enabled"); + return false; + } + + memset(&ffbPacket, 0, sizeof(ffbPacket)); + + if (vjdStatus == VJD_STAT_OWN) { + RelinquishVJD(vjDev); + vjdStatus = GetVJDStatus(vjDev); + } + if (vjdStatus == VJD_STAT_FREE) { + if (!AcquireVJD(vjDev, ffbEvent, &ffbPacket)) { + text(L"Failed to acquire vJoy device %d!", vjDev); + return false; + } + } + else { + text(L"ERROR: vJoy device %d status is %d", vjDev, vjdStatus); + return false; + } + + vjButtons = GetVJDButtonNumber(vjDev); + vjPov = GetVJDContPovNumber(vjDev); + vjPov += GetVJDDiscPovNumber(vjDev); + + text(L"Acquired vJoy device %d", vjDev); + ResetVJD(vjDev); + + return true; } void initAll() { - initVJD(); - initDirectInput(); + initVJD(); + initDirectInput(); } void releaseAll() { - releaseDirectInput(); - - if (fan) - fan->setSpeed(0); + releaseDirectInput(); - RelinquishVJD(vjDev); + RelinquishVJD(vjDev); - irsdk_shutdown(); + irsdk_shutdown(); } diff --git a/irFFB/irFFB.h b/irFFB/irFFB.h index 24fb883..d01d1d5 100644 --- a/irFFB/irFFB.h +++ b/irFFB/irFFB.h @@ -21,14 +21,14 @@ along with this program. If not, see . #include "stdafx.h" #include "irsdk_defines.h" -#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken = '6595b64144ccf1df' language = '*'\"") + #define MAX_FFB_DEVICES 16 #define DI_MAX 10000 #define IR_MAX 9996 #define MINFORCE_MULTIPLIER 100 #define MIN_MAXFORCE 5 -#define MAX_MAXFORCE 300 +#define MAX_MAXFORCE 100 #define BUMPSFORCE_MULTIPLIER 1.6f #define LOADFORCE_MULTIPLIER 0.08f #define LONGLOAD_STDPOWER 4 @@ -41,9 +41,9 @@ along with this program. If not, see . #define DIRECT_INTERP_SAMPLES 6 #define SETTINGS_KEY L"Software\\irFFB\\Settings" #define RUN_ON_STARTUP_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Run" -#define INI_PATH L"\\irFFB.ini" -#define INI_SCAN_FORMAT "%[^:]:%d:%d:%d:%f:%f:%d:%d:%f:%f:%f:%f" -#define INI_PRINT_FORMAT "%s:%d:%d:%d:%0.1f:%0.1f:%d:%d:%0.1f:%0.1f:%0.1f:%0.1f\r" +#define INI_PATH L"irFFB.ini" +#define INI_SCAN_FORMAT "%[^:]:%d:%d:%d:%f:%f:%d:%d:%f:%f:%f:%f:%f:%f" +#define INI_PRINT_FORMAT "%s:%d:%d:%d:%0.1f:%0.1f:%d:%d:%0.1f:%0.1f:%0.1f:%0.1f:%0.1f:%0.1f\r" #define MAX_CAR_NAME 32 #define MAX_LATENCY_TIMES 32 #define LATENCY_MIN_DX 60 @@ -53,6 +53,8 @@ along with this program. If not, see . #define EDIT_INT 0 #define EDIT_FLOAT 1 #define ID_TRAY_EXIT 40000 +#define ID_MAXFORCE_UP 1 +#define ID_MAXFORCE_DOWN 2 #define SVCNAME L"irFFBsvc" #define CMDLINE_HGSVC L"service" @@ -70,6 +72,17 @@ along with this program. If not, see . #define LOGI_WHEEL_HID_CMD "\x00\xf8\x81\x84\x03\x00\x00\x00\x00" #define LOGI_WHEEL_HID_CMD_LEN 9 +#define OVERLAY_WINDOW_HEIGHT 41 + +extern "C" NTSYSAPI NTSTATUS NTAPI NtSetTimerResolution(ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution); + +extern "C" NTSYSAPI NTSTATUS NTAPI NtQueryTimerResolution(PULONG MininumResolution, PULONG MaximumResolution, PULONG CurrentResolution); + +typedef LONG NTSTATUS, * PNTSTATUS; +#define STATUS_SUCCESS (0x00000000) + +typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + enum ffbType { FFBTYPE_360HZ, FFBTYPE_360HZ_INTERP, @@ -82,6 +95,8 @@ typedef struct sWins { HWND trackbar; HWND label; HWND value; + float min; + float max; } sWins_t; struct LogiRpmData { @@ -102,17 +117,30 @@ struct understeerCoefs { float latAccelDiv; }; +RTL_OSVERSIONINFOW GetRealOSVersion(); + DWORD WINAPI readWheelThread(LPVOID); DWORD WINAPI directFFBThread(LPVOID); ATOM MyRegisterClass(HINSTANCE); + BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK myNcHitTest(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR); +LRESULT CALLBACK myPaint(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK WndProcOverlay(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); HWND combo(HWND, wchar_t *, int, int); sWins_t *slider(HWND, wchar_t *, int, int, wchar_t *, wchar_t *, bool); -HWND checkbox(HWND, wchar_t *, int, int); +HWND slider(HWND, wchar_t*, int, int, int, int, int, int); +HWND checkbox(HWND, wchar_t *, int, int, int, int); +HWND groupox(HWND, wchar_t*, int, int, int, int); +HWND progressbar(HWND, wchar_t*, int, int, int, int, int); + +void ActivateOverLayWindow(); +void DeActivateOverlayWindow(); +void CreateOverlayWindow(HINSTANCE); bool initVJD(); void text(wchar_t *, ...); @@ -127,6 +155,7 @@ void initDirectInput(); void releaseDirectInput(); void reacquireDIDevice(); inline void sleepSpinUntil(PLARGE_INTEGER, UINT, UINT); +inline void nanosleep(LONGLONG); inline int scaleTorque(float); inline void setFFB(int); void initAll(); diff --git a/irFFB/irFFB.rc b/irFFB/irFFB.rc index 6a4e128..46a6d03 100644 Binary files a/irFFB/irFFB.rc and b/irFFB/irFFB.rc differ diff --git a/irFFB/irFFB.vcxproj b/irFFB/irFFB.vcxproj index 58e9451..afa1fa9 100644 --- a/irFFB/irFFB.vcxproj +++ b/irFFB/irFFB.vcxproj @@ -34,9 +34,9 @@ Application false - v142 true Unicode + v142 Application @@ -75,6 +75,7 @@ true + $(ProjectName)64 true @@ -83,6 +84,7 @@ false + $(ProjectName)64 @@ -92,11 +94,13 @@ Disabled WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) All + stdcpp17 + stdc17 Windows true - dxguid.lib;dinput8.lib;shlwapi.lib;wbemuuid.lib;comctl32.lib;winhttp.lib;%(AdditionalDependencies) + dxguid.lib;dinput8.lib;shlwapi.lib;wbemuuid.lib;comctl32.lib;winhttp.lib;ntdll.lib;Version.lib;dwmapi.lib;%(AdditionalDependencies) @@ -106,10 +110,13 @@ Level3 Disabled _DEBUG;_WINDOWS;%(PreprocessorDefinitions) + stdcpp17 + stdc17 Windows true + dxguid.lib;dinput8.lib;shlwapi.lib;wbemuuid.lib;comctl32.lib;winhttp.lib;ntdll.lib;dwmapi.lib;%(AdditionalDependencies) @@ -128,13 +135,16 @@ All StreamingSIMDExtensions2 None + stdcpp17 + /Zc:strictStrings- %(AdditionalOptions) + stdc17 Windows No true true - dxguid.lib;dinput8.lib;shlwapi.lib;wbemuuid.lib;comctl32.lib;winhttp.lib;%(AdditionalDependencies) + dxguid.lib;dinput8.lib;shlwapi.lib;wbemuuid.lib;comctl32.lib;winhttp.lib;ntdll.lib;dwmapi.lib;%(AdditionalDependencies) NoErrorReport UseLinkTimeCodeGeneration true @@ -149,30 +159,26 @@ true true NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + stdcpp17 + stdc17 Windows true true true + dxguid.lib;dinput8.lib;shlwapi.lib;wbemuuid.lib;comctl32.lib;winhttp.lib;ntdll.lib;dwmapi.lib;%(AdditionalDependencies) - - - - - - - @@ -190,12 +196,6 @@ - - - Document - - - diff --git a/irFFB/irFFB.vcxproj.filters b/irFFB/irFFB.vcxproj.filters index f91a12c..eb42c73 100644 --- a/irFFB/irFFB.vcxproj.filters +++ b/irFFB/irFFB.vcxproj.filters @@ -30,18 +30,9 @@ Source Files - - Source Files - - - Source Files - Source Files - - Source Files - @@ -68,21 +59,9 @@ Header Files - - Header Files - - - Header Files - - - Header Files - Header Files - - Header Files - @@ -97,10 +76,4 @@ Resource Files - - - Resource Files - - - \ No newline at end of file diff --git a/irFFB/irsdk_utils.cpp b/irFFB/irsdk_utils.cpp index 819e31f..ca071c8 100644 --- a/irFFB/irsdk_utils.cpp +++ b/irFFB/irsdk_utils.cpp @@ -322,7 +322,7 @@ unsigned int irsdk_getBroadcastMsgID() void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, int var2, int var3) { - irsdk_broadcastMsg(msg, var1, MAKELONG(var2, var3)); + irsdk_broadcastMsg(msg, var1, (int)MAKELONG(var2, var3)); } void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, float var2) diff --git a/irFFB/jetseat.cpp b/irFFB/jetseat.cpp deleted file mode 100644 index 91e49ff..0000000 --- a/irFFB/jetseat.cpp +++ /dev/null @@ -1,600 +0,0 @@ -#include "jetseat.h" - -JetSeat *JetSeat::instance = nullptr; - -JetSeat *JetSeat::init() { - - JetSeat *js = new JetSeat(); - if (js->initialise()) - return js; - - return nullptr; - -} - -JetSeat::JetSeat() { - instance = this; -} - -JetSeat::~JetSeat() { - - UINT status; - - if (FAILED(jetseat->uwGetStatus(&status))) - return; - - if (status == UW_STATUS_IN_USE) - jetseat->uwClose(); - -} - -bool JetSeat::initialise() { - - readSettings(); - - if (FAILED(CoInitializeEx(0, COINIT_MULTITHREADED))) - return false; - - CoInitializeSecurity( - NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, - RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL - ); - - HRESULT hr = CoCreateInstance(CLSID_Uberwoorf, NULL, CLSCTX_ALL, IID_IUberwoorf, (void **)&jetseat); - if (FAILED(hr)) - return false; - - if (enabled) - return open(); - - return true; - -} - -bool JetSeat::open() { - - UINT uwOpenStatus; - if (FAILED(jetseat->uwOpen(&uwOpenStatus))) { - text(L"JetSeat found but open failed"); - return false; - } - - jetseat->uwReset(); - text(L"JetSeat init OK"); - return initEffects(); - -} - -bool JetSeat::initEffects() { - - effect_handles[GW_LEG_LEFT] = createEffect(UW_SIT_LEFT); - effect_handles[GW_LEG_RIGHT] = createEffect(UW_SIT_RIGHT); - effect_handles[GW_LEG_BOTH] = createEffect(UW_SIT); - effect_handles[GW_SLIDE_LEFT] = createSlideEffect(UW_SIT_LEFT); - effect_handles[GW_SLIDE_RIGHT] = createSlideEffect(UW_SIT_RIGHT); - effect_handles[GW_ALL_LEFT] = createEffect(UW_LEFT); - effect_handles[GW_ALL_RIGHT] = createEffect(UW_RIGHT); - effect_handles[GW_ALL_BOTH] = createEffect(UW_ALL_ZONES); - effect_handles[GW_BACK_LEFT] = createEffect(UW_BACK_LOW_LEFT); - effect_handles[GW_BACK_RIGHT] = createEffect(UW_BACK_LOW_RIGHT); - effect_handles[GW_BACK_BOTH] = createEffect(UW_BACK_LOW); - - for (int i = GW_LEG_LEFT; i <= GW_BACK_BOTH; i++) - if (effect_handles[i] < 0) { - text(L"Create effect %d failed\n", i); - return false; - } - - createEngineEffect(); - - text(L"JetSeat effects initialised"); - startEffect(GW_BACK_BOTH, 100, 1); - - return true; - -} - -ATOM JetSeat::registerClass(HINSTANCE hInstance) { - - WNDCLASSEXW wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = wndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_IRFFB)); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = windowClass; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); - - return RegisterClassExW(&wcex); - -} - -void JetSeat::effectControls( - wchar_t *effect, int x, int y, HWND *placeWnd, sWins_t *gainWnd, HINSTANCE hInst -) { - - wchar_t gain[64]; - swprintf_s(gain, L"%s gain:", effect); - - if (placeWnd != nullptr) { - - wchar_t eff[64]; - swprintf_s(eff, L"%s effect location:", effect); - - CreateWindowW( - L"STATIC", eff, - WS_CHILD | WS_VISIBLE, - x, y, 200, 20, mainWnd, NULL, hInst, NULL - ); - - *placeWnd = CreateWindow( - L"COMBOBOX", nullptr, - CBS_DROPDOWN | WS_CHILD | WS_VISIBLE | WS_TABSTOP, - x, y + 40, 200, 100, mainWnd, nullptr, hInst, nullptr - ); - - for (int i = 0; i <= ALL; i++) - SendMessage(*placeWnd, CB_ADDSTRING, 0, LPARAM(effectPlaces[i])); - - } - - gainWnd->value = CreateWindowW( - L"STATIC", gain, - WS_CHILD | WS_VISIBLE, - x + 256, y, 200, 20, mainWnd, NULL, hInst, NULL - ); - - gainWnd->trackbar = CreateWindowEx( - 0, TRACKBAR_CLASS, gain, - WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_TOOLTIPS | TBS_TRANSPARENTBKGND, - x + 256, y + 40, 320, 30, - mainWnd, NULL, hInst, NULL - ); - - HWND buddyLeft = CreateWindowEx( - 0, L"STATIC", L"0", - SS_LEFT | WS_CHILD | WS_VISIBLE, - 0, 0, 20, 20, mainWnd, NULL, hInst, NULL - ); - - SendMessage(gainWnd->trackbar, TBM_SETBUDDY, (WPARAM)TRUE, (LPARAM)buddyLeft); - - HWND buddyRight = CreateWindowEx( - 0, L"STATIC", L"100", - SS_RIGHT | WS_CHILD | WS_VISIBLE, - 0, 0, 30, 20, mainWnd, NULL, hInst, NULL - ); - - SendMessage(gainWnd->trackbar, TBM_SETBUDDY, (WPARAM)FALSE, (LPARAM)buddyRight); - -} - -void JetSeat::createWindow(HINSTANCE hInst) { - - if (!classIsRegistered) { - registerClass(hInst); - classIsRegistered = true; - } - - mainWnd = CreateWindowW( - windowClass, windowClass, WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, - CW_USEDEFAULT, CW_USEDEFAULT, 712, 480, - NULL, NULL, hInst, NULL - ); - - if (!mainWnd) - return; - - enableWnd = CreateWindowEx( - 0, L"BUTTON", L"Enable irFFB control", - BS_CHECKBOX | BS_MULTILINE | WS_CHILD | WS_VISIBLE, - 40, 260, 180, 58, mainWnd, nullptr, hInst, nullptr - ); - effectControls(L"Engine", 40, 30, &enginePlaceWnd, &engineGainWnd, hInst); - effectControls(L"Gear shift", 40, 130, &gearPlaceWnd, &gearGainWnd, hInst); - effectControls(L"Bumps", 40, 230, nullptr, &bumpsGainWnd, hInst); - effectControls(L"Slide", 40, 330, nullptr, &yawGainWnd, hInst); - - readSettings(); - - ShowWindow(mainWnd, SW_SHOWNORMAL); - UpdateWindow(mainWnd); - - return; - -} - -LRESULT CALLBACK JetSeat::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - - switch (message) { - - case WM_COMMAND: { - int wmId = LOWORD(wParam); - switch (wmId) { - case IDM_EXIT: - DestroyWindow(hWnd); - break; - default: - if (HIWORD(wParam) == CBN_SELCHANGE) { - if ((HWND)lParam == instance->gearPlaceWnd) - instance->setGearPlace(SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0)); - else if ((HWND)lParam == instance->enginePlaceWnd) { - instance->setEnginePlace(SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0)); - } - } - else if (HIWORD(wParam) == BN_CLICKED) { - bool oldValue = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED; - if ((HWND)lParam == instance->enableWnd) - instance->setEnabled(!oldValue); - } - break; - } - } - break; - - case WM_HSCROLL: { - if ((HWND)lParam == instance->gearGainWnd.trackbar) - instance->gearGain = (float)(SendMessage((HWND)lParam, TBM_GETPOS, 0, 0)); - else if ((HWND)lParam == instance->bumpsGainWnd.trackbar) - instance->bumpsGain = (float)(SendMessage((HWND)lParam, TBM_GETPOS, 0, 0)); - else if ((HWND)lParam == instance->engineGainWnd.trackbar) - instance->engineGain = (float)(SendMessage((HWND)lParam, TBM_GETPOS, 0, 0)); - else if ((HWND)lParam == instance->yawGainWnd.trackbar) - instance->yawGain = (float)(SendMessage((HWND)lParam, TBM_GETPOS, 0, 0)); - } - break; - - case WM_CTLCOLORSTATIC: { - SetBkColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); - return (LRESULT)CreateSolidBrush(RGB(0xff, 0xff, 0xff)); - } - break; - - case WM_PAINT: { - PAINTSTRUCT ps; - BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - break; - - case WM_DESTROY: { - instance->writeSettings(); - } - break; - - default: - return DefWindowProc(hWnd, message, wParam, lParam); - - } - - return 0; - -} - -void JetSeat::setGearPlace(int loc) { - SendMessage(gearPlaceWnd, CB_SETCURSEL, loc, 0); - gearPlace = effectLocation(loc); -} -int JetSeat::getGearPlace() { - return effectSetting(gearPlace); -} - -void JetSeat::setEnginePlace(int loc) { - SendMessage(enginePlaceWnd, CB_SETCURSEL, loc, 0); - enginePlace = effectLocation(loc); - switch (enginePlace) { - case GW_LEG_BOTH: { - engineLeft = UW_SIT_LEFT; - engineRight = UW_SIT_RIGHT; - } - break; - case GW_BACK_BOTH: { - engineLeft = UW_BACK_LOW_LEFT; - engineRight = UW_BACK_LOW_RIGHT; - } - break; - case GW_ALL_BOTH: { - engineLeft = UW_LEFT; - engineRight = UW_RIGHT; - } - break; - } - if (engineOn) - stopEngineEffect(); -} -int JetSeat::getEnginePlace() { - return effectSetting(enginePlace); -} - -void JetSeat::setGearGain(float gain) { - gearGain = gain; - SendMessage(gearGainWnd.trackbar, TBM_SETPOS, TRUE, (int)gain); - SendMessage(gearGainWnd.trackbar, TBM_SETPOSNOTIFY, 0, (int)gain); - swprintf_s(strbuf, L"Gear shift gain [ %d ]", (int)gain); - SendMessage(gearGainWnd.value, WM_SETTEXT, NULL, LPARAM(strbuf)); -} -void JetSeat::setEngineGain(float gain) { - engineGain = gain; - SendMessage(engineGainWnd.trackbar, TBM_SETPOS, TRUE, (int)gain); - SendMessage(engineGainWnd.trackbar, TBM_SETPOSNOTIFY, 0, (int)gain); - swprintf_s(strbuf, L"Engine gain [ %d ]", (int)gain); - SendMessage(engineGainWnd.value, WM_SETTEXT, NULL, LPARAM(strbuf)); -} -void JetSeat::setBumpsGain(float gain) { - bumpsGain = gain; - SendMessage(bumpsGainWnd.trackbar, TBM_SETPOS, TRUE, (int)gain); - SendMessage(bumpsGainWnd.trackbar, TBM_SETPOSNOTIFY, 0, (int)gain); - swprintf_s(strbuf, L"Bumps gain [ %d ]", (int)gain); - SendMessage(bumpsGainWnd.value, WM_SETTEXT, NULL, LPARAM(strbuf)); -} -void JetSeat::setYawGain(float gain) { - yawGain = gain; - SendMessage(yawGainWnd.trackbar, TBM_SETPOS, TRUE, (int)gain); - SendMessage(yawGainWnd.trackbar, TBM_SETPOSNOTIFY, 0, (int)gain); - swprintf_s(strbuf, L"Slide gain [ %d ]", (int)gain); - SendMessage(yawGainWnd.value, WM_SETTEXT, NULL, LPARAM(strbuf)); -} - -void JetSeat::setEnabled(bool en) { - - UINT status; - - enabled = en; - SendMessage(enableWnd, BM_SETCHECK, en ? BST_CHECKED : BST_UNCHECKED, NULL); - EnableWindow(gearPlaceWnd, en); - EnableWindow(gearGainWnd.trackbar, en); - EnableWindow(gearGainWnd.value, en); - EnableWindow(enginePlaceWnd, en); - EnableWindow(engineGainWnd.trackbar, en); - EnableWindow(engineGainWnd.value, en); - EnableWindow(bumpsGainWnd.trackbar, en); - EnableWindow(bumpsGainWnd.value, en); - EnableWindow(yawGainWnd.trackbar, en); - EnableWindow(yawGainWnd.value, en); - - if (!jetseat) - return; - - if (FAILED(jetseat->uwGetStatus(&status))) { - text(L"Failed to get JetSeat status"); - enabled = false; - return; - } - - if (!en && status == UW_STATUS_IN_USE) { - jetseat->uwClose(); - text(L"JetSeat closed"); - return; - } - - else if (en && status == UW_STATUS_READY) { - if (open()) - return; - else - enabled = false; - } - -} - -bool JetSeat::isEnabled() { - return enabled; -} - -int JetSeat::effectLocation(int idx) { - - switch (idx) { - case LEGS: return GW_LEG_BOTH; - case BACK: return GW_BACK_BOTH; - case ALL: return GW_ALL_BOTH; - } - - return GW_ALL_BOTH; - -} - -int JetSeat::effectSetting(int loc) { - - switch (loc) { - case GW_LEG_BOTH: return LEGS; - case GW_BACK_BOTH: return BACK; - case GW_ALL_BOTH: return ALL; - } - - return ALL; - -} - -int JetSeat::createEffect(UINT zones) { - - UINT handle, vib; - UINT dur[2] = { 0, 100 }; - BYTE amp[2] = { 255, 255 }; - - jetseat->uwCreateEffect(&handle); - jetseat->uwSetVibration(handle, zones, dur, amp, 2, &vib); - - return handle; - -} - -int JetSeat::createSlideEffect(UINT zones) { - - UINT handle, vib; - UINT dur[6] = { 0, 50, 50, 75, 75, 125 }; - BYTE amp[6] = { 255, 255, 0, 0, 255, 255 }; - - jetseat->uwCreateEffect(&handle); - jetseat->uwSetVibration(handle, zones, dur, amp, 6, &vib); - - return handle; - -} - -void JetSeat::createEngineEffect() { - - UINT dur[2] = { 150, 150 }; - BYTE amp[2] = { 0, 0 }; - - jetseat->uwCreateEffect(&engineEffect); - jetseat->uwSetVibration(engineEffect, engineLeft, dur, amp, 2, &engineVibL1); - jetseat->uwSetVibration(engineEffect, engineRight, dur, amp, 2, &engineVibL2); - jetseat->uwSetVibration(engineEffect, engineLeft, dur, amp, 2, &engineVibR1); - jetseat->uwSetVibration(engineEffect, engineRight, dur, amp, 2, &engineVibR2); - -} - -void JetSeat::startEffect(int effect, float gain, int count) { - - gain = minf(gain, 100); - jetseat->uwSetEffectGain(effect_handles[effect], (UINT)gain); - jetseat->uwStartEffect(effect_handles[effect], count); - -} - -void JetSeat::stopEffect(int effect) { - - jetseat->uwStopEffect(effect_handles[effect]); - -} - -void JetSeat::startEngineEffect() { - - if (engineGain == 0.0f || engineOn) - return; - jetseat->uwStartEffect(engineEffect, INFINITE); - engineOn = true; - engineCounter = 0; - -} - -void JetSeat::stopEngineEffect() { - - if (!jetseat || !engineOn) - return; - jetseat->uwStopEffect(engineEffect); - engineOn = false; - -} - -void JetSeat::updateEngineEffect(float rpmPerCent) { - - if (engineGain == 0 || !engineOn || engineCounter++ < 10) - return; - - UINT intervalsOn[2]; - UINT intervalsOff[2]; - BYTE amps[2] = { 0, 0 }; - BYTE ampsZero[2] = { 0, 0 }; - - engineCounter = 0; - - UINT on = (UINT)(rpmPerCent * 3.0f); - - if (on < 60) - on = 60; - - int amp = (int)(engineGain * 2.55f); - - int space = 150 - on; - UINT delay = space > 0 ? space >> 1 : 0; - - amps[0] = amps[1] = amp > 255 ? 255 : amp; - - intervalsOff[0] = 0; - intervalsOn[0] = delay; - intervalsOn[1] = delay + on; - intervalsOff[1] = 300 - on - delay; - - jetseat->uwUpdateVibration(engineEffect, engineVibL1, engineLeft, intervalsOn, amps, 2); - jetseat->uwUpdateVibration(engineEffect, engineVibR1, engineRight, intervalsOff, ampsZero, 2); - - intervalsOff[0] = delay + on; - intervalsOn[0] = 300 - on - delay; - intervalsOff[1] = 300; - intervalsOn[1] = 300 - delay; - jetseat->uwUpdateVibration(engineEffect, engineVibL2, engineLeft, intervalsOff, ampsZero, 2); - jetseat->uwUpdateVibration(engineEffect, engineVibR2, engineRight, intervalsOn, amps, 2); - -} - -void JetSeat::gearEffect() { - if (gearGain > 0.0f) - startEffect(gearPlace, gearGain, 1); -} - -void JetSeat::fBumpEffect(float l, float r) { - if (bumpsGain == 0.0f) - return; - startEffect(GW_LEG_LEFT, l * bumpsGain, 1); - startEffect(GW_LEG_RIGHT, r * bumpsGain, 1); -} - -void JetSeat::rBumpEffect(float l, float r) { - if (bumpsGain == 0.0f) - return; - startEffect(GW_BACK_RIGHT, l * bumpsGain, 1); - startEffect(GW_BACK_RIGHT, r * bumpsGain, 1); -} - -void JetSeat::yawEffect(float f) { - if (yawGain == 0.0f) - return; - if (f > 0.0f) - startEffect(GW_SLIDE_LEFT, f * 5.0f * yawGain, 3); - else - startEffect(GW_SLIDE_RIGHT, -f * 5.0f * yawGain, 3); -} - -void JetSeat::readSettings() { - - HKEY key = Settings::getSettingsRegKey(); - - if (key == NULL) { - setGearPlace(BACK); - setEnginePlace(ALL); - setGearGain(80); - setEngineGain(0); - setBumpsGain(80); - setYawGain(80); - setEnabled(true); - return; - } - - setGearPlace(Settings::getRegSetting(key, L"jsGearPlace", BACK)); - setEnginePlace(Settings::getRegSetting(key, L"jsEnginePlace", ALL)); - setGearGain(Settings::getRegSetting(key, L"jsGearGain", 80.0f)); - setEngineGain(Settings::getRegSetting(key, L"jsEngineGain", 0.0f)); - setBumpsGain(Settings::getRegSetting(key, L"jsBumpsGain", 80.0f)); - setYawGain(Settings::getRegSetting(key, L"jsYawGain", 80.0f)); - setEnabled(Settings::getRegSetting(key, L"jsEnabled", true)); - - RegCloseKey(key); - -} - -void JetSeat::writeSettings() { - - HKEY key = Settings::getSettingsRegKey(); - - if (key == NULL) - return; - - Settings::setRegSetting(key, L"jsGearPlace", gearPlace); - Settings::setRegSetting(key, L"jsEnginePlace", enginePlace); - Settings::setRegSetting(key, L"jsGearGain", gearGain); - Settings::setRegSetting(key, L"jsEngineGain", engineGain); - Settings::setRegSetting(key, L"jsBumpsGain", bumpsGain); - Settings::setRegSetting(key, L"jsYawGain", yawGain); - Settings::setRegSetting(key, L"jsEnabled", enabled); - - RegCloseKey(key); - -} - diff --git a/irFFB/jetseat.h b/irFFB/jetseat.h deleted file mode 100644 index 527cd40..0000000 --- a/irFFB/jetseat.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once -#include -#include -#include -#include - -#include "stdafx.h" -#include "irFFB.h" -#include "settings.h" -#include "IUberwoorf.h" - - -#define MAX_JETSEAT_EFFECTS 16 -#define GW_LEG_LEFT 1 -#define GW_LEG_RIGHT 2 -#define GW_LEG_BOTH 3 -#define GW_SLIDE_LEFT 4 -#define GW_SLIDE_RIGHT 5 -#define GW_ALL_LEFT 6 -#define GW_ALL_RIGHT 7 -#define GW_ALL_BOTH 8 -#define GW_BACK_LEFT 9 -#define GW_BACK_RIGHT 10 -#define GW_BACK_BOTH 11 - -#define LEGS 0 -#define BACK 1 -#define ALL 2 - -class JetSeat { - - public: - static JetSeat *init(); - bool isEnabled(); - void createWindow(HINSTANCE); - void startEngineEffect(); - void stopEngineEffect(); - void updateEngineEffect(float); - void gearEffect(); - void fBumpEffect(float, float); - void rBumpEffect(float, float); - void yawEffect(float); - - private: - JetSeat(); - ~JetSeat(); - bool initialise(); - bool open(); - bool initEffects(); - ATOM registerClass(HINSTANCE); - void effectControls(wchar_t *, int, int, HWND *, sWins_t *, HINSTANCE); - static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); - void setGearPlace(int); - int getGearPlace(); - void setEnginePlace(int); - int getEnginePlace(); - void setGearGain(float); - void setEngineGain(float); - void setBumpsGain(float); - void setYawGain(float); - void setEnabled(bool); - int effectLocation(int); - int effectSetting(int); - int createEffect(UINT); - int createSlideEffect(UINT); - void createEngineEffect(); - void startEffect(int, float, int); - void stopEffect(int); - void readSettings(); - void writeSettings(); - - static JetSeat *instance; - - wchar_t *windowClass = L"JetSeat Configuration"; - - HWND mainWnd, gearPlaceWnd, enginePlaceWnd, enableWnd; - sWins_t gearGainWnd, bumpsGainWnd, engineGainWnd, yawGainWnd; - - UINT effect_handles[MAX_JETSEAT_EFFECTS]; - wchar_t *effectPlaces[3] = { L"Legs", L"Back", L"All" }; - IUberwoorf *jetseat = nullptr; - UINT engineEffect, engineVibL1, engineVibL2, engineVibR1, engineVibR2; - UINT engineLeft = UW_BACK_LOW_LEFT, engineRight = UW_BACK_LOW_RIGHT; - bool enabled = true, engineOn = false, classIsRegistered = false; - - int gearPlace, enginePlace, engineCounter = 0; - float gearGain = 100, bumpsGain = 100, yawGain = 100, engineGain = 0; - wchar_t strbuf[64]; - -}; \ No newline at end of file diff --git a/irFFB/resource.h b/irFFB/resource.h index 3e62833..86b1fae 100644 --- a/irFFB/resource.h +++ b/irFFB/resource.h @@ -7,18 +7,19 @@ #define IDS_APP_TITLE 103 #define IDD_ABOUTBOX 103 #define IDM_ABOUT 104 +#define IDS_APP_TITLE_64 104 #define IDM_EXIT 105 #define IDI_IRFFB 107 #define IDI_SMALL 108 #define IDC_IRFFB 109 #define IDR_MAINFRAME 128 +#define IDC_SYSLINK1 1001 #define IDR_HIDG64 8192 #define ID_SETTINGS_JETSEAT 32774 #define ID_SETTINGS_FAN 32775 #define ID_SETTINGS_HIDGUARDIAN 32778 #define ID_SETTINGS_TRACTIONLOSS 32779 #define IDC_STATIC -1 -#define IDC_SYSLINK1 1001 // Next default values for new objects // diff --git a/irFFB/settings.cpp b/irFFB/settings.cpp index 122289e..03b2882 100644 --- a/irFFB/settings.cpp +++ b/irFFB/settings.cpp @@ -2,7 +2,9 @@ #include #include #include - +#include +#include +namespace fs = std::filesystem; HKEY Settings::getSettingsRegKey() { HKEY key; @@ -96,7 +98,7 @@ void Settings::setMinWnd(sWins_t *wnd) { void Settings::setMaxWnd(sWins_t *wnd) { maxWnd = wnd; - SendMessage(maxWnd->trackbar, TBM_SETRANGE, TRUE, MAKELPARAM(MIN_MAXFORCE, 65)); + SendMessage(maxWnd->trackbar, TBM_SETRANGE, TRUE, MAKELPARAM(MIN_MAXFORCE, 100)); } void Settings::setBumpsWnd(sWins_t *wnd) { bumpsWnd = wnd; } @@ -105,12 +107,24 @@ void Settings::setSopWnd(sWins_t *wnd) { sopWnd = wnd; } void Settings::setSopOffsetWnd(sWins_t *wnd) { sopOffsetWnd = wnd; } void Settings::setUndersteerWnd(sWins_t *wnd) { understeerWnd = wnd; } void Settings::setUndersteerOffsetWnd(sWins_t *wnd) { understeerOffsetWnd = wnd; } +void Settings::setUndersteerYawRateMultWnd(sWins_t* wnd) { understeerYawRateMultWnd = wnd; } +void Settings::setUndersteerlatAccelDivWnd(sWins_t* wnd) { understeerlatAccelDivWnd = wnd; } +void Settings::setOverlayTransparencyWnd(sWins_t* wnd) { overlayTransparencyWnd = wnd;} void Settings::setUse360Wnd(HWND wnd) { use360Wnd = wnd; } void Settings::setReduceWhenParkedWnd(HWND wnd) { reduceWhenParkedWnd = wnd; } void Settings::setCarSpecificWnd(HWND wnd) { carSpecificWnd = wnd; } void Settings::setRunOnStartupWnd(HWND wnd) { runOnStartupWnd = wnd; } void Settings::setStartMinimisedWnd(HWND wnd) { startMinimisedWnd = wnd; } void Settings::setDebugWnd(HWND wnd) { debugWnd = wnd; } +void Settings::setAltTimerWnd(HWND wnd) { altTimerWnd = wnd; } +void Settings::setForceOverlayWnd(HWND wnd) { forceOverlayWnd = wnd; } + +void Settings::setOverlayMaxForceWnd(HWND wnd) +{ + overlayMaxForceWnd = wnd; + SendMessage(overlayMaxForceWnd, TBM_SETRANGE, TRUE, MAKELPARAM(MIN_MAXFORCE, 65)); +} + void Settings::clearFfbDevices() { memset(ffdevices, 0, sizeof(ffdevices)); @@ -178,6 +192,7 @@ bool Settings::setMaxForce(int max, HWND wnd) { swprintf_s(strbuf, L"%d", max); SendMessage(maxWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); } + SendMessage(getOverlayMaxForceWnd(), TBM_SETPOS, TRUE, maxForce); scaleFactor = (float)DI_MAX / maxForce; irsdk_broadcastMsg( irsdk_BroadcastFFBCommand, irsdk_FFBCommand_MaxForce, (float)maxForce @@ -264,6 +279,63 @@ bool Settings::setUndersteerOffset(float offset, HWND wnd) { return true; } +bool Settings::setUndersteerYawRateMult(float mul, HWND wnd) +{ + if (mul < understeerYawRateMultWnd->min || mul > understeerYawRateMultWnd->max) + return false; + + understeerYawRateMult = mul; + if (wnd != understeerYawRateMultWnd->trackbar) + SendMessage(understeerYawRateMultWnd->trackbar, TBM_SETPOS, TRUE, (int)mul); + if (wnd != understeerYawRateMultWnd->value) { + swprintf_s(strbuf, L"%.1f", mul); + SendMessage(understeerYawRateMultWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); + } + return true; +} + +bool Settings::setUndersteerlatAccelDiv(float div, HWND wnd) +{ + if (div < understeerlatAccelDivWnd->min || div > understeerlatAccelDivWnd->max) + return false; + understeerlatAccelDiv = div; + if (wnd != understeerlatAccelDivWnd->trackbar) + SendMessage(understeerlatAccelDivWnd->trackbar, TBM_SETPOS, TRUE, (int)div); + if (wnd != understeerlatAccelDivWnd->value) { + swprintf_s(strbuf, L"%.1f", div); + SendMessage(understeerlatAccelDivWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); + } + return true; +} + +bool Settings::setOverlayTransparency(float transparency, HWND wnd) +{ + if (transparency < overlayTransparencyWnd->min || transparency > overlayTransparencyWnd->max) + return false; + overlayTransparency = transparency; + if (wnd != overlayTransparencyWnd->trackbar) + SendMessage(overlayTransparencyWnd->trackbar, TBM_SETPOS, TRUE, (int)transparency); + if (wnd != overlayTransparencyWnd->value) { + swprintf_s(strbuf, L"%.1f", transparency); + SendMessage(overlayTransparencyWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); + } + return true; +} + +void Settings::enableOverlayTransparencyWnd() +{ + EnableWindow(overlayTransparencyWnd->label, TRUE); + EnableWindow(overlayTransparencyWnd->value, TRUE); + EnableWindow(overlayTransparencyWnd->trackbar, TRUE); +} + +void Settings::disableOverlayTransparencyWnd() +{ + EnableWindow(overlayTransparencyWnd->label, FALSE); + EnableWindow(overlayTransparencyWnd->value, FALSE); + EnableWindow(overlayTransparencyWnd->trackbar, FALSE); +} + void Settings::setUse360ForDirect(bool set) { use360ForDirect = set; SendMessage(use360Wnd, BM_SETCHECK, set ? BST_CHECKED : BST_UNCHECKED, NULL); @@ -287,7 +359,6 @@ void Settings::setUseCarSpecific(bool set, char *car) { useCarSpecific = set; SendMessage(carSpecificWnd, BM_SETCHECK, set ? BST_CHECKED : BST_UNCHECKED, NULL); writeCarSpecificSetting(); - } void Settings::setReduceWhenParked(bool reduce) { @@ -331,6 +402,22 @@ void Settings::setDebug(bool enabled) { SendMessage(debugWnd, BM_SETCHECK, enabled ? BST_CHECKED : BST_UNCHECKED, NULL); } +void Settings::setUseAltTimer(bool enabled) +{ + useAltTimer = enabled; + SendMessage(altTimerWnd, BM_SETCHECK, enabled ? BST_CHECKED : BST_UNCHECKED, NULL); +} + +void Settings::setShowForceOverlay(bool enabled) +{ + showForceOverlay = enabled; + SendMessage(forceOverlayWnd, BM_SETCHECK, enabled ? BST_CHECKED : BST_UNCHECKED, NULL); + if (enabled) + enableOverlayTransparencyWnd(); + else + disableOverlayTransparencyWnd(); +} + float Settings::getBumpsSetting() { return sqrt(bumpsFactor / BUMPSFORCE_MULTIPLIER); } @@ -365,7 +452,12 @@ void Settings::readRegSettings(char *car) { setReduceWhenParked(true); setStartMinimised(false); setRunOnStartup(false); + setUseAltTimer(false); setUseCarSpecific(false, car); + setShowForceOverlay(false); + setWindowPosX(30); + setWindowPosY(30); + setOverlayTransparency(255.0f, (HWND)-1); return; } @@ -377,8 +469,12 @@ void Settings::readRegSettings(char *car) { setReduceWhenParked(getRegSetting(key, L"reduceWhenParked", true)); setRunOnStartup(getRegSetting(key, L"runOnStartup", false)); setStartMinimised(getRegSetting(key, L"startMinimised", false)); + setUseAltTimer(getRegSetting(key, L"useAltTimer", false)); setUseCarSpecific(getRegSetting(key, L"useCarSpecific", false), car); - + setShowForceOverlay(getRegSetting(key, L"showForceOverlay", false)); + setWindowPosX(getRegSetting(key, L"windowPosX", 30)); + setWindowPosY(getRegSetting(key, L"windowPosY", 30)); + setOverlayTransparency(getRegSetting(key, L"overlayTransparency", 255.0f), (HWND)-1); RegCloseKey(key); } @@ -400,6 +496,9 @@ void Settings::readGenericSettings() { setUndersteerFactor(0.0f, (HWND)-1); setUndersteerOffset(0.0f, (HWND)-1); setUse360ForDirect(true); + setUndersteerlatAccelDiv(60.0f, (HWND)-1); + setUndersteerYawRateMult(0.0f, (HWND)-1); + return; } @@ -413,7 +512,9 @@ void Settings::readGenericSettings() { setUndersteerFactor(getRegSetting(key, L"understeerFactor", 0.0f), (HWND)-1); setUndersteerOffset(getRegSetting(key, L"understeerOffset", 0.0f), (HWND)-1); setUse360ForDirect(getRegSetting(key, L"use360ForDirect", true)); - + setUndersteerlatAccelDiv(getRegSetting(key, L"understeerlatAccelDiv", 60.0f), (HWND)-1); + setUndersteerYawRateMult(getRegSetting(key, L"understeerYawRateMult", 0.0f), (HWND)-1); + RegCloseKey(key); } @@ -435,7 +536,11 @@ void Settings::writeRegSettings() { setRegSetting(key, L"reduceWhenParked", getReduceWhenParked()); setRegSetting(key, L"runOnStartup", getRunOnStartup()); setRegSetting(key, L"startMinimised", getStartMinimised()); - + setRegSetting(key, L"windowPosX", getWindowPosX()); + setRegSetting(key, L"windowPosY", getWindowPosY()); + setRegSetting(key, L"useAltTimer", getUseAltTimer()); + setRegSetting(key, L"showForceOverlay", getShowForceOverlay()); + setRegSetting(key, L"overlayTransparency", getOverlayTransparency()); RegCloseKey(key); } @@ -457,6 +562,8 @@ void Settings::writeGenericSettings() { setRegSetting(key, L"use360ForDirect", use360ForDirect); setRegSetting(key, L"understeerFactor", understeerFactor); setRegSetting(key, L"understeerOffset", understeerOffset); + setRegSetting(key, L"understeerlatAccelDiv", understeerlatAccelDiv); + setRegSetting(key, L"understeerYawRateMult", understeerYawRateMult); RegCloseKey(key); @@ -464,9 +571,9 @@ void Settings::writeGenericSettings() { void Settings::readSettingsForCar(char *car) { - PWSTR path = getIniPath(); + std::wstring path = getIniPath(); - if (path == nullptr) { + if (path.empty()) { text(L"Failed to locate documents folder, can't read ini"); return; } @@ -477,7 +584,7 @@ void Settings::readSettingsForCar(char *car) { char carName[MAX_CAR_NAME]; int type = 2, min = 0, max = 45, longLoad = 1, use360 = 1; float bumps = 0.0f, damping = 0.0f, yaw = 0.0f, yawOffset = 0.0f; - float understeer = 0.0f, understeerOffset = 0.0f; + float understeer = 0.0f, understeerOffset = 0.0f, understeerYawRateMult = 0.0f, understeerlatAccelDiv = 0.0f; memset(carName, 0, sizeof(carName)); @@ -487,7 +594,7 @@ void Settings::readSettingsForCar(char *car) { line.c_str(), INI_SCAN_FORMAT, carName, sizeof(carName), &type, &min, &max, &bumps, &damping, &longLoad, &use360, &yaw, - &yawOffset, &understeer, &understeerOffset + &yawOffset, &understeer, &understeerOffset, &understeerYawRateMult, &understeerlatAccelDiv ) < 8 ) continue; @@ -510,25 +617,25 @@ void Settings::readSettingsForCar(char *car) { setUndersteerFactor(understeer, (HWND)-1); setUndersteerOffset(understeerOffset, (HWND)-1); setUse360ForDirect(use360 > 0); - + setUndersteerYawRateMult(understeerYawRateMult, (HWND)-1); + setUndersteerlatAccelDiv(understeerlatAccelDiv, (HWND)-1); DONE: iniFile.close(); - delete[] path; } void Settings::writeSettingsForCar(char *car) { - PWSTR path = getIniPath(); + std::wstring path = getIniPath(); - if (path == nullptr) { + if (path.empty()) { text(L"Failed to locate documents folder, can't write ini"); return; } - PWSTR tmpPath = new wchar_t[lstrlen(path) + 5]; - lstrcpy(tmpPath, path); - lstrcat(tmpPath, L".tmp"); + std::wstring tmpPath(path); + tmpPath.append(L".tmp"); + std::ifstream iniFile(path); std::ofstream tmpFile(tmpPath); @@ -537,7 +644,7 @@ void Settings::writeSettingsForCar(char *car) { char carName[MAX_CAR_NAME], buf[256]; int type = 2, min = 0, max = 45, longLoad = 1, use360 = 1; float bumps = 0.0f, damping = 0.0f, yaw = 0.0f, yawOffset = 0.0f; - float understeer = 0.0f, understeerOffset = 0.0f; + float understeer = 0.0f, understeerOffset = 0.0f, understeerYawRateMult = 0.0f, understeerlatAccelDiv = 0.0f; bool written = false, iniPresent = iniFile.good(); text(L"Writing settings for car %s", car); @@ -553,7 +660,7 @@ void Settings::writeSettingsForCar(char *car) { line.c_str(), INI_SCAN_FORMAT, carName, sizeof(carName), &type, &min, &max, &bumps, &damping, &longLoad, &use360, - &yaw, &yawOffset, &understeer, &understeerOffset + &yaw, &yawOffset, &understeer, &understeerOffset, &understeerYawRateMult, &understeerlatAccelDiv ) < 8 ) { strcpy_s(buf, line.c_str()); @@ -569,7 +676,8 @@ void Settings::writeSettingsForCar(char *car) { buf, INI_PRINT_FORMAT, car, ffbType, getMinForceSetting(), maxForce, getBumpsSetting(), dampingFactor, 1, use360ForDirect, sopFactor, getSopOffsetSetting(), - understeerFactor, getUndersteerOffsetSetting() + understeerFactor, getUndersteerOffsetSetting(), getUndersteerYawRateMult(), + getUndersteerlatAccelDiv() ); writeWithNewline(tmpFile, buf); written = true; @@ -609,7 +717,8 @@ void Settings::writeSettingsForCar(char *car) { buf, INI_PRINT_FORMAT, car, ffbType, getMinForceSetting(), maxForce, getBumpsSetting(), dampingFactor, 1, use360ForDirect, sopFactor, getSopOffsetSetting(), - understeerFactor, getUndersteerOffsetSetting() + understeerFactor, getUndersteerOffsetSetting(), getUndersteerYawRateMult(), + getUndersteerlatAccelDiv() ); writeWithNewline(tmpFile, buf); @@ -617,11 +726,9 @@ void Settings::writeSettingsForCar(char *car) { iniFile.close(); tmpFile.close(); - if (!MoveFileEx(tmpPath, path, MOVEFILE_REPLACE_EXISTING)) + if (!MoveFileEx(tmpPath.c_str(), path.c_str(), MOVEFILE_REPLACE_EXISTING)) text(L"Failed to update ini file, error %d", GetLastError()); - delete[] path; - delete[] tmpPath; } @@ -635,50 +742,51 @@ wchar_t *Settings::ffbTypeString(int type) { } } -PWSTR Settings::getIniPath() { +std::wstring Settings::getIniPath() { PWSTR docsPath; - wchar_t *path; - if (SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &docsPath) != S_OK) - return nullptr; - - path = new wchar_t[lstrlen(docsPath) + lstrlen(INI_PATH) + 1]; + return std::wstring(L""); - lstrcpyW(path, docsPath); - lstrcatW(path, INI_PATH); + fs::path fsPath = { docsPath }; CoTaskMemFree(docsPath); + fsPath.append("irFFB"); + if (!fs::exists(fsPath)) + { + fs::create_directory(fsPath); + } - return path; - + fsPath.append(INI_PATH); + ::debug((wchar_t*)fsPath.wstring().c_str(), L""); + return fsPath.wstring(); } -PWSTR Settings::getLogPath() { +std::wstring Settings::getLogPath() { PWSTR docsPath; - wchar_t buf[64]; - wchar_t *path; SYSTEMTIME lt; if (SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &docsPath) != S_OK) - return nullptr; + return std::wstring(L""); - GetLocalTime(<); - - lstrcpyW(buf, L"\\irFFB-"); - int len = wcslen(buf) * sizeof(wchar_t); - StringCbPrintf( - buf + wcslen(buf), sizeof(buf) - len, L"%d-%02d-%02d-%02d-%02d-%02d.log", - lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond - ); + fs::path fsPath = { docsPath }; + CoTaskMemFree(docsPath); + fsPath.append("irFFB"); + fsPath.append("Log"); + if (!fs::exists(fsPath)) + { + fs::create_directories(fsPath); + } - path = new wchar_t[lstrlen(docsPath) + lstrlen(buf) + 1]; + GetLocalTime(<); - lstrcpyW(path, docsPath); - lstrcatW(path, buf); - CoTaskMemFree(docsPath); + char logfile[256]; + sprintf_s(logfile, 256, "irFFB-%d-%02d-%02d-%02d-%02d-%02d.log", lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond); + std::string fmtFileName(logfile); + fsPath.append(fmtFileName); - return path; + ::debug((wchar_t*)fsPath.wstring().c_str(), L""); + return fsPath.wstring(); } diff --git a/irFFB/stdafx.h b/irFFB/stdafx.h index 26c803f..5020314 100644 --- a/irFFB/stdafx.h +++ b/irFFB/stdafx.h @@ -7,7 +7,7 @@ #include "targetver.h" -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +//#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files: #include @@ -34,6 +34,12 @@ #include #include #include +#include +#include + +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif #define DIRECTINPUT_VERSION 0x0800 #include @@ -44,3 +50,24 @@ #include +#ifdef _UNICODE + +#if defined _M_IX86 + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#elif defined _M_IA64 + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#elif defined _M_X64 + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#else + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#endif + +#endif diff --git a/irFFB/tractionloss.cpp b/irFFB/tractionloss.cpp deleted file mode 100644 index 7a995bf..0000000 --- a/irFFB/tractionloss.cpp +++ /dev/null @@ -1,527 +0,0 @@ -#include - -#include "irFFB.h" -#include "tractionloss.h" - -TractionLoss *TractionLoss::instance = nullptr; - -TractionLoss *TractionLoss::init() { - return new TractionLoss(); -} - -TractionLoss::TractionLoss() { - - if (FAILED(CoInitializeEx(0, COINIT_MULTITHREADED))) - return; - - CoInitializeSecurity( - NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, - RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL - ); - - instance = this; - readSettings(); - enumSerialPorts(); - -} - -ATOM TractionLoss::registerClass(HINSTANCE hInstance) { - - WNDCLASSEXW wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = wndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_IRFFB)); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = windowClass; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); - - return RegisterClassExW(&wcex); - -} - -void TractionLoss::createWindow(HINSTANCE hInst) { - - if (!classIsRegistered) { - registerClass(hInst); - classIsRegistered = true; - } - - mainWnd = CreateWindowW( - windowClass, windowClass, WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, - CW_USEDEFAULT, CW_USEDEFAULT, 440, 360, - NULL, NULL, hInst, NULL - ); - - if (!mainWnd) - return; - - portWnd = combo(mainWnd, L"TL controller port:", 40, 40); - minAngleWnd = slider(mainWnd, L"Min angle:", 40, 120, L"0", L"50", false); - SendMessage(minAngleWnd->trackbar, TBM_SETRANGE, TRUE, MAKELPARAM(0, 50)); - stepsPerDegWnd = slider(mainWnd, L"Steps per deg:", 40, 200, L"0", L"500", false); - SendMessage(stepsPerDegWnd->trackbar, TBM_SETRANGE, TRUE, MAKELPARAM(0, 500)); - - ShowWindow(mainWnd, SW_SHOWNORMAL); - UpdateWindow(mainWnd); - enumSerialPorts(); - readSettings(); - - return; - -} - -LRESULT CALLBACK TractionLoss::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - - HWND wnd = (HWND)lParam; - - switch (message) { - - case WM_COMMAND: { - int wmId = LOWORD(wParam); - switch (wmId) { - case IDM_EXIT: - DestroyWindow(hWnd); - break; - default: - if (HIWORD(wParam) == CBN_SELCHANGE) { - if (wnd == instance->portWnd) { - int idx = (int)SendMessage(wnd, CB_GETCURSEL, 0, 0); - if (idx >= 0 && idx < instance->numPorts) { - instance->tlPort = instance->ports[idx].dev; - instance->initPort(); - } - } - } - break; - } - } - - case WM_HSCROLL: { - if (wnd == instance->minAngleWnd->trackbar) { - wchar_t strbuf[8]; - int angle = SendMessage(wnd, TBM_GETPOS, 0, 0); - swprintf_s(strbuf, L"%d", angle); - instance->setMinAngle(angle); - SendMessage(instance->minAngleWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); - } - else if (wnd == instance->stepsPerDegWnd->trackbar) { - wchar_t strbuf[8]; - int steps = SendMessage(wnd, TBM_GETPOS, 0, 0); - swprintf_s(strbuf, L"%d", steps); - instance->setStepsPerDeg(steps); - SendMessage(instance->stepsPerDegWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); - } - } - break; - - case WM_EDIT_VALUE: { - if (wnd == instance->minAngleWnd->value) { - instance->setMinAngle(wParam); - SendMessage(instance->minAngleWnd->trackbar, TBM_SETPOS, true, wParam); - } - else if (wnd == instance->stepsPerDegWnd->value) { - instance->setStepsPerDeg(wParam); - SendMessage(instance->stepsPerDegWnd->trackbar, TBM_SETPOS, true, wParam); - } - } - break; - - case WM_CTLCOLORSTATIC: { - SetBkColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); - return (LRESULT)CreateSolidBrush(RGB(0xff, 0xff, 0xff)); - } - break; - - case WM_PAINT: { - PAINTSTRUCT ps; - BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - break; - - case WM_DESTROY: { - instance->writeSettings(); - } - break; - - default: - return DefWindowProc(hWnd, message, wParam, lParam); - - } - - return 0; - -} - -void TractionLoss::setMinAngle(int angle) { - if (angle < 0 || angle > 50) return; - minAngle = angle / 10.0f; - if (minAngleWnd == nullptr) return; - SendMessage(minAngleWnd->trackbar, TBM_SETPOS, TRUE, angle); - swprintf_s(strbuf, L"%d", angle); - SendMessage(minAngleWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); -} - -void TractionLoss::setStepsPerDeg(int steps) { - if (steps < 0 || steps > 500) return; - stepsPerDeg = steps / 10.0f; - if (stepsPerDegWnd == nullptr) return; - SendMessage(stepsPerDegWnd->trackbar, TBM_SETPOS, TRUE, steps); - swprintf_s(strbuf, L"%d", steps); - SendMessage(stepsPerDegWnd->value, WM_SETTEXT, NULL, LPARAM(strbuf)); -} - - -void TractionLoss::enumSerialPorts() { - - UINT portsSize = numPorts = 0; - - IWbemLocator *locator = NULL; - if ( - FAILED( - CoCreateInstance( - CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, - IID_IWbemLocator, reinterpret_cast(&locator) - ) - ) - ) { - text(L"Failed to CoCreateInstance of WbemLocator"); - return; - } - - IWbemServices *services = NULL; - if ( - FAILED( - locator->ConnectServer( - _bstr_t("\\\\.\\root\\cimv2"), NULL, NULL, NULL, 0, NULL, NULL, &services - ) - ) - ) { - text(L"Failed to connect to cimv2 server"); - locator->Release(); - return; - } - - IEnumWbemClassObject *classObject = NULL; - HRESULT hr = services->ExecQuery( - _bstr_t("WQL"), _bstr_t("SELECT * FROM Win32_SerialPort"), - WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &classObject - ); - - if (FAILED(hr)) { - _com_error err(hr); - text(L"SerialPort query failed: %s", err.ErrorMessage()); - services->Release(); - locator->Release(); - return; - } - - hr = WBEM_S_NO_ERROR; - - while (hr == WBEM_S_NO_ERROR) { - - ULONG num = 0; - IWbemClassObject *obj[16]; - - if ( - SUCCEEDED( - classObject->Next( - WBEM_INFINITE, 16, reinterpret_cast(obj), &num - ) - ) - ) { - - UINT i = 0; - - if (num == 0) - break; - - portsSize += sizeof(port) * num; - ports = (port *)realloc(ports, portsSize); - - for (ULONG n = 0; n < num; n++) { - - VARIANT name; - HRESULT hrGet = obj[n]->Get(L"DeviceID", 0, &name, NULL, NULL); - - if ( - SUCCEEDED(hrGet) && (name.vt == VT_BSTR) && (wcslen(name.bstrVal) > 3) - ) { - - if (_wcsnicmp(name.bstrVal, L"COM", 3) != 0) - continue; - - VARIANT fname; - ports[numPorts + i].dev = (wchar_t *)malloc((lstrlen(name.bstrVal) + 5) * sizeof(wchar_t)); - lstrcpy(ports[numPorts + i].dev, L"\\\\.\\"); - lstrcat(ports[numPorts + i].dev, name.bstrVal); - if ( - FAILED(obj[n]->Get(L"Name", 0, &fname, NULL, NULL)) || - fname.vt != VT_BSTR - ) - ports[numPorts + i].name = StrDupW(name.bstrVal); - else - ports[numPorts + i].name = StrDupW(fname.bstrVal); - - SendMessage( - portWnd, CB_ADDSTRING, 0, - LPARAM(ports[numPorts + i].name) - ); - - if (tlPort != nullptr && _wcsnicmp(ports[numPorts + i].dev, tlPort, 128) == 0) { - SendMessage((HWND)portWnd, CB_SETCURSEL, numPorts + i, 0); - if (tlHandle == INVALID_HANDLE_VALUE) - initPort(); - } - - i++; - - } - - obj[n]->Release(); - - } - - numPorts += i; - - } - } - - classObject->Release(); - services->Release(); - locator->Release(); - -} - -void TractionLoss::initPort() { - - byte buf[] = { '[', 'r', 'd', 'S', ']' }; - - DWORD written; - COMSTAT comstat; - DWORD errors; - - if (tlPort == nullptr) - return; - - wchar_t *settings = L"500000,n,8,1"; - - if (tlHandle != INVALID_HANDLE_VALUE) - CloseHandle(tlHandle); - - tlHandle = CreateFile( - tlPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0 - ); - - DCB dcb; - - memset(&dcb, 0, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); - if (!BuildCommDCB(settings, &dcb)) { - text(L"Error building TL control port parameters"); - CloseHandle(tlHandle); - tlHandle = INVALID_HANDLE_VALUE; - return; - } - - dcb.fAbortOnError = FALSE; - dcb.fDtrControl = TRUE; - - if (!SetCommState(tlHandle, &dcb)) { - text(L"Error setting TL control port parameters"); - CloseHandle(tlHandle); - tlHandle = INVALID_HANDLE_VALUE; - return; - } - - COMMTIMEOUTS timeouts; - memset(&timeouts, 0, sizeof(timeouts)); - timeouts.WriteTotalTimeoutConstant = 10; - timeouts.ReadTotalTimeoutConstant = 1000; - SetCommTimeouts(tlHandle, &timeouts); - - Sleep(1000); - - if (!WriteFile(tlHandle, buf, 5, &written, NULL)) { - if (GetLastError() != ERROR_IO_PENDING) - ClearCommError(tlHandle, &errors, &comstat); - text(L"Error writing to TL control port"); - tlHandle = INVALID_HANDLE_VALUE; - return; - } - - memset(buf, 0, 5); - - for (int i = 0; i < 5; i++) - if (!ReadFile(tlHandle, buf + i, 1, &written, NULL)) - break; - - if (buf[4] != ']') { - text(L"Error talking to SMC, correct port?"); - CloseHandle(tlHandle); - tlHandle = INVALID_HANDLE_VALUE; - return; - } - - minPos = buf[3] + 12; - maxPos = 1023 - minPos; - maxDelta = maxPos - minPos; - - text(L"Connected to TL control port, max delta: %hd", maxDelta); - -} - -void TractionLoss::setEnabled(bool enabled) { - - static byte buf[5] = { '[', 0, 0, 0, ']' }; - - DWORD written; - COMSTAT comstat; - DWORD errors; - - if (tlHandle == INVALID_HANDLE_VALUE) - return; - - isEnabled = enabled; - - if (!enabled) { - - buf[1] = 'A'; - buf[2] = 512 >> 8; - buf[3] = 0; - - if (!WriteFile(tlHandle, buf, 5, &written, NULL)) { - text(L"Error writing to TL port: %d", GetLastError()); - if (GetLastError() != ERROR_IO_PENDING) - ClearCommError(tlHandle, &errors, &comstat); - } - - } - - buf[1] = 'N'; - buf[2] = 0; - buf[3] = enabled ? 1 : 0; - - if (!WriteFile(tlHandle, buf, 5, &written, NULL)) { - text(L"Error writing to TL port: %d", GetLastError()); - if (GetLastError() != ERROR_IO_PENDING) - ClearCommError(tlHandle, &errors, &comstat); - } - - if (enabled) { - - buf[1] = 'e'; - buf[2] = 'n'; - buf[3] = '1'; - - if (!WriteFile(tlHandle, buf, 5, &written, NULL)) { - text(L"Error writing to TL port: %d", GetLastError()); - if (GetLastError() != ERROR_IO_PENDING) - ClearCommError(tlHandle, &errors, &comstat); - } - - text(L"TL enabled"); - - } - else { - text(L"TL disabled"); - } - -} - -void TractionLoss::setAngle(float angle) { - - static byte buf[] = { '[', 'A', 0, 0, ']' }; - - DWORD written; - COMSTAT comstat; - DWORD errors; - - if (tlHandle == INVALID_HANDLE_VALUE) - return; - - int16_t pos = 512 + (int16_t)(angle * 57.2958f * stepsPerDeg); - - if (pos > maxPos) pos = maxPos; - else if (pos < minPos) pos = minPos; - - buf[2] = pos >> 8; - buf[3] = pos & 0xff; - - if (!WriteFile(tlHandle, buf, 5, &written, NULL)) { - text(L"Error writing to TL control port: %d", GetLastError()); - if (GetLastError() != ERROR_IO_PENDING) - ClearCommError(tlHandle, &errors, &comstat); - } - -} - -void TractionLoss::readSettings() { - - HKEY regKey; - DWORD val; - DWORD sz = sizeof(val); - - if (tlPort != nullptr) - delete[] tlPort; - - tlPort = new wchar_t[128]; - DWORD tlPortSize = 128 * sizeof(wchar_t); - - if (!RegOpenKeyEx(HKEY_CURRENT_USER, SETTINGS_KEY, 0, KEY_ALL_ACCESS, ®Key)) { - - if (RegGetValueW(regKey, nullptr, L"tlPort", RRF_RT_REG_SZ, nullptr, tlPort, &tlPortSize)) { - delete[] tlPort; - tlPort = nullptr; - } - if (RegGetValueW(regKey, nullptr, L"tlMinAngle", RRF_RT_REG_DWORD, nullptr, (BYTE *)&val, &sz)) - setMinAngle(35); - else - setMinAngle(val); - if (RegGetValueW(regKey, nullptr, L"tlStepsPerDeg", RRF_RT_REG_DWORD, nullptr, (BYTE *)&val, &sz)) - setStepsPerDeg(350); - else - setStepsPerDeg(val); - - } - else { - delete[] tlPort; - tlPort = nullptr; - setMinAngle(35); - setStepsPerDeg(350); - } - -} - -void TractionLoss::writeSettings() { - - HKEY regKey; - DWORD sz = sizeof(int); - DWORD tlPortSz = 0; - DWORD minAngleVal = (DWORD)(minAngle * 10.0f); - DWORD stepsPerDegVal = (DWORD)(stepsPerDeg * 10.0f); - - if (tlPort) - tlPortSz = (lstrlen(tlPort) + 1) * sizeof(wchar_t); - - RegCreateKeyEx( - HKEY_CURRENT_USER, SETTINGS_KEY, 0, nullptr, - REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr, ®Key, nullptr - ); - - if (!RegOpenKeyEx(HKEY_CURRENT_USER, SETTINGS_KEY, 0, KEY_ALL_ACCESS, ®Key)) { - if (tlPort) - RegSetValueEx(regKey, L"tlPort", 0, REG_SZ, (BYTE *)tlPort, tlPortSz); - RegSetValueEx(regKey, L"tlMinAngle", 0, REG_DWORD, (BYTE *)&minAngleVal, sz); - RegSetValueEx(regKey, L"tlStepsPerDeg", 0, REG_DWORD, (BYTE *)&stepsPerDegVal, sz); - } - -} \ No newline at end of file diff --git a/irFFB/tractionloss.h b/irFFB/tractionloss.h deleted file mode 100644 index 31f31f3..0000000 --- a/irFFB/tractionloss.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include - -#include "stdafx.h" -#include "irFFB.h" -#include "fan.h" - -class TractionLoss -{ - - public: - static TractionLoss *init(); - void createWindow(HINSTANCE); - float getMinAngle() { return minAngle / 57.2958f; }; - void setAngle(float); - void setEnabled(bool enable); - private: - TractionLoss(); - ATOM registerClass(HINSTANCE); - static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); - void setMinAngle(int); - void setStepsPerDeg(int); - void enumSerialPorts(); - void initPort(); - void readSettings(); - void writeSettings(); - - static TractionLoss *instance; - - wchar_t *windowClass = L"Traction Loss settings"; - HWND mainWnd, portWnd; - sWins_t *minAngleWnd = nullptr, *stepsPerDegWnd = nullptr; - int numPorts = 0; - wchar_t *tlPort = nullptr; - port *ports = nullptr; - HANDLE tlHandle = INVALID_HANDLE_VALUE; - wchar_t strbuf[64]; - bool classIsRegistered = false; - bool isEnabled = false; - int16_t minPos = 0, maxPos = 0, maxDelta = 0; - float minAngle, stepsPerDeg; - -}; -