diff --git a/HandheldCompanion.iss b/HandheldCompanion.iss index 1c6ae8a71..d7134cd2a 100644 --- a/HandheldCompanion.iss +++ b/HandheldCompanion.iss @@ -1,597 +1,583 @@ -; ----------- -; CODE -; ----------- -[Code] -// types and variables -type - TDependency_Entry = record - Filename: String; - Parameters: String; - Title: String; - URL: String; - Checksum: String; - ForceSuccess: Boolean; - RestartAfter: Boolean; - end; - -var - Dependency_Memo: String; - Dependency_List: array of TDependency_Entry; - Dependency_NeedRestart, Dependency_ForceX86: Boolean; - Dependency_DownloadPage: TDownloadWizardPage; - -procedure Dependency_Add(const Filename, Parameters, Title, URL, Checksum: String; const ForceSuccess, RestartAfter: Boolean); -var - Dependency: TDependency_Entry; - DependencyCount: Integer; -begin - Dependency_Memo := Dependency_Memo + #13#10 + '%1' + Title; - - Dependency.Filename := Filename; - Dependency.Parameters := Parameters; - Dependency.Title := Title; - - if FileExists(ExpandConstant('{tmp}{\}') + Filename) then begin - Dependency.URL := ''; - end else begin - Dependency.URL := URL; - end; - - Dependency.Checksum := Checksum; - Dependency.ForceSuccess := ForceSuccess; - Dependency.RestartAfter := RestartAfter; - - DependencyCount := GetArrayLength(Dependency_List); - SetArrayLength(Dependency_List, DependencyCount + 1); - Dependency_List[DependencyCount] := Dependency; -end; - -procedure Dependency_InitializeWizard; -begin - Dependency_DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil); -end; - -function Dependency_PrepareToInstall(var NeedsRestart: Boolean): String; -var - DependencyCount, DependencyIndex, ResultCode: Integer; - Retry: Boolean; - TempValue: String; -begin - DependencyCount := GetArrayLength(Dependency_List); - - if DependencyCount > 0 then begin - Dependency_DownloadPage.Show; - - for DependencyIndex := 0 to DependencyCount - 1 do begin - if Dependency_List[DependencyIndex].URL <> '' then begin - Dependency_DownloadPage.Clear; - Dependency_DownloadPage.Add(Dependency_List[DependencyIndex].URL, Dependency_List[DependencyIndex].Filename, Dependency_List[DependencyIndex].Checksum); - - Retry := True; - while Retry do begin - Retry := False; - - try - Dependency_DownloadPage.Download; - except - if Dependency_DownloadPage.AbortedByUser then begin - Result := Dependency_List[DependencyIndex].Title; - DependencyIndex := DependencyCount; - end else begin - case SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of - IDABORT: begin - Result := Dependency_List[DependencyIndex].Title; - DependencyIndex := DependencyCount; - end; - IDRETRY: begin - Retry := True; - end; - end; - end; - end; - end; - end; - end; - - if Result = '' then begin - for DependencyIndex := 0 to DependencyCount - 1 do begin - Dependency_DownloadPage.SetText(Dependency_List[DependencyIndex].Title, ''); - Dependency_DownloadPage.SetProgress(DependencyIndex + 1, DependencyCount + 1); - - while True do begin - ResultCode := 0; - if ShellExec('', ExpandConstant('{tmp}{\}') + Dependency_List[DependencyIndex].Filename, Dependency_List[DependencyIndex].Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode) then begin - if Dependency_List[DependencyIndex].RestartAfter then begin - if DependencyIndex = DependencyCount - 1 then begin - Dependency_NeedRestart := True; - end else begin - NeedsRestart := True; - Result := Dependency_List[DependencyIndex].Title; - end; - break; - end else if (ResultCode = 0) or Dependency_List[DependencyIndex].ForceSuccess then begin // ERROR_SUCCESS (0) - break; - end else if ResultCode = 1641 then begin // ERROR_SUCCESS_REBOOT_INITIATED (1641) - NeedsRestart := True; - Result := Dependency_List[DependencyIndex].Title; - break; - end else if ResultCode = 3010 then begin // ERROR_SUCCESS_REBOOT_REQUIRED (3010) - Dependency_NeedRestart := True; - break; - end; - end; - - case SuppressibleMsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [Dependency_List[DependencyIndex].Title, IntToStr(ResultCode)]), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of - IDABORT: begin - Result := Dependency_List[DependencyIndex].Title; - break; - end; - IDIGNORE: begin - break; - end; - end; - end; - - if Result <> '' then begin - break; - end; - end; - - if NeedsRestart then begin - TempValue := '"' + ExpandConstant('{srcexe}') + '" /restart=1 /LANG="' + ExpandConstant('{language}') + '" /DIR="' + WizardDirValue + '" /GROUP="' + WizardGroupValue + '" /TYPE="' + WizardSetupType(False) + '" /COMPONENTS="' + WizardSelectedComponents(False) + '" /TASKS="' + WizardSelectedTasks(False) + '"'; - if WizardNoIcons then begin - TempValue := TempValue + ' /NOICONS'; - end; - RegWriteStringValue(HKA, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', '{#SetupSetting("AppName")}', TempValue); - end; - end; - - Dependency_DownloadPage.Hide; - end; -end; - -function Dependency_UpdateReadyMemo(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String; -begin - Result := ''; - if MemoUserInfoInfo <> '' then begin - Result := Result + MemoUserInfoInfo + Newline + NewLine; - end; - if MemoDirInfo <> '' then begin - Result := Result + MemoDirInfo + Newline + NewLine; - end; - if MemoTypeInfo <> '' then begin - Result := Result + MemoTypeInfo + Newline + NewLine; - end; - if MemoComponentsInfo <> '' then begin - Result := Result + MemoComponentsInfo + Newline + NewLine; - end; - if MemoGroupInfo <> '' then begin - Result := Result + MemoGroupInfo + Newline + NewLine; - end; - if MemoTasksInfo <> '' then begin - Result := Result + MemoTasksInfo; - end; - - if Dependency_Memo <> '' then begin - if MemoTasksInfo = '' then begin - Result := Result + SetupMessage(msgReadyMemoTasks); - end; - Result := Result + FmtMessage(Dependency_Memo, [Space]); - end; -end; - -function Dependency_IsX64: Boolean; -begin - Result := not Dependency_ForceX86 and Is64BitInstallMode; -end; - -function Dependency_String(const x86, x64: String): String; -begin - if Dependency_IsX64 then begin - Result := x64; - end else begin - Result := x86; - end; -end; - -function Dependency_ArchSuffix: String; -begin - Result := Dependency_String('', '_x64'); -end; - -function Dependency_ArchTitle: String; -begin - Result := Dependency_String(' (x86)', ' (x64)'); -end; - -function Dependency_IsNetCoreInstalled(const Version: String): Boolean; -var - ResultCode: Integer; -begin - // source code: https://github.com/dotnet/deployment-tools/tree/master/src/clickonce/native/projects/NetCoreCheck - if not FileExists(ExpandConstant('{tmp}{\}') + 'netcorecheck' + Dependency_ArchSuffix + '.exe') then begin - ExtractTemporaryFile('netcorecheck' + Dependency_ArchSuffix + '.exe'); - end; - Result := ShellExec('', ExpandConstant('{tmp}{\}') + 'netcorecheck' + Dependency_ArchSuffix + '.exe', Version, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0); -end; - -procedure Dependency_AddDotNet80Desktop; -begin - // https://dotnet.microsoft.com/en-us/download/dotnet/8.0 - if not Dependency_IsNetCoreInstalled('Microsoft.WindowsDesktop.App 8.0.0') then begin - Dependency_Add('dotNet80desktop' + Dependency_ArchSuffix + '.exe', - '/lcid ' + IntToStr(GetUILanguage) + ' /passive /norestart', - '.NET Desktop Runtime 8.0.0' + Dependency_ArchTitle, - Dependency_String('https://download.visualstudio.microsoft.com/download/pr/b280d97f-25a9-4ab7-8a12-8291aa3af117/a37ed0e68f51fcd973e9f6cb4f40b1a7/windowsdesktop-runtime-8.0.0-win-x64.exe', - 'https://download.visualstudio.microsoft.com/download/pr/f9e3b581-059d-429f-9f0d-1d1167ff7e32/bd7661030cd5d66cd3eee0fd20b24540/windowsdesktop-runtime-8.0.0-win-x86.exe'), - '', False, False); - end; -end; - -procedure Dependency_AddVC2005; -begin - // https://www.microsoft.com/en-US/download/details.aspx?id=26347 - if not IsMsiProductInstalled(Dependency_String('{86C9D5AA-F00C-4921-B3F2-C60AF92E2844}', '{A8D19029-8E5C-4E22-8011-48070F9E796E}'), PackVersionComponents(8, 0, 61000, 0)) then begin - Dependency_Add('vcredist2005' + Dependency_ArchSuffix + '.exe', - '/q', - 'Visual C++ 2005 Service Pack 1 Redistributable' + Dependency_ArchTitle, - Dependency_String('https://download.microsoft.com/download/8/B/4/8B42259F-5D70-43F4-AC2E-4B208FD8D66A/vcredist_x86.EXE', 'https://download.microsoft.com/download/8/B/4/8B42259F-5D70-43F4-AC2E-4B208FD8D66A/vcredist_x64.EXE'), - '', False, False); - end; -end; - -procedure Dependency_AddVC2008; -begin - // https://www.microsoft.com/en-US/download/details.aspx?id=26368 - if not IsMsiProductInstalled(Dependency_String('{DE2C306F-A067-38EF-B86C-03DE4B0312F9}', '{FDA45DDF-8E17-336F-A3ED-356B7B7C688A}'), PackVersionComponents(9, 0, 30729, 6161)) then begin - Dependency_Add('vcredist2008' + Dependency_ArchSuffix + '.exe', - '/q', - 'Visual C++ 2008 Service Pack 1 Redistributable' + Dependency_ArchTitle, - Dependency_String('https://download.microsoft.com/download/5/D/8/5D8C65CB-C849-4025-8E95-C3966CAFD8AE/vcredist_x86.exe', 'https://download.microsoft.com/download/5/D/8/5D8C65CB-C849-4025-8E95-C3966CAFD8AE/vcredist_x64.exe'), - '', False, False); - end; -end; - -procedure Dependency_AddVC2010; -begin - // https://www.microsoft.com/en-US/download/details.aspx?id=26999 - if not IsMsiProductInstalled(Dependency_String('{1F4F1D2A-D9DA-32CF-9909-48485DA06DD5}', '{5B75F761-BAC8-33BC-A381-464DDDD813A3}'), PackVersionComponents(10, 0, 40219, 0)) then begin - Dependency_Add('vcredist2010' + Dependency_ArchSuffix + '.exe', - '/passive /norestart', - 'Visual C++ 2010 Service Pack 1 Redistributable' + Dependency_ArchTitle, - Dependency_String('https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x86.exe', 'https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x64.exe'), - '', False, False); - end; -end; - -procedure Dependency_AddVC2012; -begin - // https://www.microsoft.com/en-US/download/details.aspx?id=30679 - if not IsMsiProductInstalled(Dependency_String('{4121ED58-4BD9-3E7B-A8B5-9F8BAAE045B7}', '{EFA6AFA1-738E-3E00-8101-FD03B86B29D1}'), PackVersionComponents(11, 0, 61030, 0)) then begin - Dependency_Add('vcredist2012' + Dependency_ArchSuffix + '.exe', - '/passive /norestart', - 'Visual C++ 2012 Update 4 Redistributable' + Dependency_ArchTitle, - Dependency_String('https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x86.exe', 'https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe'), - '', False, False); - end; -end; - -procedure Dependency_AddVC2013; -begin - // https://support.microsoft.com/en-US/help/4032938 - if not IsMsiProductInstalled(Dependency_String('{B59F5BF1-67C8-3802-8E59-2CE551A39FC5}', '{20400CF0-DE7C-327E-9AE4-F0F38D9085F8}'), PackVersionComponents(12, 0, 40664, 0)) then begin - Dependency_Add('vcredist2013' + Dependency_ArchSuffix + '.exe', - '/passive /norestart', - 'Visual C++ 2013 Update 5 Redistributable' + Dependency_ArchTitle, - Dependency_String('https://download.visualstudio.microsoft.com/download/pr/10912113/5da66ddebb0ad32ebd4b922fd82e8e25/vcredist_x86.exe', 'https://download.visualstudio.microsoft.com/download/pr/10912041/cee5d6bca2ddbcd039da727bf4acb48a/vcredist_x64.exe'), - '', False, False); - end; -end; - -procedure Dependency_AddVC2015To2019; -begin - // https://support.microsoft.com/en-US/help/2977003/the-latest-supported-visual-c-downloads - if not IsMsiProductInstalled(Dependency_String('{65E5BD06-6392-3027-8C26-853107D3CF1A}', '{36F68A90-239C-34DF-B58C-64B30153CE35}'), PackVersionComponents(14, 29, 30037, 0)) then begin - Dependency_Add('vcredist2019' + Dependency_ArchSuffix + '.exe', - '/passive /norestart', - 'Visual C++ 2015-2019 Redistributable' + Dependency_ArchTitle, - Dependency_String('https://aka.ms/vs/16/release/vc_redist.x86.exe', 'https://aka.ms/vs/16/release/vc_redist.x64.exe'), - '', False, False); - end; -end; - -procedure Dependency_AddDirectX; -begin - // https://www.microsoft.com/en-US/download/details.aspx?id=35 - Dependency_Add('dxwebsetup.exe', - '/q', - 'DirectX Runtime', - 'https://download.microsoft.com/download/1/7/1/1718CCC4-6315-4D8E-9543-8E28A4E18C4C/dxwebsetup.exe', - '', True, False); -end; - -procedure Dependency_AddHideHide; -begin - Dependency_Add('HidHide_1.4.192_x64.exe', - '/quiet /norestart', - 'HidHide Drivers', - 'https://github.com/nefarius/HidHide/releases/download/v1.4.192.0/HidHide_1.4.192_x64.exe', - '', True, False); -end; - -procedure Dependency_AddViGem; -begin - Dependency_Add('ViGEmBus_1.22.0_x64_x86_arm64.exe', - '/quiet /norestart', - 'ViGEmBus Setup', - 'https://github.com/nefarius/ViGEmBus/releases/download/v1.22.0/ViGEmBus_1.22.0_x64_x86_arm64.exe', - '', True, False); -end; - -procedure Dependency_AddRTSS; -begin - Dependency_Add('RTSSSetup735Beta5.exe', - '/S', - 'RTSS Setup v7.3.5 Beta5', - 'https://github.com/Valkirie/HandheldCompanion/raw/main/redist/RTSSSetup735Beta5.exe', - '', True, False); -end; - -procedure Dependency_AddHWiNFO; -begin - Dependency_Add('hwi_766.exe', - '/silent', - 'HWiNFO v7.6.6', - 'https://github.com/Valkirie/HandheldCompanion/raw/main/redist/hwi_766.exe', - '', True, False); -end; - -[Setup] -; ------------- -; SETUP -; ------------- -#ifndef Dependency_NoExampleSetup - -; requires netcorecheck.exe and netcorecheck_x64.exe (see download link below) -#define UseNetCoreCheck -#ifdef UseNetCoreCheck - #define UseDotNet80 -#endif - -;#define UseVC2005 -;#define UseVC2008 -;#define UseVC2010 -;#define UseVC2012 -;#define UseVC2013 -;#define UseVC2015To2019 - -#define UseDirectX -; install ViGem first -#define UseViGem -#define UseHideHide -#define UseRTSS -#define UseHWiNFO - -#define MyAppSetupName 'Handheld Companion' -#define MyBuildId 'HandheldCompanion' -#define MyAppVersion '0.19.1.8' -#define MyAppPublisher 'BenjaminLSR' -#define MyAppCopyright 'Copyright @ BenjaminLSR' -#define MyAppURL 'https://github.com/Valkirie/HandheldCompanion' -#define MyAppExeName "HandheldCompanion.exe" -#define MyConfiguration "Release" - -#ifdef UseDotNet80 - #define MyConfigurationExt "net8.0" -#endif - -AppName={#MyAppSetupName} -AppVersion={#MyAppVersion} -AppVerName={#MyAppSetupName} -AppCopyright={#MyAppCopyright} -VersionInfoVersion={#MyAppVersion} -VersionInfoCompany={#MyAppPublisher} -AppPublisher={#MyAppPublisher} -AppPublisherURL={#MyAppURL} -AppSupportURL={#MyAppURL} -AppUpdatesURL={#MyAppURL} -OutputBaseFilename={#MyBuildId}-{#MyAppVersion} -DefaultGroupName={#MyAppSetupName} -DefaultDirName={autopf}\{#MyAppSetupName} -UninstallDisplayIcon={app}\{#MyAppExeName} -SetupIconFile="{#SourcePath}\HandheldCompanion\Resources\icon.ico" -SourceDir=redist -OutputDir={#SourcePath}\install -AllowNoIcons=yes -MinVersion=6.0 -;PrivilegesRequired=admin -PrivilegesRequiredOverridesAllowed=dialog -Compression=lzma -SolidCompression=yes - -// remove next line if you only deploy 32-bit binaries and dependencies -ArchitecturesInstallIn64BitMode=x64 - -[Languages] -Name: en; MessagesFile: "compiler:Default.isl" - -[Setup] -AlwaysRestart = yes -CloseApplications = yes - -[Files] -#ifdef UseNetCoreCheck -// download netcorecheck.exe: https://go.microsoft.com/fwlink/?linkid=2135256 -// download netcorecheck_x64.exe: https://go.microsoft.com/fwlink/?linkid=2135504 -Source: "netcorecheck.exe"; Flags: dontcopy noencryption -Source: "netcorecheck_x64.exe"; Flags: dontcopy noencryption -#endif - -Source: "{#SourcePath}\bin\{#MyConfiguration}\{#MyConfigurationExt}-windows10.0.19041.0\WinRing0x64.dll"; DestDir: "{app}"; Flags: onlyifdoesntexist -Source: "{#SourcePath}\bin\{#MyConfiguration}\{#MyConfigurationExt}-windows10.0.19041.0\WinRing0x64.sys"; DestDir: "{app}"; Flags: onlyifdoesntexist -Source: "{#SourcePath}\bin\{#MyConfiguration}\{#MyConfigurationExt}-windows10.0.19041.0\*"; Excludes: "*WinRing0x64.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs - -Source: "{#SourcePath}\redist\SegoeIcons.ttf"; DestDir: "{autofonts}"; FontInstall: "Segoe Fluent Icons (TrueType)"; Flags: onlyifdoesntexist uninsneveruninstall -Source: "{#SourcePath}\redist\PromptFont.otf"; DestDir: "{autofonts}"; FontInstall: "PromptFont"; Flags: uninsneveruninstall - -[Icons] -Name: "{group}\{#MyAppSetupName}"; Filename: "{app}\{#MyAppExeName}" -Name: "{group}\{cm:UninstallProgram,{#MyAppSetupName}}"; Filename: "{uninstallexe}" -Name: "{commondesktop}\{#MyAppSetupName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}" - -[UninstallRun] -Filename: "C:\Program Files\Nefarius Software Solutions\HidHide\x64\HidHideCLI.exe"; Parameters: "--cloak-off" ; RunOnceId: "CloakOff"; Flags: runascurrentuser runhidden - -[UninstallDelete] -Type: filesandordirs; Name: "{app}" - -[Registry] -Root: HKLM; Subkey: "Software\Microsoft\Windows\Windows Error Reporting\LocalDumps"; Flags: uninsdeletekeyifempty -Root: HKLM; Subkey: "Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\HandheldCompanion.exe"; ValueType: string; ValueName: "DumpFolder"; ValueData: "{userdocs}\HandheldCompanion\dumps"; Flags: uninsdeletekey - -[Code] -#include "./UpdateUninstallWizard.iss" - -procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); -var - resultCode:integer; -begin - if CurUninstallStep = usUninstall then - begin - if not(checkListBox.checked[keepAllCheck]) then - begin - if DirExists(ExpandConstant('{userdocs}\{#MyBuildId}\profiles')) then - DelTree(ExpandConstant('{userdocs}\{#MyBuildId}\profiles'), True, True, True); - if DirExists(ExpandConstant('{userdocs}\{#MyBuildId}\hotkeys')) then - DelTree(ExpandConstant('{userdocs}\{#MyBuildId}\hotkeys'), True, True, True); - DelTree(ExpandConstant('{localappdata}\HandheldCompanion'), True, True, True); - exit; - end - else - begin - if not(checkListBox.checked[profilesCheck]) then - begin - if DirExists(ExpandConstant('{userdocs}\{#MyBuildId}\profiles')) then - DelTree(ExpandConstant('{userdocs}\{#MyBuildId}\profiles'), True, True, True); - end; - - if not(checkListBox.checked[hotkeysCheck]) then - begin - if DirExists(ExpandConstant('{userdocs}\{#MyBuildId}\hotkeys')) then - DelTree(ExpandConstant('{userdocs}\{#MyBuildId}\hotkeys'), True, True, True); - end; - - if not(checkListBox.checked[applicationSettingsCheck]) then - begin - DelTree(ExpandConstant('{localappdata}\HandheldCompanion'), True, True, True); - end; - end; - - if not(keepHidhideCheckbox.Checked) then - begin - if(ShellExec('', 'msiexec.exe', '/X{BE49B9DE-F8EB-4F54-B312-DD4B601985FC}', '', SW_SHOW, ewWaitUntilTerminated, resultCode)) then - begin - log('Successfully executed Hidhide uninstaller'); - if(resultCode = 0) then - log('Hidhide uninstaller finished successfully') - else - log('Hidhide uninstaller failed with exit code ' +intToStr(resultCode)); - end - else - begin - log('Failed to execute Hidhide uninstaller'); - end; - end; - - if not(keepVigemCheckbox.Checked) then - begin - if(ShellExec('', 'msiexec.exe', '/X{966606F3-2745-49E9-BF15-5C3EAA4E9077}', '', SW_SHOW, ewWaitUntilTerminated, resultCode)) then - begin - log('Successfully executed Vigem uninstaller'); - if(resultCode = 0) then - log('Vigem uninstaller finished successfully') - else - log('Vigem uninstaller failed with exit code ' +intToStr(resultCode)); - end - else - begin - log('Failed to execute Vigem uninstaller'); - end; - end; - end; -end; - - -procedure InitializeWizard; -begin - Dependency_InitializeWizard; -end; - -function PrepareToInstall(var NeedsRestart: Boolean): String; -begin - Result := Dependency_PrepareToInstall(NeedsRestart); -end; - -function NeedRestart: Boolean; -begin - Result := Dependency_NeedRestart; -end; - -function UpdateReadyMemo(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String; -begin - Result := Dependency_UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo); -end; - -function InitializeSetup: Boolean; -begin - -#ifdef UseDotNet80 - Dependency_AddDotNet80Desktop; -#endif - -#ifdef UseVC2005 - Dependency_AddVC2005; -#endif -#ifdef UseVC2008 - Dependency_AddVC2008; -#endif -#ifdef UseVC2010 - Dependency_AddVC2010; -#endif -#ifdef UseVC2012 - Dependency_AddVC2012; -#endif -#ifdef UseVC2013 - Dependency_AddVC2013; -#endif -#ifdef UseVC2015To2019 - Dependency_AddVC2015To2019; -#endif - -#ifdef UseDirectX - Dependency_AddDirectX; -#endif - -#ifdef UseHideHide - Dependency_AddHideHide; -#endif - -#ifdef UseViGem - Dependency_AddViGem; -#endif - -#ifdef UseRTSS - Dependency_AddRTSS; -#endif - -#ifdef UseHWiNFO - Dependency_AddHWiNFO; -#endif - - Result := True; -end; - -#endif +; ----------- +; CODE +; ----------- +[Code] +// types and variables +type + TDependency_Entry = record + Filename: String; + Parameters: String; + Title: String; + URL: String; + Checksum: String; + ForceSuccess: Boolean; + RestartAfter: Boolean; + end; + +var + Dependency_Memo: String; + Dependency_List: array of TDependency_Entry; + Dependency_NeedRestart, Dependency_ForceX86: Boolean; + Dependency_DownloadPage: TDownloadWizardPage; + +procedure Dependency_Add(const Filename, Parameters, Title, URL, Checksum: String; const ForceSuccess, RestartAfter: Boolean); +var + Dependency: TDependency_Entry; + DependencyCount: Integer; +begin + Dependency_Memo := Dependency_Memo + #13#10 + '%1' + Title; + + Dependency.Filename := Filename; + Dependency.Parameters := Parameters; + Dependency.Title := Title; + + if FileExists(ExpandConstant('{tmp}{\}') + Filename) then begin + Dependency.URL := ''; + end else begin + Dependency.URL := URL; + end; + + Dependency.Checksum := Checksum; + Dependency.ForceSuccess := ForceSuccess; + Dependency.RestartAfter := RestartAfter; + + DependencyCount := GetArrayLength(Dependency_List); + SetArrayLength(Dependency_List, DependencyCount + 1); + Dependency_List[DependencyCount] := Dependency; +end; + +procedure Dependency_InitializeWizard; +begin + Dependency_DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil); +end; + +function Dependency_PrepareToInstall(var NeedsRestart: Boolean): String; +var + DependencyCount, DependencyIndex, ResultCode: Integer; + Retry: Boolean; + TempValue: String; +begin + DependencyCount := GetArrayLength(Dependency_List); + + if DependencyCount > 0 then begin + Dependency_DownloadPage.Show; + + for DependencyIndex := 0 to DependencyCount - 1 do begin + if Dependency_List[DependencyIndex].URL <> '' then begin + Dependency_DownloadPage.Clear; + Dependency_DownloadPage.Add(Dependency_List[DependencyIndex].URL, Dependency_List[DependencyIndex].Filename, Dependency_List[DependencyIndex].Checksum); + + Retry := True; + while Retry do begin + Retry := False; + + try + Dependency_DownloadPage.Download; + except + if Dependency_DownloadPage.AbortedByUser then begin + Result := Dependency_List[DependencyIndex].Title; + DependencyIndex := DependencyCount; + end else begin + case SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of + IDABORT: begin + Result := Dependency_List[DependencyIndex].Title; + DependencyIndex := DependencyCount; + end; + IDRETRY: begin + Retry := True; + end; + end; + end; + end; + end; + end; + end; + + if Result = '' then begin + for DependencyIndex := 0 to DependencyCount - 1 do begin + Dependency_DownloadPage.SetText(Dependency_List[DependencyIndex].Title, ''); + Dependency_DownloadPage.SetProgress(DependencyIndex + 1, DependencyCount + 1); + + while True do begin + ResultCode := 0; + if ShellExec('', ExpandConstant('{tmp}{\}') + Dependency_List[DependencyIndex].Filename, Dependency_List[DependencyIndex].Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode) then begin + if Dependency_List[DependencyIndex].RestartAfter then begin + if DependencyIndex = DependencyCount - 1 then begin + Dependency_NeedRestart := True; + end else begin + NeedsRestart := True; + Result := Dependency_List[DependencyIndex].Title; + end; + break; + end else if (ResultCode = 0) or Dependency_List[DependencyIndex].ForceSuccess then begin // ERROR_SUCCESS (0) + break; + end else if ResultCode = 1641 then begin // ERROR_SUCCESS_REBOOT_INITIATED (1641) + NeedsRestart := True; + Result := Dependency_List[DependencyIndex].Title; + break; + end else if ResultCode = 3010 then begin // ERROR_SUCCESS_REBOOT_REQUIRED (3010) + Dependency_NeedRestart := True; + break; + end; + end; + + case SuppressibleMsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [Dependency_List[DependencyIndex].Title, IntToStr(ResultCode)]), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of + IDABORT: begin + Result := Dependency_List[DependencyIndex].Title; + break; + end; + IDIGNORE: begin + break; + end; + end; + end; + + if Result <> '' then begin + break; + end; + end; + + if NeedsRestart then begin + TempValue := '"' + ExpandConstant('{srcexe}') + '" /restart=1 /LANG="' + ExpandConstant('{language}') + '" /DIR="' + WizardDirValue + '" /GROUP="' + WizardGroupValue + '" /TYPE="' + WizardSetupType(False) + '" /COMPONENTS="' + WizardSelectedComponents(False) + '" /TASKS="' + WizardSelectedTasks(False) + '"'; + if WizardNoIcons then begin + TempValue := TempValue + ' /NOICONS'; + end; + RegWriteStringValue(HKA, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', '{#SetupSetting("AppName")}', TempValue); + end; + end; + + Dependency_DownloadPage.Hide; + end; +end; + +function Dependency_UpdateReadyMemo(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String; +begin + Result := ''; + if MemoUserInfoInfo <> '' then begin + Result := Result + MemoUserInfoInfo + Newline + NewLine; + end; + if MemoDirInfo <> '' then begin + Result := Result + MemoDirInfo + Newline + NewLine; + end; + if MemoTypeInfo <> '' then begin + Result := Result + MemoTypeInfo + Newline + NewLine; + end; + if MemoComponentsInfo <> '' then begin + Result := Result + MemoComponentsInfo + Newline + NewLine; + end; + if MemoGroupInfo <> '' then begin + Result := Result + MemoGroupInfo + Newline + NewLine; + end; + if MemoTasksInfo <> '' then begin + Result := Result + MemoTasksInfo; + end; + + if Dependency_Memo <> '' then begin + if MemoTasksInfo = '' then begin + Result := Result + SetupMessage(msgReadyMemoTasks); + end; + Result := Result + FmtMessage(Dependency_Memo, [Space]); + end; +end; + +function Dependency_IsX64: Boolean; +begin + Result := not Dependency_ForceX86 and Is64BitInstallMode; +end; + +function Dependency_String(const x86, x64: String): String; +begin + if Dependency_IsX64 then begin + Result := x64; + end else begin + Result := x86; + end; +end; + +function Dependency_ArchSuffix: String; +begin + Result := Dependency_String('', '_x64'); +end; + +function Dependency_ArchTitle: String; +begin + Result := Dependency_String(' (x86)', ' (x64)'); +end; + +function Dependency_IsNetCoreInstalled(const Version: String): Boolean; +var + ResultCode: Integer; +begin + // source code: https://github.com/dotnet/deployment-tools/tree/master/src/clickonce/native/projects/NetCoreCheck + if not FileExists(ExpandConstant('{tmp}{\}') + 'netcorecheck' + Dependency_ArchSuffix + '.exe') then begin + ExtractTemporaryFile('netcorecheck' + Dependency_ArchSuffix + '.exe'); + end; + Result := ShellExec('', ExpandConstant('{tmp}{\}') + 'netcorecheck' + Dependency_ArchSuffix + '.exe', Version, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0); +end; + +procedure Dependency_AddDotNet80Desktop; +begin + // https://dotnet.microsoft.com/en-us/download/dotnet/8.0 + if not Dependency_IsNetCoreInstalled('Microsoft.WindowsDesktop.App 8.0.0') then begin + Dependency_Add('dotNet80desktop' + Dependency_ArchSuffix + '.exe', + '/lcid ' + IntToStr(GetUILanguage) + ' /passive /norestart', + '.NET Desktop Runtime 8.0.0' + Dependency_ArchTitle, + Dependency_String('https://download.visualstudio.microsoft.com/download/pr/b280d97f-25a9-4ab7-8a12-8291aa3af117/a37ed0e68f51fcd973e9f6cb4f40b1a7/windowsdesktop-runtime-8.0.0-win-x64.exe', + 'https://download.visualstudio.microsoft.com/download/pr/f9e3b581-059d-429f-9f0d-1d1167ff7e32/bd7661030cd5d66cd3eee0fd20b24540/windowsdesktop-runtime-8.0.0-win-x86.exe'), + '', False, False); + end; +end; + +procedure Dependency_AddVC2005; +begin + // https://www.microsoft.com/en-US/download/details.aspx?id=26347 + if not IsMsiProductInstalled(Dependency_String('{86C9D5AA-F00C-4921-B3F2-C60AF92E2844}', '{A8D19029-8E5C-4E22-8011-48070F9E796E}'), PackVersionComponents(8, 0, 61000, 0)) then begin + Dependency_Add('vcredist2005' + Dependency_ArchSuffix + '.exe', + '/q', + 'Visual C++ 2005 Service Pack 1 Redistributable' + Dependency_ArchTitle, + Dependency_String('https://download.microsoft.com/download/8/B/4/8B42259F-5D70-43F4-AC2E-4B208FD8D66A/vcredist_x86.EXE', 'https://download.microsoft.com/download/8/B/4/8B42259F-5D70-43F4-AC2E-4B208FD8D66A/vcredist_x64.EXE'), + '', False, False); + end; +end; + +procedure Dependency_AddVC2008; +begin + // https://www.microsoft.com/en-US/download/details.aspx?id=26368 + if not IsMsiProductInstalled(Dependency_String('{DE2C306F-A067-38EF-B86C-03DE4B0312F9}', '{FDA45DDF-8E17-336F-A3ED-356B7B7C688A}'), PackVersionComponents(9, 0, 30729, 6161)) then begin + Dependency_Add('vcredist2008' + Dependency_ArchSuffix + '.exe', + '/q', + 'Visual C++ 2008 Service Pack 1 Redistributable' + Dependency_ArchTitle, + Dependency_String('https://download.microsoft.com/download/5/D/8/5D8C65CB-C849-4025-8E95-C3966CAFD8AE/vcredist_x86.exe', 'https://download.microsoft.com/download/5/D/8/5D8C65CB-C849-4025-8E95-C3966CAFD8AE/vcredist_x64.exe'), + '', False, False); + end; +end; + +procedure Dependency_AddVC2010; +begin + // https://www.microsoft.com/en-US/download/details.aspx?id=26999 + if not IsMsiProductInstalled(Dependency_String('{1F4F1D2A-D9DA-32CF-9909-48485DA06DD5}', '{5B75F761-BAC8-33BC-A381-464DDDD813A3}'), PackVersionComponents(10, 0, 40219, 0)) then begin + Dependency_Add('vcredist2010' + Dependency_ArchSuffix + '.exe', + '/passive /norestart', + 'Visual C++ 2010 Service Pack 1 Redistributable' + Dependency_ArchTitle, + Dependency_String('https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x86.exe', 'https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x64.exe'), + '', False, False); + end; +end; + +procedure Dependency_AddVC2012; +begin + // https://www.microsoft.com/en-US/download/details.aspx?id=30679 + if not IsMsiProductInstalled(Dependency_String('{4121ED58-4BD9-3E7B-A8B5-9F8BAAE045B7}', '{EFA6AFA1-738E-3E00-8101-FD03B86B29D1}'), PackVersionComponents(11, 0, 61030, 0)) then begin + Dependency_Add('vcredist2012' + Dependency_ArchSuffix + '.exe', + '/passive /norestart', + 'Visual C++ 2012 Update 4 Redistributable' + Dependency_ArchTitle, + Dependency_String('https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x86.exe', 'https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe'), + '', False, False); + end; +end; + +procedure Dependency_AddVC2013; +begin + // https://support.microsoft.com/en-US/help/4032938 + if not IsMsiProductInstalled(Dependency_String('{B59F5BF1-67C8-3802-8E59-2CE551A39FC5}', '{20400CF0-DE7C-327E-9AE4-F0F38D9085F8}'), PackVersionComponents(12, 0, 40664, 0)) then begin + Dependency_Add('vcredist2013' + Dependency_ArchSuffix + '.exe', + '/passive /norestart', + 'Visual C++ 2013 Update 5 Redistributable' + Dependency_ArchTitle, + Dependency_String('https://download.visualstudio.microsoft.com/download/pr/10912113/5da66ddebb0ad32ebd4b922fd82e8e25/vcredist_x86.exe', 'https://download.visualstudio.microsoft.com/download/pr/10912041/cee5d6bca2ddbcd039da727bf4acb48a/vcredist_x64.exe'), + '', False, False); + end; +end; + +procedure Dependency_AddVC2015To2019; +begin + // https://support.microsoft.com/en-US/help/2977003/the-latest-supported-visual-c-downloads + if not IsMsiProductInstalled(Dependency_String('{65E5BD06-6392-3027-8C26-853107D3CF1A}', '{36F68A90-239C-34DF-B58C-64B30153CE35}'), PackVersionComponents(14, 29, 30037, 0)) then begin + Dependency_Add('vcredist2019' + Dependency_ArchSuffix + '.exe', + '/passive /norestart', + 'Visual C++ 2015-2019 Redistributable' + Dependency_ArchTitle, + Dependency_String('https://aka.ms/vs/16/release/vc_redist.x86.exe', 'https://aka.ms/vs/16/release/vc_redist.x64.exe'), + '', False, False); + end; +end; + +procedure Dependency_AddDirectX; +begin + // https://www.microsoft.com/en-US/download/details.aspx?id=35 + Dependency_Add('dxwebsetup.exe', + '/q', + 'DirectX Runtime', + 'https://download.microsoft.com/download/1/7/1/1718CCC4-6315-4D8E-9543-8E28A4E18C4C/dxwebsetup.exe', + '', True, False); +end; + +procedure Dependency_AddHideHide; +begin + Dependency_Add('HidHide_1.4.192_x64.exe', + '/quiet /norestart', + 'HidHide Drivers', + 'https://github.com/nefarius/HidHide/releases/download/v1.4.192.0/HidHide_1.4.192_x64.exe', + '', True, False); +end; + +procedure Dependency_AddViGem; +begin + Dependency_Add('ViGEmBus_1.22.0_x64_x86_arm64.exe', + '/quiet /norestart', + 'ViGEmBus Setup', + 'https://github.com/nefarius/ViGEmBus/releases/download/v1.22.0/ViGEmBus_1.22.0_x64_x86_arm64.exe', + '', True, False); +end; + +procedure Dependency_AddRTSS; +begin + Dependency_Add('RTSSSetup735Beta5.exe', + '/S', + 'RTSS Setup v7.3.5 Beta5', + 'https://github.com/Valkirie/HandheldCompanion/raw/main/redist/RTSSSetup735Beta5.exe', + '', True, False); +end; + +[Setup] +; ------------- +; SETUP +; ------------- +#ifndef Dependency_NoExampleSetup + +; requires netcorecheck.exe and netcorecheck_x64.exe (see download link below) +#define UseNetCoreCheck +#ifdef UseNetCoreCheck + #define UseDotNet80 +#endif + +;#define UseVC2005 +;#define UseVC2008 +;#define UseVC2010 +;#define UseVC2012 +;#define UseVC2013 +;#define UseVC2015To2019 + +#define UseDirectX +; install ViGem first +#define UseViGem +#define UseHideHide +#define UseRTSS + +#define MyAppSetupName 'Handheld Companion' +#define MyBuildId 'HandheldCompanion' +#define MyAppVersion '0.20.3.0' +#define MyAppPublisher 'BenjaminLSR' +#define MyAppCopyright 'Copyright @ BenjaminLSR' +#define MyAppURL 'https://github.com/Valkirie/HandheldCompanion' +#define MyAppExeName "HandheldCompanion.exe" +#define MyConfiguration "Release" + +#ifdef UseDotNet80 + #define MyConfigurationExt "net8.0" +#endif + +AppName={#MyAppSetupName} +AppVersion={#MyAppVersion} +AppVerName={#MyAppSetupName} +AppCopyright={#MyAppCopyright} +VersionInfoVersion={#MyAppVersion} +VersionInfoCompany={#MyAppPublisher} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +OutputBaseFilename={#MyBuildId}-{#MyAppVersion} +DefaultGroupName={#MyAppSetupName} +DefaultDirName={autopf}\{#MyAppSetupName} +UninstallDisplayIcon={app}\{#MyAppExeName} +SetupIconFile="{#SourcePath}\HandheldCompanion\Resources\icon.ico" +SourceDir=redist +OutputDir={#SourcePath}\install +AllowNoIcons=yes +MinVersion=6.0 +;PrivilegesRequired=admin +PrivilegesRequiredOverridesAllowed=dialog +Compression=lzma +SolidCompression=yes + +// remove next line if you only deploy 32-bit binaries and dependencies +ArchitecturesInstallIn64BitMode=x64 + +[Languages] +Name: en; MessagesFile: "compiler:Default.isl" + +[Setup] +AlwaysRestart = yes +CloseApplications = yes + +[Files] +#ifdef UseNetCoreCheck +// download netcorecheck.exe: https://go.microsoft.com/fwlink/?linkid=2135256 +// download netcorecheck_x64.exe: https://go.microsoft.com/fwlink/?linkid=2135504 +Source: "netcorecheck.exe"; Flags: dontcopy noencryption +Source: "netcorecheck_x64.exe"; Flags: dontcopy noencryption +#endif + +Source: "{#SourcePath}\bin\{#MyConfiguration}\{#MyConfigurationExt}-windows10.0.19041.0\WinRing0x64.dll"; DestDir: "{app}"; Flags: onlyifdoesntexist +Source: "{#SourcePath}\bin\{#MyConfiguration}\{#MyConfigurationExt}-windows10.0.19041.0\WinRing0x64.sys"; DestDir: "{app}"; Flags: onlyifdoesntexist +Source: "{#SourcePath}\bin\{#MyConfiguration}\{#MyConfigurationExt}-windows10.0.19041.0\*"; Excludes: "*WinRing0x64.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs + +Source: "{#SourcePath}\redist\SegoeIcons.ttf"; DestDir: "{autofonts}"; FontInstall: "Segoe Fluent Icons (TrueType)"; Flags: onlyifdoesntexist uninsneveruninstall +Source: "{#SourcePath}\redist\PromptFont.otf"; DestDir: "{autofonts}"; FontInstall: "PromptFont"; Flags: uninsneveruninstall + +[Icons] +Name: "{group}\{#MyAppSetupName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{group}\{cm:UninstallProgram,{#MyAppSetupName}}"; Filename: "{uninstallexe}" +Name: "{commondesktop}\{#MyAppSetupName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}" + +[UninstallRun] +Filename: "C:\Program Files\Nefarius Software Solutions\HidHide\x64\HidHideCLI.exe"; Parameters: "--cloak-off" ; RunOnceId: "CloakOff"; Flags: runascurrentuser runhidden + +[UninstallDelete] +Type: filesandordirs; Name: "{app}" + +[Registry] +Root: HKLM; Subkey: "Software\Microsoft\Windows\Windows Error Reporting\LocalDumps"; Flags: uninsdeletekeyifempty +Root: HKLM; Subkey: "Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\HandheldCompanion.exe"; ValueType: string; ValueName: "DumpFolder"; ValueData: "{userdocs}\HandheldCompanion\dumps"; Flags: uninsdeletekey + +[Code] +#include "./UpdateUninstallWizard.iss" + +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +var + resultCode:integer; +begin + if CurUninstallStep = usUninstall then + begin + if not(checkListBox.checked[keepAllCheck]) then + begin + if DirExists(ExpandConstant('{userdocs}\{#MyBuildId}\profiles')) then + DelTree(ExpandConstant('{userdocs}\{#MyBuildId}\profiles'), True, True, True); + if DirExists(ExpandConstant('{userdocs}\{#MyBuildId}\hotkeys')) then + DelTree(ExpandConstant('{userdocs}\{#MyBuildId}\hotkeys'), True, True, True); + DelTree(ExpandConstant('{localappdata}\HandheldCompanion'), True, True, True); + exit; + end + else + begin + if not(checkListBox.checked[profilesCheck]) then + begin + if DirExists(ExpandConstant('{userdocs}\{#MyBuildId}\profiles')) then + DelTree(ExpandConstant('{userdocs}\{#MyBuildId}\profiles'), True, True, True); + end; + + if not(checkListBox.checked[hotkeysCheck]) then + begin + if DirExists(ExpandConstant('{userdocs}\{#MyBuildId}\hotkeys')) then + DelTree(ExpandConstant('{userdocs}\{#MyBuildId}\hotkeys'), True, True, True); + end; + + if not(checkListBox.checked[applicationSettingsCheck]) then + begin + DelTree(ExpandConstant('{localappdata}\HandheldCompanion'), True, True, True); + end; + end; + + if not(keepHidhideCheckbox.Checked) then + begin + if(ShellExec('', 'msiexec.exe', '/X{BE49B9DE-F8EB-4F54-B312-DD4B601985FC}', '', SW_SHOW, ewWaitUntilTerminated, resultCode)) then + begin + log('Successfully executed Hidhide uninstaller'); + if(resultCode = 0) then + log('Hidhide uninstaller finished successfully') + else + log('Hidhide uninstaller failed with exit code ' +intToStr(resultCode)); + end + else + begin + log('Failed to execute Hidhide uninstaller'); + end; + end; + + if not(keepVigemCheckbox.Checked) then + begin + if(ShellExec('', 'msiexec.exe', '/X{966606F3-2745-49E9-BF15-5C3EAA4E9077}', '', SW_SHOW, ewWaitUntilTerminated, resultCode)) then + begin + log('Successfully executed Vigem uninstaller'); + if(resultCode = 0) then + log('Vigem uninstaller finished successfully') + else + log('Vigem uninstaller failed with exit code ' +intToStr(resultCode)); + end + else + begin + log('Failed to execute Vigem uninstaller'); + end; + end; + end; +end; + + +procedure InitializeWizard; +begin + Dependency_InitializeWizard; +end; + +function PrepareToInstall(var NeedsRestart: Boolean): String; +begin + Result := Dependency_PrepareToInstall(NeedsRestart); +end; + +function NeedRestart: Boolean; +begin + Result := Dependency_NeedRestart; +end; + +function UpdateReadyMemo(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String; +begin + Result := Dependency_UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo); +end; + +function InitializeSetup: Boolean; +begin + +#ifdef UseDotNet80 + Dependency_AddDotNet80Desktop; +#endif + +#ifdef UseVC2005 + Dependency_AddVC2005; +#endif +#ifdef UseVC2008 + Dependency_AddVC2008; +#endif +#ifdef UseVC2010 + Dependency_AddVC2010; +#endif +#ifdef UseVC2012 + Dependency_AddVC2012; +#endif +#ifdef UseVC2013 + Dependency_AddVC2013; +#endif +#ifdef UseVC2015To2019 + Dependency_AddVC2015To2019; +#endif + +#ifdef UseDirectX + Dependency_AddDirectX; +#endif + +#ifdef UseHideHide + Dependency_AddHideHide; +#endif + +#ifdef UseViGem + Dependency_AddViGem; +#endif + +#ifdef UseRTSS + Dependency_AddRTSS; +#endif + + Result := True; +end; + +#endif \ No newline at end of file diff --git a/HandheldCompanion/ADLX_3DSettings.dll b/HandheldCompanion/ADLX_3DSettings.dll new file mode 100644 index 000000000..7cdeefa6f Binary files /dev/null and b/HandheldCompanion/ADLX_3DSettings.dll differ diff --git a/HandheldCompanion/ADLX_DisplaySettings.dll b/HandheldCompanion/ADLX_DisplaySettings.dll new file mode 100644 index 000000000..dc8b70eae Binary files /dev/null and b/HandheldCompanion/ADLX_DisplaySettings.dll differ diff --git a/HandheldCompanion/Actions/AxisActions.cs b/HandheldCompanion/Actions/AxisActions.cs index 40ec13ae4..bd5e31c1a 100644 --- a/HandheldCompanion/Actions/AxisActions.cs +++ b/HandheldCompanion/Actions/AxisActions.cs @@ -21,7 +21,7 @@ public class AxisActions : GyroActions public AxisActions() { - this.ActionType = ActionType.Joystick; + this.actionType = ActionType.Joystick; this.Value = new Vector2(); } diff --git a/HandheldCompanion/Actions/ButtonActions.cs b/HandheldCompanion/Actions/ButtonActions.cs index 5e56ea707..2b95662ac 100644 --- a/HandheldCompanion/Actions/ButtonActions.cs +++ b/HandheldCompanion/Actions/ButtonActions.cs @@ -13,7 +13,7 @@ public class ButtonActions : IActions public ButtonActions() { - this.ActionType = ActionType.Button; + this.actionType = ActionType.Button; this.Value = false; this.prevValue = false; diff --git a/HandheldCompanion/Actions/IActions.cs b/HandheldCompanion/Actions/IActions.cs index 98e03a224..ab25b1683 100644 --- a/HandheldCompanion/Actions/IActions.cs +++ b/HandheldCompanion/Actions/IActions.cs @@ -19,6 +19,17 @@ public enum ActionType Special = 6, } + [Serializable] + public enum ActionState + { + Stopped = 0, + Running = 1, + Aborted = 2, + Succeed = 3, + Suspended = 4, + Forced = 5, + } + [Serializable] public enum ModifierSet { @@ -36,7 +47,9 @@ public enum ModifierSet public enum PressType { Short = 0, - Long = 1, + Long = 1, // hold for x ms and get an action + Hold = 2, // press and hold the command for x ms + Double = 3, } [Serializable] @@ -71,15 +84,17 @@ public abstract class IActions : ICloneable { ModifierSet.ShiftControlAlt, new KeyCode[] { KeyCode.LShift, KeyCode.LControl, KeyCode.LMenu } }, }; - public ActionType ActionType = ActionType.Disabled; + public ActionType actionType = ActionType.Disabled; + public PressType pressType = PressType.Short; + public ActionState actionState = ActionState.Stopped; protected object Value; protected object prevValue; - // TODO: multiple delay, delay ranges - public PressType PressType = PressType.Short; - public int LongPressTime = 450; // default value for steam - protected int pressTimer = -1; // -1 inactive, >= 0 active + public int ActionTimer = 200; // default value for steam + public int pressTimer = -1; // -1 inactive, >= 0 active + + private int pressCount = 0; // used to store previous press value for double tap public bool Turbo; public int TurboDelay = 30; @@ -89,6 +104,8 @@ public abstract class IActions : ICloneable public bool Toggle; protected bool IsToggled; + public bool Interruptable = true; + public HapticMode HapticMode = HapticMode.Off; public HapticStrength HapticStrength = HapticStrength.Low; @@ -110,21 +127,203 @@ public virtual void SetHaptic(ButtonFlags button, bool up) public virtual void Execute(ButtonFlags button, bool value) { - switch(PressType) + if (actionState == ActionState.Suspended) + { + // bypass output + this.Value = false; + this.prevValue = value; + return; + } + else if (actionState == ActionState.Forced) + { + // bypass output + value = true; + } + + switch (pressType) { case PressType.Long: { - if (value || (pressTimer <= LongPressTime && pressTimer >= 0)) + if (value) + { + // update state + actionState = ActionState.Running; + + // update timer + pressTimer += TimerManager.GetPeriod(); + + if (pressTimer >= ActionTimer) + { + // update state + actionState = ActionState.Succeed; + } + else + { + // bypass output + this.Value = false; + this.prevValue = value; + return; + } + } + else + { + // key was released too early + if (actionState == ActionState.Running) + { + // update state + actionState = ActionState.Aborted; + + // update timer + pressTimer = Math.Max(50, pressTimer); + } + else if (actionState == ActionState.Succeed) + { + // update state + actionState = ActionState.Stopped; + + // update timer + pressTimer = -1; + } + else if (actionState == ActionState.Stopped) + { + // update timer + pressTimer = -1; + } + + if (actionState == ActionState.Aborted) + { + // set to aborted for a time equal to the actions was "running" + if (pressTimer >= 0) + { + // update state + actionState = ActionState.Aborted; + + // update timer + pressTimer -= TimerManager.GetPeriod(); + } + else + { + // update state + actionState = ActionState.Stopped; + + // update timer + pressTimer = -1; + } + } + } + } + break; + + case PressType.Hold: + { + if (value || (pressTimer <= ActionTimer && pressTimer >= 0)) { + // update state + actionState = ActionState.Running; + + // update timer pressTimer += TimerManager.GetPeriod(); + + // bypass output (simple) value = true; } - else if(pressTimer >= LongPressTime) + else if (pressTimer >= ActionTimer) { + // update state + actionState = ActionState.Stopped; + + // reset var(s) pressTimer = -1; } } break; + + case PressType.Double: + { + if (value) + { + // increase press count + if ((bool)prevValue != value) + pressCount++; + } + + switch (pressCount) + { + default: + { + if (actionState != ActionState.Stopped) + { + // update timer + pressTimer += TimerManager.GetPeriod(); + + if (pressTimer >= 50) + { + // update state + actionState = ActionState.Stopped; + + // reset var(s) + pressCount = 0; + pressTimer = 0; + } + } + + // bypass output + this.Value = false; + this.prevValue = value; + return; + } + + case 1: + { + // update state + actionState = ActionState.Running; + + // update timer + pressTimer += TimerManager.GetPeriod(); + + // too slow to press again ? + if (pressTimer > ActionTimer) + { + // update state + actionState = ActionState.Aborted; + + // reset var(s) + pressCount = 0; + pressTimer = 0; + } + + // bypass output + this.Value = false; + this.prevValue = value; + return; + } + + case 2: + { + // on time + if (pressTimer <= ActionTimer && value) + { + // update state + actionState = ActionState.Succeed; + + // reset var(s) + pressCount = 2; + pressTimer = ActionTimer; + } + else + { + // update state + actionState = ActionState.Stopped; + + // reset var(s) + pressCount = 0; + pressTimer = 0; + } + } + break; + } + } + break; } if (Toggle) diff --git a/HandheldCompanion/Actions/KeyboardActions.cs b/HandheldCompanion/Actions/KeyboardActions.cs index d58a37739..6f1c488af 100644 --- a/HandheldCompanion/Actions/KeyboardActions.cs +++ b/HandheldCompanion/Actions/KeyboardActions.cs @@ -20,7 +20,7 @@ public class KeyboardActions : IActions public KeyboardActions() { - this.ActionType = ActionType.Keyboard; + this.actionType = ActionType.Keyboard; this.Value = false; this.prevValue = false; diff --git a/HandheldCompanion/Actions/MouseActions.cs b/HandheldCompanion/Actions/MouseActions.cs index fdc4941be..97fdc8c00 100644 --- a/HandheldCompanion/Actions/MouseActions.cs +++ b/HandheldCompanion/Actions/MouseActions.cs @@ -59,7 +59,7 @@ public class MouseActions : GyroActions public MouseActions() { - this.ActionType = ActionType.Mouse; + this.actionType = ActionType.Mouse; this.Value = false; this.prevValue = false; diff --git a/HandheldCompanion/Actions/SpecialActions.cs b/HandheldCompanion/Actions/SpecialActions.cs index e71040516..5845e0194 100644 --- a/HandheldCompanion/Actions/SpecialActions.cs +++ b/HandheldCompanion/Actions/SpecialActions.cs @@ -32,7 +32,7 @@ public class SpecialActions : IActions public SpecialActions() { - this.ActionType = ActionType.Special; + this.actionType = ActionType.Special; } public SpecialActions(SpecialActionsType type) : this() diff --git a/HandheldCompanion/Actions/TriggerActions.cs b/HandheldCompanion/Actions/TriggerActions.cs index 5aa394b9c..e18661611 100644 --- a/HandheldCompanion/Actions/TriggerActions.cs +++ b/HandheldCompanion/Actions/TriggerActions.cs @@ -16,7 +16,7 @@ public class TriggerActions : IActions public TriggerActions() { - this.ActionType = ActionType.Trigger; + this.actionType = ActionType.Trigger; this.Value = (short)0; } diff --git a/HandheldCompanion/App.config b/HandheldCompanion/App.config index bf7669c66..a3ffdcfcf 100644 --- a/HandheldCompanion/App.config +++ b/HandheldCompanion/App.config @@ -185,9 +185,6 @@ True - - True - 3 @@ -227,6 +224,9 @@ False + + False + 0 @@ -245,6 +245,12 @@ False + + False + + + 2 + \ No newline at end of file diff --git a/HandheldCompanion/App.xaml b/HandheldCompanion/App.xaml index 0f61123f6..e41d783e8 100644 --- a/HandheldCompanion/App.xaml +++ b/HandheldCompanion/App.xaml @@ -68,6 +68,10 @@ + + \ No newline at end of file diff --git a/HandheldCompanion/Controllers/DS4Controller.cs b/HandheldCompanion/Controllers/DS4Controller.cs index 7028dc7b5..a081322cf 100644 --- a/HandheldCompanion/Controllers/DS4Controller.cs +++ b/HandheldCompanion/Controllers/DS4Controller.cs @@ -112,11 +112,6 @@ public override void SetLightColor(byte R, byte G, byte B) }); } - public override void Cleanup() - { - TimerManager.Tick -= UpdateInputs; - } - public override string GetGlyph(ButtonFlags button) { switch (button) diff --git a/HandheldCompanion/Controllers/DualSenseController.cs b/HandheldCompanion/Controllers/DualSenseController.cs index 2c9884e36..f23bb9eba 100644 --- a/HandheldCompanion/Controllers/DualSenseController.cs +++ b/HandheldCompanion/Controllers/DualSenseController.cs @@ -105,11 +105,6 @@ public override void SetLightColor(byte R, byte G, byte B) }); } - public override void Cleanup() - { - TimerManager.Tick -= UpdateInputs; - } - public override string GetGlyph(ButtonFlags button) { switch (button) diff --git a/HandheldCompanion/Controllers/GordonController.cs b/HandheldCompanion/Controllers/GordonController.cs index 637c007f8..14dcdac54 100644 --- a/HandheldCompanion/Controllers/GordonController.cs +++ b/HandheldCompanion/Controllers/GordonController.cs @@ -282,11 +282,6 @@ private void Close() catch { } } - public override void Cleanup() - { - TimerManager.Tick -= UpdateInputs; - } - public ushort GetHapticIntensity(byte input, ushort maxIntensity) { return (ushort)(input * maxIntensity * VibrationStrength / 255); diff --git a/HandheldCompanion/Controllers/IController.xaml.cs b/HandheldCompanion/Controllers/IController.xaml.cs index 8ab2a6e99..7e3f74323 100644 --- a/HandheldCompanion/Controllers/IController.xaml.cs +++ b/HandheldCompanion/Controllers/IController.xaml.cs @@ -2,7 +2,7 @@ using HandheldCompanion.Inputs; using HandheldCompanion.Managers; using HandheldCompanion.Utils; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using System; using System.Collections.Generic; using System.Linq; @@ -354,11 +354,6 @@ public virtual void Unplug() }); } - // like Unplug but one that can be safely called when controller is already removed - public virtual void Cleanup() - { - } - public bool IsHidden() { // bool hide_device = HidHide.IsRegistered(Details.deviceInstanceId); diff --git a/HandheldCompanion/Controllers/LegionController.cs b/HandheldCompanion/Controllers/LegionController.cs index d3ea3b717..d870afbef 100644 --- a/HandheldCompanion/Controllers/LegionController.cs +++ b/HandheldCompanion/Controllers/LegionController.cs @@ -37,15 +37,22 @@ private enum BackEnum Y1 = 128, } + private enum ControllerState + { + Unk0 = 0, + Unk1 = 1, + Wired = 2, + Wireless = 3, + } + private HidDevice hidDevice; private const byte FRONT_IDX = 17; private const byte BACK_IDX = 19; private const byte STATUS_IDX = 0; - private const byte PING_IDX = 40; - private HashSet READY_STATES = new HashSet() {25, 60}; + private const byte LCONTROLLER_STATE_IDX = 11; + private const byte RCONTROLLER_STATE_IDX = 12; - private const byte MIN_WIRELESS_STATUS = 40; - private const byte MAX_WIRELESS_STATUS = 50; + private HashSet READY_STATES = new HashSet() {25, 60}; private Thread dataThread; private bool dataThreadRunning; @@ -64,8 +71,9 @@ public bool IsWireless { get { - byte status = GetStatus(PING_IDX); - return (status >= MIN_WIRELESS_STATUS && status <= MAX_WIRELESS_STATUS); + byte LControllerState = GetStatus(LCONTROLLER_STATE_IDX); + byte RControllerState = GetStatus(RCONTROLLER_STATE_IDX); + return LControllerState == (byte)ControllerState.Wireless || RControllerState == (byte)ControllerState.Wireless; } } @@ -149,36 +157,42 @@ private byte GetStatus(int idx) public override void Plug() { hidDevice = GetHidDevice(); - if (hidDevice is not null && hidDevice.IsConnected) { if (!hidDevice.IsOpen) - hidDevice.OpenDevice(); - - dataThreadRunning = true; - dataThread = new Thread(dataThreadLoop); - dataThread.IsBackground = true; - dataThread.Start(); + hidDevice.OpenDevice(); + + // start data thread + if (dataThread is null) + { + dataThreadRunning = true; + + dataThread = new Thread(dataThreadLoop); + dataThread.IsBackground = true; + dataThread.Start(); + } } base.Plug(); } public override void Unplug() - { + { + // kill data thread + if (dataThread is not null) + { + dataThreadRunning = false; + dataThread.Join(); + dataThread = null; + } + if (hidDevice is not null) { - // kill rumble thread - dataThreadRunning = false; - if (dataThread is not null) - dataThread.Join(); - if (hidDevice.IsConnected && hidDevice.IsOpen) - { - hidDevice.CloseDevice(); - hidDevice.Dispose(); - hidDevice = null; - } + hidDevice.CloseDevice(); + + hidDevice.Dispose(); + hidDevice = null; } base.Unplug(); @@ -240,12 +254,13 @@ private async void dataThreadLoop(object? obj) continue; HidReport report = hidDevice.ReadReport(); - if (report is not null) { // check if packet is safe - if (READY_STATES.Contains(report.Data[STATUS_IDX])) - Data = report.Data; + if (READY_STATES.Contains(report.Data[STATUS_IDX])) + { + Data = report.Data; + } } } } diff --git a/HandheldCompanion/Controllers/ProController.cs b/HandheldCompanion/Controllers/ProController.cs index 170232f27..e3d9b08d9 100644 --- a/HandheldCompanion/Controllers/ProController.cs +++ b/HandheldCompanion/Controllers/ProController.cs @@ -48,11 +48,6 @@ public override void Unplug() base.Unplug(); } - public override void Cleanup() - { - TimerManager.Tick -= UpdateInputs; - } - public override void SetVibration(byte LargeMotor, byte SmallMotor) { // HD rumble isn't yet supported diff --git a/HandheldCompanion/Controllers/XInputController.cs b/HandheldCompanion/Controllers/XInputController.cs index 4e06b6faf..819c718c3 100644 --- a/HandheldCompanion/Controllers/XInputController.cs +++ b/HandheldCompanion/Controllers/XInputController.cs @@ -159,11 +159,6 @@ public override void Unplug() base.Unplug(); } - public override void Cleanup() - { - TimerManager.Tick -= UpdateInputs; - } - public static UserIndex TryGetUserIndex(PnPDetails details) { XInputCapabilitiesEx capabilitiesEx = new(); diff --git a/HandheldCompanion/Controls/Hints/Hint_AMD_IntegerScalingCheck.cs b/HandheldCompanion/Controls/Hints/Hint_AMD_IntegerScalingCheck.cs new file mode 100644 index 000000000..74f017a12 --- /dev/null +++ b/HandheldCompanion/Controls/Hints/Hint_AMD_IntegerScalingCheck.cs @@ -0,0 +1,80 @@ +using HandheldCompanion.Managers; +using HandheldCompanion.Misc; +using HandheldCompanion.Processors; +using HandheldCompanion.Utils; +using iNKORE.UI.WPF.Modern.Controls; +using System; +using System.Diagnostics; +using System.Management; +using System.Windows; + +namespace HandheldCompanion.Controls.Hints +{ + public class Hint_AMD_IntegerScalingCheck : IHint + { + public Hint_AMD_IntegerScalingCheck() : base() + { + // default state + this.HintActionButton.Visibility = Visibility.Visible; + + this.HintTitle.Text = Properties.Resources.Hint_AMD_IntegerScalingCheck; + this.HintDescription.Text = Properties.Resources.Hint_AMD_IntegerScalingCheckDesc; + this.HintReadMe.Text = Properties.Resources.Hint_AMD_IntegerScalingCheckReadme; + + this.HintActionButton.Content = Properties.Resources.Hint_AMD_IntegerScalingCheckAction; + + // manage events + PerformanceManager.Initialized += PerformanceManager_Initialized; + } + + private void PerformanceManager_Initialized() + { + Processor processor = PerformanceManager.GetProcessor(); + + if (processor is not null && processor is AMDProcessor) + CheckSettings(); + } + + private void CheckSettings() + { + // read OS specific values + int EmbeddedIntegerScalingSupport = RegistryUtils.GetInt(@"SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000", "DalEmbeddedIntegerScalingSupport"); + + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + this.Visibility = EmbeddedIntegerScalingSupport != 1 ? Visibility.Visible : Visibility.Collapsed; + }); + } + + protected override async void HintActionButton_Click(object sender, RoutedEventArgs e) + { + RegistryUtils.SetValue(@"SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000", "DalEmbeddedIntegerScalingSupport", 1); + + var result = Dialog.ShowAsync($"{Properties.Resources.Dialog_ForceRestartTitle}", + $"{Properties.Resources.Dialog_ForceRestartDesc}", + ContentDialogButton.Primary, null, + $"{Properties.Resources.Dialog_Yes}", + $"{Properties.Resources.Dialog_No}"); + + await result; + + switch (result.Result) + { + case ContentDialogResult.Primary: + using (Process shutdown = new()) + { + shutdown.StartInfo.FileName = "shutdown.exe"; + shutdown.StartInfo.Arguments = "-r -t 3"; + + shutdown.StartInfo.UseShellExecute = false; + shutdown.StartInfo.CreateNoWindow = true; + shutdown.Start(); + } + break; + case ContentDialogResult.Secondary: + break; + } + } + } +} diff --git a/HandheldCompanion/Controls/Hints/Hint_CoreIsolationCheck.cs b/HandheldCompanion/Controls/Hints/Hint_CoreIsolationCheck.cs index 54537025b..8630a0700 100644 --- a/HandheldCompanion/Controls/Hints/Hint_CoreIsolationCheck.cs +++ b/HandheldCompanion/Controls/Hints/Hint_CoreIsolationCheck.cs @@ -1,6 +1,6 @@ using HandheldCompanion.Misc; using HandheldCompanion.Utils; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using System; using System.Diagnostics; using System.Management; diff --git a/HandheldCompanion/Controls/Hints/Hint_LegionGoLegionSpace.cs b/HandheldCompanion/Controls/Hints/Hint_LegionGoLegionSpace.cs new file mode 100644 index 000000000..8f74c2b31 --- /dev/null +++ b/HandheldCompanion/Controls/Hints/Hint_LegionGoLegionSpace.cs @@ -0,0 +1,128 @@ +using HandheldCompanion.Devices; +using HandheldCompanion.Utils; +using HandheldCompanion.Views; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.ServiceProcess; +using System.Threading.Tasks; +using System.Timers; +using System.Windows; + +namespace HandheldCompanion.Controls.Hints +{ + public class Hint_LegionGoLegionSpace : IHint + { + private List serviceNames = new() + { + "DAService", + }; + + private List taskNames = new() + { + "LegionGoQuickSettings", + "LegionSpace", + "LSDaemon" + }; + + private List serviceControllers = new(); + private Timer serviceTimer; + + public Hint_LegionGoLegionSpace() : base() + { + if (MainWindow.CurrentDevice is not LegionGo) + return; + + // Get all the services installed on the local computer + ServiceController[] services = ServiceController.GetServices(); + foreach (string serviceName in serviceNames) + { + if (services.Any(s => serviceNames.Contains(s.ServiceName))) + { + // Create a service controller object for the specified service + ServiceController serviceController = new ServiceController(serviceName); + serviceControllers.Add(serviceController); + } + } + + // Check if any of the services in the list exist + if (!serviceControllers.Any()) + return; + + serviceTimer = new Timer(4000); + serviceTimer.Elapsed += ServiceTimer_Elapsed; + serviceTimer.Start(); + + // default state + this.HintActionButton.Visibility = Visibility.Visible; + + this.HintTitle.Text = Properties.Resources.Hint_LegionGoServices; + this.HintDescription.Text = Properties.Resources.Hint_LegionGoServicesDesc; + this.HintReadMe.Text = Properties.Resources.Hint_LegionGoServicesReadme; + + this.HintActionButton.Content = Properties.Resources.Hint_LegionGoServicesAction; + } + + private void ServiceTimer_Elapsed(object? sender, ElapsedEventArgs e) + { + if (!serviceControllers.Any()) + return; + + // Check if any of the services in the list exist and are running + bool anyRunning = false; + + foreach (ServiceController serviceController in serviceControllers) + { + serviceController.Refresh(); + if (serviceController.Status == ServiceControllerStatus.Running) + { + anyRunning = true; + break; + } + } + + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + this.Visibility = anyRunning ? Visibility.Visible : Visibility.Collapsed; + }); + } + + protected override void HintActionButton_Click(object sender, RoutedEventArgs e) + { + if (!serviceControllers.Any()) + return; + + Task.Run(async () => + { + // Disable services + foreach (ServiceController serviceController in serviceControllers) + { + // Disable service from doing anything anymore + ServiceUtils.ChangeStartMode(serviceController, ServiceStartMode.Disabled, out string error); + + // Stop tasks related to service + foreach (string taskName in taskNames) + { + var taskProcess = Process.GetProcessesByName(taskName).FirstOrDefault(); + if (taskProcess != null && !taskProcess.HasExited) + { + taskProcess.Kill(); + } + } + + // Stop running service + if (serviceController.Status == ServiceControllerStatus.Running) + serviceController.Stop(); + } + }); + } + + public override void Stop() + { + serviceTimer.Stop(); + base.Stop(); + } + } +} diff --git a/HandheldCompanion/Controls/Mapping/AxisMapping.xaml b/HandheldCompanion/Controls/Mapping/AxisMapping.xaml index 1bac32689..913421d36 100644 --- a/HandheldCompanion/Controls/Mapping/AxisMapping.xaml +++ b/HandheldCompanion/Controls/Mapping/AxisMapping.xaml @@ -6,12 +6,12 @@ xmlns:local="clr-namespace:HandheldCompanion.Controls" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" - d:Background="White" + d:Background="Black" d:DesignHeight="1500" d:DesignWidth="800" mc:Ignorable="d"> - + @@ -60,475 +60,565 @@ + - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0} °, ElementName=Axis2AxisRotation, Mode=OneWay}" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + FlowDirection="LeftToRight" + IsMoveToPointEnabled="True" + IsSnapToTickEnabled="True" + Maximum="270" + Minimum="0" + ScrollViewer.PanningMode="HorizontalOnly" + Style="{DynamicResource SliderStyle1}" + TickFrequency="90" + TickPlacement="BottomRight" + ToolTip="{Binding Value, StringFormat=N0, RelativeSource={RelativeSource Self}, Mode=OneWay}" + ValueChanged="Axis_Rotation_Slider_ValueChanged" /> + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat=N3, ElementName=Axis2MouseFilterCutoff, Mode=OneWay}" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HandheldCompanion/Controls/Mapping/AxisMapping.xaml.cs b/HandheldCompanion/Controls/Mapping/AxisMapping.xaml.cs index bc5abbc14..90492dfa3 100644 --- a/HandheldCompanion/Controls/Mapping/AxisMapping.xaml.cs +++ b/HandheldCompanion/Controls/Mapping/AxisMapping.xaml.cs @@ -3,7 +3,7 @@ using HandheldCompanion.Inputs; using HandheldCompanion.Managers; using HandheldCompanion.Utils; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using System; using System.Windows; using System.Windows.Controls; @@ -53,7 +53,7 @@ internal void SetIActions(IActions actions) base.SetIActions(actions); // update UI - ActionComboBox.SelectedIndex = (int)actions.ActionType; + ActionComboBox.SelectedIndex = (int)actions.actionType; } private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -70,10 +70,10 @@ private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) TargetComboBox.IsEnabled = ActionComboBox.SelectedIndex != 0; // get current controller - var controller = ControllerManager.GetEmulatedController(); + IController? controller = ControllerManager.GetEmulatedController(); // populate target dropdown based on action type - var type = (ActionType)ActionComboBox.SelectedIndex; + ActionType type = (ActionType)ActionComboBox.SelectedIndex; if (type == ActionType.Disabled) { @@ -91,10 +91,10 @@ private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) if (controller is null) return; - foreach (var axis in IController.GetTargetAxis()) + foreach (AxisLayoutFlags axis in IController.GetTargetAxis()) { // create a label, store ButtonFlags as Tag and Label as controller specific string - var buttonLabel = new Label { Tag = axis, Content = controller.GetAxisName(axis) }; + Label buttonLabel = new Label { Tag = axis, Content = controller.GetAxisName(axis) }; TargetComboBox.Items.Add(buttonLabel); if (axis.Equals(((AxisActions)Actions).Axis)) @@ -129,8 +129,7 @@ private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) } // create a label, store MouseActionsType as Tag and Label as controller specific string - var buttonLabel = new Label - { Tag = mouseType, Content = EnumUtils.GetDescriptionFromEnumValue(mouseType) }; + Label buttonLabel = new Label { Tag = mouseType, Content = EnumUtils.GetDescriptionFromEnumValue(mouseType) }; TargetComboBox.Items.Add(buttonLabel); if (mouseType.Equals(((MouseActions)Actions).MouseType)) @@ -148,6 +147,10 @@ private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) Axis2MouseFilterCutoff.Value = ((MouseActions)this.Actions).FilterCutoff; } + // if no target element was selected, pick the first one + if (TargetComboBox.SelectedItem is null) + TargetComboBox.SelectedIndex = 0; + base.Update(); } @@ -160,7 +163,7 @@ private void Target_SelectionChanged(object sender, SelectionChangedEventArgs e) return; // generate IActions based on settings - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: { @@ -191,7 +194,7 @@ private void Axis2AxisAutoRotate_Toggled(object sender, RoutedEventArgs e) if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AutoRotate = Axis2AxisAutoRotate.IsOn; @@ -206,7 +209,7 @@ private void Axis_Rotation_Slider_ValueChanged(object sender, RoutedPropertyChan if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AxisInverted = (((int)Axis2AxisRotation.Value / 90) & 2) == 2; @@ -222,7 +225,7 @@ private void Axis_InnerDeadzone_Slider_ValueChanged(object sender, RoutedPropert if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AxisDeadZoneInner = (int)Axis2AxisInnerDeadzone.Value; @@ -237,7 +240,7 @@ private void Axis_OuterDeadzone_Slider_ValueChanged(object sender, RoutedPropert if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AxisDeadZoneOuter = (int)Axis2AxisOuterDeadzone.Value; @@ -252,7 +255,7 @@ private void Axis_AntiDeadZone_Slider_ValueChanged(object sender, RoutedProperty if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AxisAntiDeadZone = (int)Axis2AxisAntiDeadzone.Value; @@ -267,7 +270,7 @@ private void Axis2AxisImproveCircularity_Toggled(object sender, RoutedEventArgs if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).ImproveCircularity = Axis2AxisImproveCircularity.IsOn; @@ -282,7 +285,7 @@ private void Axis2MousePointerSpeed_ValueChanged(object sender, RoutedPropertyCh if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Mouse: ((MouseActions)Actions).Sensivity = (int)Axis2MousePointerSpeed.Value; @@ -297,7 +300,7 @@ private void Axis2MouseAutoRotate_Toggled(object sender, RoutedEventArgs e) if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Mouse: ((MouseActions)Actions).AutoRotate = Axis2MouseAutoRotate.IsOn; @@ -312,7 +315,7 @@ private void Axis2MouseRotation_ValueChanged(object sender, RoutedPropertyChange if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Mouse: ((MouseActions)Actions).AxisInverted = (((int)Axis2MouseRotation.Value / 90) & 2) == 2; @@ -328,7 +331,7 @@ private void Axis2MouseDeadzone_ValueChanged(object sender, RoutedPropertyChange if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Mouse: ((MouseActions)Actions).Deadzone = (int)Axis2MouseDeadzone.Value; @@ -343,7 +346,7 @@ private void Axis2MouseAcceleration_ValueChanged(object sender, RoutedPropertyCh if (this.Actions is null) return; - switch (this.Actions.ActionType) + switch (this.Actions.actionType) { case ActionType.Mouse: ((MouseActions)this.Actions).Acceleration = (float)Axis2MouseAcceleration.Value; @@ -359,7 +362,7 @@ private void Axis2MouseFiltering_Toggled(object sender, RoutedEventArgs e) if (this.Actions is null) return; - switch (this.Actions.ActionType) + switch (this.Actions.actionType) { case ActionType.Mouse: ((MouseActions)this.Actions).Filtering = Axis2MouseFiltering.IsOn; @@ -374,7 +377,7 @@ private void Axis2MouseFilterCutoff_ValueChanged(object sender, RoutedPropertyCh if (this.Actions is null) return; - switch (this.Actions.ActionType) + switch (this.Actions.actionType) { case ActionType.Mouse: ((MouseActions)this.Actions).FilterCutoff = (float)Axis2MouseFilterCutoff.Value; diff --git a/HandheldCompanion/Controls/Mapping/ButtonMapping.xaml b/HandheldCompanion/Controls/Mapping/ButtonMapping.xaml index 1f4394781..82ad10483 100644 --- a/HandheldCompanion/Controls/Mapping/ButtonMapping.xaml +++ b/HandheldCompanion/Controls/Mapping/ButtonMapping.xaml @@ -6,7 +6,7 @@ xmlns:local="clr-namespace:HandheldCompanion.Controls" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" - d:Background="White" + d:Background="Black" d:DesignHeight="1000" d:DesignWidth="800" mc:Ignorable="d"> @@ -39,12 +39,14 @@ - - + + + + @@ -73,101 +75,109 @@ - - - - - - - - - - - - - - - - - + + - - + + - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + - - + - - - - - - - - - + Text="{Binding Value, StringFormat={}{0} ms, ElementName=Turbo_Slider, Mode=OneWay}" /> + + + + + + + + - - + + + Text="Interruptable" /> + Toggled="Toggle_Interruptable_Toggled" /> - - - - - - - + BorderThickness="0,1,0,0" /> - - - - + + + Text="Press to toggle" /> - - - - - - - - - - - - - + + BorderThickness="0,1,0,0" /> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HandheldCompanion/Controls/Mapping/ButtonMapping.xaml.cs b/HandheldCompanion/Controls/Mapping/ButtonMapping.xaml.cs index 272f1d223..ad3238b9a 100644 --- a/HandheldCompanion/Controls/Mapping/ButtonMapping.xaml.cs +++ b/HandheldCompanion/Controls/Mapping/ButtonMapping.xaml.cs @@ -4,11 +4,12 @@ using HandheldCompanion.Inputs; using HandheldCompanion.Managers; using HandheldCompanion.Utils; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; +using System.Linq; namespace HandheldCompanion.Controls; @@ -67,7 +68,7 @@ public void SetIActions(IActions actions) base.SetIActions(actions); // update UI - ActionComboBox.SelectedIndex = (int)actions.ActionType; + ActionComboBox.SelectedIndex = (int)actions.actionType; } public IActions GetIActions() @@ -90,10 +91,10 @@ private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) TargetComboBox.IsEnabled = ActionComboBox.SelectedIndex != 0; // get current controller - var controller = ControllerManager.GetEmulatedController(); + IController controller = ControllerManager.GetEmulatedController(); // populate target dropdown based on action type - var type = (ActionType)ActionComboBox.SelectedIndex; + ActionType type = (ActionType)ActionComboBox.SelectedIndex; if (type == ActionType.Disabled) { @@ -107,22 +108,16 @@ private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) if (Actions is null || Actions is not ButtonActions) Actions = new ButtonActions(); - foreach (var button in IController.GetTargetButtons()) + foreach (ButtonFlags button in IController.GetTargetButtons()) { // create a label, store ButtonFlags as Tag and Label as controller specific string - var buttonLabel = new Label { Tag = button, Content = controller.GetButtonName(button) }; + Label buttonLabel = new Label { Tag = button, Content = controller.GetButtonName(button) }; TargetComboBox.Items.Add(buttonLabel); if (button.Equals(((ButtonActions)Actions).Button)) TargetComboBox.SelectedItem = buttonLabel; } - // settings - if (TargetComboBox.SelectedItem is not null) - PressComboBox.SelectedIndex = (int)this.Actions.PressType; - else - this.Actions.PressType = (PressType)PressComboBox.SelectedIndex; - // button specific settings } else if (type == ActionType.Keyboard) @@ -132,10 +127,8 @@ private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) // use optimized lazily created list TargetComboBox.ItemsSource = keyList; - - foreach (var keyLabel in keyList) - if (keyLabel.Tag.Equals(((KeyboardActions)this.Actions).Key)) - TargetComboBox.SelectedItem = keyLabel; + foreach (var keyLabel in keyList.Where(keyLabel => keyLabel.Tag.Equals(((KeyboardActions)this.Actions).Key))) + TargetComboBox.SelectedItem = keyLabel; // keyboard specific settings ModifierComboBox.SelectedIndex = (int)((KeyboardActions)this.Actions).Modifiers; @@ -156,35 +149,34 @@ private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) } // create a label, store MouseActionsType as Tag and Label as controller specific string - var buttonLabel = new Label - { Tag = mouseType, Content = EnumUtils.GetDescriptionFromEnumValue(mouseType) }; + Label buttonLabel = new Label { Tag = mouseType, Content = EnumUtils.GetDescriptionFromEnumValue(mouseType) }; TargetComboBox.Items.Add(buttonLabel); if (mouseType.Equals(((MouseActions)Actions).MouseType)) TargetComboBox.SelectedItem = buttonLabel; } - // settings - if (TargetComboBox.SelectedItem is not null) - PressComboBox.SelectedIndex = (int)this.Actions.PressType; - else - this.Actions.PressType = (PressType)PressComboBox.SelectedIndex; - // mouse specific settings ModifierComboBox.SelectedIndex = (int)((MouseActions)this.Actions).Modifiers; } - // press type is treated specially, it can be set before action + // settings if (TargetComboBox.SelectedItem is not null) - PressComboBox.SelectedIndex = (int)this.Actions.PressType; + PressComboBox.SelectedIndex = (int)this.Actions.pressType; else - this.Actions.PressType = (PressType)PressComboBox.SelectedIndex; - Button2ButtonPressDelay.Visibility = Actions.PressType == PressType.Long ? Visibility.Visible : Visibility.Collapsed; + this.Actions.pressType = (PressType)PressComboBox.SelectedIndex; + + // if no target element was selected, pick the first one + if (TargetComboBox.SelectedItem is null) + TargetComboBox.SelectedIndex = 0; + + Button2ButtonPressDelay.Visibility = Actions.pressType != PressType.Short ? Visibility.Visible : Visibility.Collapsed; // settings - LongPressDelaySlider.Value = (int)this.Actions.LongPressTime; + LongPressDelaySlider.Value = (int)this.Actions.ActionTimer; Toggle_Turbo.IsOn = this.Actions.Turbo; Turbo_Slider.Value = this.Actions.TurboDelay; + Toggle_Interruptable.IsOn = this.Actions.Interruptable; Toggle_Toggle.IsOn = this.Actions.Toggle; HapticModeComboBox.SelectedIndex = (int)this.Actions.HapticMode; HapticStrengthComboBox.SelectedIndex = (int)this.Actions.HapticStrength; @@ -201,7 +193,7 @@ private void Target_SelectionChanged(object sender, SelectionChangedEventArgs e) return; // generate IActions based on settings - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Button: { @@ -240,9 +232,9 @@ private void Press_SelectionChanged(object sender, SelectionChangedEventArgs e) if (this.Actions is null) return; - this.Actions.PressType = (PressType)PressComboBox.SelectedIndex; + this.Actions.pressType = (PressType)PressComboBox.SelectedIndex; - Button2ButtonPressDelay.Visibility = Actions.PressType == PressType.Long ? Visibility.Visible : Visibility.Collapsed; + Button2ButtonPressDelay.Visibility = Actions.pressType != PressType.Short ? Visibility.Visible : Visibility.Collapsed; base.Update(); } @@ -252,7 +244,7 @@ private void LongPressDelaySlider_ValueChanged(object sender, RoutedPropertyChan if (this.Actions is null) return; - this.Actions.LongPressTime = (int)LongPressDelaySlider.Value; + this.Actions.ActionTimer = (int)LongPressDelaySlider.Value; base.Update(); } @@ -264,7 +256,7 @@ private void Modifier_SelectionChanged(object sender, SelectionChangedEventArgs ModifierSet mods = (ModifierSet)ModifierComboBox.SelectedIndex; - switch (this.Actions.ActionType) + switch (this.Actions.actionType) { case ActionType.Keyboard: ((KeyboardActions)this.Actions).Modifiers = mods; @@ -327,4 +319,14 @@ private void HapticStrength_SelectionChanged(object sender, SelectionChangedEven base.Update(); } + + private void Toggle_Interruptable_Toggled(object sender, RoutedEventArgs e) + { + if (this.Actions is null) + return; + + this.Actions.Interruptable = Toggle_Interruptable.IsOn; + + base.Update(); + } } \ No newline at end of file diff --git a/HandheldCompanion/Controls/Mapping/ButtonStack.xaml.cs b/HandheldCompanion/Controls/Mapping/ButtonStack.xaml.cs index ca89c8a1f..dc4d1e16f 100644 --- a/HandheldCompanion/Controls/Mapping/ButtonStack.xaml.cs +++ b/HandheldCompanion/Controls/Mapping/ButtonStack.xaml.cs @@ -1,6 +1,6 @@ using HandheldCompanion.Actions; using HandheldCompanion.Inputs; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; diff --git a/HandheldCompanion/Controls/Mapping/GyroMapping.xaml b/HandheldCompanion/Controls/Mapping/GyroMapping.xaml index 206ee2186..dabe9d517 100644 --- a/HandheldCompanion/Controls/Mapping/GyroMapping.xaml +++ b/HandheldCompanion/Controls/Mapping/GyroMapping.xaml @@ -7,7 +7,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:resx="clr-namespace:HandheldCompanion.Properties" xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" - d:Background="White" + d:Background="Black" d:DesignHeight="1500" d:DesignWidth="800" mc:Ignorable="d"> diff --git a/HandheldCompanion/Controls/Mapping/GyroMapping.xaml.cs b/HandheldCompanion/Controls/Mapping/GyroMapping.xaml.cs index 5dae39bec..b0bfb3d95 100644 --- a/HandheldCompanion/Controls/Mapping/GyroMapping.xaml.cs +++ b/HandheldCompanion/Controls/Mapping/GyroMapping.xaml.cs @@ -3,7 +3,7 @@ using HandheldCompanion.Inputs; using HandheldCompanion.Managers; using HandheldCompanion.Utils; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using System; using System.Windows; using System.Windows.Controls; @@ -100,7 +100,7 @@ internal void SetIActions(IActions actions) GyroHotkey.inputsChord.State = ((GyroActions)actions).MotionTrigger.Clone() as ButtonState; GyroHotkey.DrawInput(); - ActionComboBox.SelectedIndex = (int)actions.ActionType; + ActionComboBox.SelectedIndex = (int)actions.actionType; } private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -231,7 +231,7 @@ private void Target_SelectionChanged(object sender, SelectionChangedEventArgs e) return; // generate IActions based on settings - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: { @@ -262,7 +262,7 @@ private void Axis2AxisAutoRotate_Toggled(object sender, RoutedEventArgs e) if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AutoRotate = Axis2AxisAutoRotate.IsOn; @@ -277,7 +277,7 @@ private void Axis_Rotation_Slider_ValueChanged(object sender, RoutedPropertyChan if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AxisInverted = (((int)Axis2AxisRotation.Value / 90) & 2) == 2; @@ -293,7 +293,7 @@ private void Axis_InnerDeadzone_Slider_ValueChanged(object sender, RoutedPropert if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AxisDeadZoneInner = (int)Axis2AxisInnerDeadzone.Value; @@ -308,7 +308,7 @@ private void Axis_OuterDeadzone_Slider_ValueChanged(object sender, RoutedPropert if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AxisDeadZoneOuter = (int)Axis2AxisOuterDeadzone.Value; @@ -323,7 +323,7 @@ private void Axis_AntiDeadZone_Slider_ValueChanged(object sender, RoutedProperty if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).AxisAntiDeadZone = (int)Axis2AxisAntiDeadzone.Value; @@ -338,7 +338,7 @@ private void Axis2AxisImproveCircularity_Toggled(object sender, RoutedEventArgs if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Joystick: ((AxisActions)Actions).ImproveCircularity = Axis2AxisImproveCircularity.IsOn; @@ -353,7 +353,7 @@ private void Axis2MousePointerSpeed_ValueChanged(object sender, RoutedPropertyCh if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Mouse: ((MouseActions)Actions).Sensivity = (int)Axis2MousePointerSpeed.Value; @@ -368,7 +368,7 @@ private void Axis2MouseAutoRotate_Toggled(object sender, RoutedEventArgs e) if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Mouse: ((MouseActions)Actions).AutoRotate = Axis2MouseAutoRotate.IsOn; @@ -383,7 +383,7 @@ private void Axis2MouseRotation_ValueChanged(object sender, RoutedPropertyChange if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Mouse: ((MouseActions)Actions).AxisInverted = (((int)Axis2MouseRotation.Value / 90) & 2) == 2; @@ -399,7 +399,7 @@ private void Axis2MouseDeadzone_ValueChanged(object sender, RoutedPropertyChange if (Actions is null) return; - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Mouse: ((MouseActions)Actions).Deadzone = (int)Axis2MouseDeadzone.Value; @@ -414,7 +414,7 @@ private void Axis2MouseAcceleration_ValueChanged(object sender, RoutedPropertyCh if (this.Actions is null) return; - switch (this.Actions.ActionType) + switch (this.Actions.actionType) { case ActionType.Mouse: ((MouseActions)this.Actions).Acceleration = (float)Axis2MouseAcceleration.Value; diff --git a/HandheldCompanion/Controls/Mapping/TriggerMapping.xaml b/HandheldCompanion/Controls/Mapping/TriggerMapping.xaml index 0d1c04207..f8e156628 100644 --- a/HandheldCompanion/Controls/Mapping/TriggerMapping.xaml +++ b/HandheldCompanion/Controls/Mapping/TriggerMapping.xaml @@ -7,12 +7,12 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:resx="clr-namespace:HandheldCompanion.Properties" xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" - d:Background="White" + d:Background="Black" d:DesignHeight="1000" d:DesignWidth="800" mc:Ignorable="d"> - + @@ -61,131 +61,154 @@ + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HandheldCompanion/Controls/Mapping/TriggerMapping.xaml.cs b/HandheldCompanion/Controls/Mapping/TriggerMapping.xaml.cs index 852fb6434..4e6439c2c 100644 --- a/HandheldCompanion/Controls/Mapping/TriggerMapping.xaml.cs +++ b/HandheldCompanion/Controls/Mapping/TriggerMapping.xaml.cs @@ -2,7 +2,7 @@ using HandheldCompanion.Controllers; using HandheldCompanion.Inputs; using HandheldCompanion.Managers; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using System.Windows; using System.Windows.Controls; @@ -51,7 +51,7 @@ internal void SetIActions(IActions actions) base.SetIActions(actions); // update UI - ActionComboBox.SelectedIndex = (int)actions.ActionType; + ActionComboBox.SelectedIndex = (int)actions.actionType; } private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -100,6 +100,10 @@ private void Action_SelectionChanged(object sender, SelectionChangedEventArgs e) } } + // if no target element was selected, pick the first one + if (TargetComboBox.SelectedItem is null) + TargetComboBox.SelectedIndex = 0; + // settings Trigger2TriggerInnerDeadzone.Value = ((TriggerActions)this.Actions).AxisDeadZoneInner; Trigger2TriggerOuterDeadzone.Value = ((TriggerActions)this.Actions).AxisDeadZoneOuter; @@ -117,7 +121,7 @@ private void Target_SelectionChanged(object sender, SelectionChangedEventArgs e) return; // generate IActions based on settings - switch (Actions.ActionType) + switch (Actions.actionType) { case ActionType.Trigger: { @@ -135,7 +139,7 @@ private void Trigger2TriggerInnerDeadzone_ValueChanged(object sender, RoutedProp if (this.Actions is null) return; - switch (this.Actions.ActionType) + switch (this.Actions.actionType) { case ActionType.Trigger: ((TriggerActions)this.Actions).AxisDeadZoneInner = (int)Trigger2TriggerInnerDeadzone.Value; @@ -150,7 +154,7 @@ private void Trigger2TriggerOuterDeadzone_ValueChanged(object sender, RoutedProp if (this.Actions is null) return; - switch (this.Actions.ActionType) + switch (this.Actions.actionType) { case ActionType.Trigger: ((TriggerActions)this.Actions).AxisDeadZoneOuter = (int)Trigger2TriggerOuterDeadzone.Value; @@ -165,7 +169,7 @@ private void Trigger2TriggerAntiDeadzone_ValueChanged(object sender, RoutedPrope if (this.Actions is null) return; - switch (this.Actions.ActionType) + switch (this.Actions.actionType) { case ActionType.Trigger: ((TriggerActions)this.Actions).AxisAntiDeadZone = (int)Trigger2TriggerAntiDeadzone.Value; diff --git a/HandheldCompanion/Controls/ProcessEx.xaml b/HandheldCompanion/Controls/ProcessEx.xaml index 1d2382797..202ade3be 100644 --- a/HandheldCompanion/Controls/ProcessEx.xaml +++ b/HandheldCompanion/Controls/ProcessEx.xaml @@ -37,7 +37,7 @@ - + @@ -59,15 +59,63 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - Device profiles - User profiles - - - - - - - - - - - - - + + - - - - + + + + + + + + - - - - - - - - - - - - + + + + @@ -223,14 +261,25 @@ - - - - + + + + + + + + - - - - - - - - - - - - + + + + @@ -303,15 +344,25 @@ - - - - - + + + + + + + + - - - - - - - - - - - + + + + @@ -380,15 +423,25 @@ - - - - - + + + + + + + + - - - - + + - - + AutoToolTipPrecision="0" + IsMoveToPointEnabled="True" + IsSnapToTickEnabled="True" + LargeChange="10" + Maximum="100" + Minimum="0" + SmallChange="1" + Style="{DynamicResource SliderStyle1}" + TickFrequency="10" + TickPlacement="BottomRight" + ToolTip="{Binding Value, StringFormat=N0, RelativeSource={RelativeSource Self}, Mode=OneWay}" + ValueChanged="EPPSlider_ValueChanged" /> + + - - - - - - - - - - - - - - - - - - - - + Text="{x:Static resx:Resources.ProfilesPage_CPU}" /> + + + + @@ -476,21 +507,32 @@ CornerRadius="{DynamicResource ControlCornerRadius}"> - + - - - - + + + + + + + + - - - - - - - - - - - + + + + @@ -554,21 +588,32 @@ Name="StackProfileGPUClock" IsEnabled="False" Spacing="6"> - + - - - - + + + + + + + + - - - - - - - - - - - + + + + @@ -630,14 +667,30 @@ Background="{DynamicResource ExpanderHeaderBackground}" CornerRadius="{DynamicResource ControlCornerRadius}"> - - - - + + + + + + + + + + + + + - - - - + + + + + + + + - - - - + + + + + + + + + { + AutoTDPSlider.Maximum = desktopScreen.devMode.dmDisplayFrequency; + }); + } + private void PowerProfileManager_Deleted(PowerProfile profile) { // UI thread (async) @@ -224,7 +235,7 @@ private void PerformanceManager_EPPChanged(uint EPP) private void PerformanceManager_Initialized() { - Processor processor = MainWindow.performanceManager.GetProcessor(); + Processor processor = PerformanceManager.GetProcessor(); if (processor is null) return; @@ -407,12 +418,31 @@ private void UpdateUI() { using (new ScopedLock(updateLock)) { + if (selectedProfile.DeviceDefault) + { + WarningBorder.Visibility = Visibility.Visible; + WarningContent.Text = Properties.Resources.ProfilesPage_DefaultDeviceProfile; + } + else if (selectedProfile.Default) + { + WarningBorder.Visibility = Visibility.Visible; + WarningContent.Text = Properties.Resources.ProfilesPage_DefaultProfile; + } + else + { + WarningBorder.Visibility = Visibility.Collapsed; + WarningContent.Text = string.Empty; + } + + // Disable everything for device power profiles + PowerPanel.IsEnabled = !selectedProfile.DeviceDefault; + FanPanel.IsEnabled = !selectedProfile.DeviceDefault; + // update PowerProfile settings PowerProfileName.Text = selectedProfile.Name; PowerProfileDescription.Text = selectedProfile.Description; // we shouldn't allow users to modify some of default profile settings - FanMode.IsEnabled = !selectedProfile.Default; ButtonProfileDelete.IsEnabled = !selectedProfile.Default; ButtonProfileMore.IsEnabled = !selectedProfile.Default; diff --git a/HandheldCompanion/Views/Pages/Profiles/SettingsMode0.xaml b/HandheldCompanion/Views/Pages/Profiles/SettingsMode0.xaml index 3e1015d59..083e8592e 100644 --- a/HandheldCompanion/Views/Pages/Profiles/SettingsMode0.xaml +++ b/HandheldCompanion/Views/Pages/Profiles/SettingsMode0.xaml @@ -52,11 +52,13 @@ Grid.Column="1" Margin="12,0,0,0" ScrollViewer.PanningMode="HorizontalOnly"> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N1}, ElementName=SliderSensitivityX, Mode=OneWay}" /> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N1}, ElementName=SliderSensitivityY, Mode=OneWay}" /> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N1}, ElementName=tb_ProfileAimingDownSightsMultiplier, Mode=OneWay}" /> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0} ms, ElementName=tb_ProfileFlickDuration, Mode=OneWay}" /> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N1}, ElementName=tb_ProfileStickSensitivity, Mode=OneWay}" /> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0} °, ElementName=SliderSteeringAngle, Mode=OneWay}" /> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N1}, ElementName=SliderPower, Mode=OneWay}" /> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N1} °, ElementName=SliderDeadzoneAngle, Mode=OneWay}" /> + + + + + @@ -137,57 +149,127 @@ Height="40" FontFamily="{DynamicResource SymbolThemeFontFamily}" Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}" - Glyph="" /> + Glyph="" /> + Text="{x:Static resx:Resources.ProfilesPage_ProfilePath}" /> + BorderThickness="1" + IsEnabled="False" + IsReadOnly="True" /> + - + Glyph="" /> + Text="{x:Static resx:Resources.ProfilesPage_SubProfiles}" /> + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - + Margin="12,0,0,0" + d:Visibility="Visible" + ScrollViewer.PanningMode="HorizontalOnly" + Visibility="{Binding ElementName=RSRToggle, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}"> - - + - - + AutoToolTipPrecision="0" + IsMoveToPointEnabled="True" + IsSnapToTickEnabled="True" + LargeChange="5" + Maximum="100" + Minimum="0" + SmallChange="1" + Style="{DynamicResource SliderStyle1}" + TickFrequency="5" + TickPlacement="BottomRight" + ToolTip="{Binding Value, StringFormat={}{0:N0} %, RelativeSource={RelativeSource Self}, Mode=OneWay}" + ValueChanged="RSRSlider_ValueChanged" /> + + - - + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + SelectionChanged="IntegerScalingComboBox_SelectionChanged" /> + + + + + + - + - - - - - - + + + + + + + - - - - + + + + - - + + - - + - + + + + ValueChanged="RISSlider_ValueChanged" /> + + - - - - - - - - - - + + - - - + + + + + + + + + + + + + + + + + @@ -515,11 +765,11 @@ Glyph="" /> - + @@ -585,11 +835,13 @@ Grid.Column="1" Margin="12,0,0,0" ScrollViewer.PanningMode="HorizontalOnly"> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N1}, ElementName=tb_ProfileGyroValue, Mode=OneWay}" /> - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N1}, ElementName=tb_ProfileAcceleroValue, Mode=OneWay}" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HandheldCompanion/Views/Pages/ProfilesPage.xaml.cs b/HandheldCompanion/Views/Pages/ProfilesPage.xaml.cs index 1d2b1b130..7636336d3 100644 --- a/HandheldCompanion/Views/Pages/ProfilesPage.xaml.cs +++ b/HandheldCompanion/Views/Pages/ProfilesPage.xaml.cs @@ -4,13 +4,17 @@ using HandheldCompanion.Managers; using HandheldCompanion.Managers.Desktop; using HandheldCompanion.Misc; +using HandheldCompanion.Platforms; using HandheldCompanion.Utils; using HandheldCompanion.Views.Pages.Profiles; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using Microsoft.Win32; +using SharpDX.Win32; using System; +using System.Collections.Generic; using System.ComponentModel; using System.IO; +using System.Linq; using System.Timers; using System.Windows; using System.Windows.Controls; @@ -28,6 +32,7 @@ public partial class ProfilesPage : Page { // when set on start cannot be null anymore public static Profile selectedProfile; + private static Profile selectedMainProfile; private readonly SettingsMode0 page0 = new("SettingsMode0"); private readonly SettingsMode1 page1 = new("SettingsMode1"); @@ -37,56 +42,115 @@ public partial class ProfilesPage : Page private const int UpdateInterval = 500; private static Timer UpdateTimer; + public ProfilesPage(string Tag) : this() + { + this.Tag = Tag; + } + public ProfilesPage() { InitializeComponent(); + + // manage events + ProfileManager.Deleted += ProfileDeleted; + ProfileManager.Updated += ProfileUpdated; + ProfileManager.Applied += ProfileApplied; + ProfileManager.Initialized += ProfileManagerLoaded; + PowerProfileManager.Updated += PowerProfileManager_Updated; + PowerProfileManager.Deleted += PowerProfileManager_Deleted; + SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; + SystemManager.Initialized += SystemManager_Initialized; + SystemManager.PrimaryScreenChanged += SystemManager_PrimaryScreenChanged; + SystemManager.StateChanged_RSR += SystemManager_StateChanged_RSR; + SystemManager.StateChanged_IntegerScaling += SystemManager_StateChanged_IntegerScaling; + SystemManager.StateChanged_GPUScaling += SystemManager_StateChanged_GPUScaling; + PlatformManager.RTSS.Updated += RTSS_Updated; UpdateTimer = new Timer(UpdateInterval); UpdateTimer.AutoReset = false; UpdateTimer.Elapsed += (sender, e) => SubmitProfile(); + + // auto-sort + cB_Profiles.Items.SortDescriptions.Add(new SortDescription(string.Empty, ListSortDirection.Descending)); + + // force call + RTSS_Updated(PlatformManager.RTSS.Status); } - public ProfilesPage(string Tag) : this() + private void SystemManager_Initialized() { - this.Tag = Tag; + bool HasScalingModeSupport = ADLXWrapper.HasScalingModeSupport(); + bool HasIntegerScalingSupport = ADLXWrapper.HasIntegerScalingSupport(); + bool HasRSRSupport = ADLXWrapper.HasRSRSupport(); + bool HasGPUScalingSupport = ADLXWrapper.HasGPUScalingSupport(); + bool IsGPUScalingEnabled = ADLXWrapper.GetGPUScaling(); - ProfileManager.Deleted += ProfileDeleted; - ProfileManager.Updated += ProfileUpdated; - ProfileManager.Applied += ProfileApplied; - - PowerProfileManager.Updated += PowerProfileManager_Updated; - PowerProfileManager.Deleted += PowerProfileManager_Deleted; + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + StackProfileRSR.IsEnabled = HasGPUScalingSupport && IsGPUScalingEnabled && HasRSRSupport; + StackProfileIS.IsEnabled = HasGPUScalingSupport && IsGPUScalingEnabled && HasIntegerScalingSupport; + GPUScalingToggle.IsEnabled = HasGPUScalingSupport; + GPUScalingComboBox.IsEnabled = HasGPUScalingSupport && HasScalingModeSupport; - ProfileManager.Initialized += ProfileManagerLoaded; + DesktopScreen desktopScreen = SystemManager.GetDesktopScreen(); + desktopScreen.screenDividers.ForEach(d => IntegerScalingComboBox.Items.Add(d)); + }); + } - SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; + private void SystemManager_StateChanged_RSR(bool Supported, bool Enabled, int Sharpness) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + using (new ScopedLock(updateLock)) + { + StackProfileRSR.IsEnabled = Supported; + } + }); + } - SystemManager.DisplaySettingsChanged += SystemManager_DisplaySettingsChanged; - SystemManager.RSRStateChanged += SystemManager_RSRStateChanged; + private void SystemManager_StateChanged_GPUScaling(bool Supported, bool Enabled, int Mode) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(async () => + { + using (new ScopedLock(updateLock)) + { + GPUScalingToggle.IsEnabled = Supported; + StackProfileRIS.IsEnabled = Supported; // check if processor is AMD should be enough + StackProfileRSR.IsEnabled = Supported; + StackProfileIS.IsEnabled = Supported; + } + }); + } - // auto-sort - cB_Profiles.Items.SortDescriptions.Add(new SortDescription(string.Empty, ListSortDirection.Descending)); + private void SystemManager_StateChanged_IntegerScaling(bool Supported, bool Enabled) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + using (new ScopedLock(updateLock)) + { + StackProfileIS.IsEnabled = Supported; + } + }); } - private void SystemManager_RSRStateChanged(int RSRState, int RSRSharpness) + private void RTSS_Updated(PlatformStatus status) { // UI thread (async) Application.Current.Dispatcher.BeginInvoke(() => { - switch (RSRState) + switch (status) { - case -1: - RSRToggle.IsEnabled = false; + case PlatformStatus.Ready: + var Processor = PerformanceManager.GetProcessor(); + StackProfileFramerate.IsEnabled = true; break; - case 0: - RSRToggle.IsEnabled = true; - RSRToggle.IsOn = false; - RSRSlider.Value = RSRSharpness; - break; - case 1: - RSRToggle.IsEnabled = true; - RSRToggle.IsOn = true; - RSRSlider.Value = RSRSharpness; + case PlatformStatus.Stalled: + // StackProfileFramerate.IsEnabled = false; + // StackProfileAutoTDP.IsEnabled = false; break; } }); @@ -103,17 +167,19 @@ public void SettingsManager_SettingValueChanged(string name, object value) }); } - private void SystemManager_DisplaySettingsChanged(ScreenResolution resolution) + private void SystemManager_PrimaryScreenChanged(DesktopScreen desktopScreen) { + List frameLimits = desktopScreen.GetFramelimits(); + // UI thread (async) Application.Current.Dispatcher.BeginInvoke(() => { - var screenFrequency = SystemManager.GetDesktopScreen().GetFrequency(); + cB_Framerate.Items.Clear(); + + foreach (ScreenFramelimit frameLimit in frameLimits) + cB_Framerate.Items.Add(frameLimit); - FramerateQuarter.Content = Convert.ToString(screenFrequency.GetValue(Frequency.Quarter)); - FramerateThird.Content = Convert.ToString(screenFrequency.GetValue(Frequency.Third)); - FramerateHalf.Content = Convert.ToString(screenFrequency.GetValue(Frequency.Half)); - FramerateFull.Content = Convert.ToString(screenFrequency.GetValue(Frequency.Full)); + cB_Framerate.SelectedItem = desktopScreen.GetClosest(selectedProfile.FramerateValue); }); } @@ -403,23 +469,15 @@ private void cB_Profiles_SelectionChanged(object sender, SelectionChangedEventAr if (cB_Profiles.SelectedItem is null) return; - // if an update is pending, cut it short, it will disturb profile selection though - if (UpdateTimer.Enabled) - { - UpdateTimer.Stop(); - SubmitProfile(); - } - - selectedProfile = (Profile)cB_Profiles.SelectedItem; - - UpdateUI(); + selectedMainProfile = (Profile)cB_Profiles.SelectedItem; + UpdateSubProfiles(); } private void UpdateMotionControlsVisibility() { bool MotionMapped = false; if (selectedProfile.Layout.GyroLayout.TryGetValue(AxisLayoutFlags.Gyroscope, out IActions action)) - if (action is not null && action.ActionType != ActionType.Disabled) + if (action is not null && action.actionType != ActionType.Disabled) MotionMapped = true; // UI thread (async) @@ -429,6 +487,7 @@ private void UpdateMotionControlsVisibility() }); } + private DesktopScreen desktopScreen; private void UpdateUI() { if (selectedProfile is null) @@ -439,19 +498,36 @@ private void UpdateUI() { using (new ScopedLock(updateLock)) { - // disable delete button if is default profile or running - b_DeleteProfile.IsEnabled = !selectedProfile.ErrorCode.HasFlag(ProfileErrorCode.Default & ProfileErrorCode.Running); + // disable delete button if is default profile or any sub profile is running + b_DeleteProfile.IsEnabled = !selectedProfile.ErrorCode.HasFlag(ProfileErrorCode.Default & ProfileErrorCode.Running); //TODO consider sub profiles pertaining to this main profile is running // prevent user from renaming default profile - tB_ProfileName.IsEnabled = !selectedProfile.Default; + b_ProfileRename.IsEnabled = !selectedMainProfile.Default; // prevent user from disabling default profile Toggle_EnableProfile.IsEnabled = !selectedProfile.Default; // prevent user from disabling default profile layout Toggle_ControllerLayout.IsEnabled = !selectedProfile.Default; // prevent user from using Wrapper on default profile cB_Wrapper.IsEnabled = !selectedProfile.Default; + UseFullscreenOptimizations.IsEnabled = !selectedProfile.Default; + UseHighDPIAwareness.IsEnabled = !selectedProfile.Default; + + // sub profiles + b_SubProfileCreate.IsEnabled = !selectedMainProfile.Default; + + // enable delete and rename if not default sub profile + if (cb_SubProfilePicker.SelectedIndex == 0) // main profile + { + b_SubProfileDelete.IsEnabled = false; + b_SubProfileRename.IsEnabled = false; + } + else // actual sub profile + { + b_SubProfileDelete.IsEnabled = true; + b_SubProfileRename.IsEnabled = true; + } // Profile info - tB_ProfileName.Text = selectedProfile.Name; + tB_ProfileName.Text = selectedMainProfile.Name; tB_ProfilePath.Text = selectedProfile.Path; Toggle_EnableProfile.IsOn = selectedProfile.Enabled; @@ -483,13 +559,32 @@ private void UpdateUI() UpdateMotionControlsVisibility(); + // Framerate limit + desktopScreen = SystemManager.GetDesktopScreen(); + if (desktopScreen is not null) + cB_Framerate.SelectedItem = desktopScreen.GetClosest(selectedProfile.FramerateValue); + + // GPU Scaling + GPUScalingToggle.IsOn = selectedProfile.GPUScaling; + GPUScalingComboBox.SelectedIndex = selectedProfile.ScalingMode; + // RSR RSRToggle.IsOn = selectedProfile.RSREnabled; RSRSlider.Value = selectedProfile.RSRSharpness; - // Framerate limit - FramerateToggle.IsOn = selectedProfile.FramerateEnabled; - FramerateSlider.Value = selectedProfile.FramerateValue; + // Integer Scaling + IntegerScalingToggle.IsOn = selectedProfile.IntegerScalingEnabled; + + if (desktopScreen is not null) + IntegerScalingComboBox.SelectedItem = desktopScreen.screenDividers.FirstOrDefault(d => d.divider == selectedProfile.IntegerScalingDivider); + + // RIS + RISToggle.IsOn = selectedProfile.RISEnabled; + RISSlider.Value = selectedProfile.RISSharpness; + + // Compatibility settings + UseFullscreenOptimizations.IsOn = selectedProfile.FullScreenOptimization; + UseHighDPIAwareness.IsOn = selectedProfile.HighDPIAware; // Layout settings Toggle_ControllerLayout.IsOn = selectedProfile.LayoutEnabled; @@ -535,17 +630,55 @@ private void UpdateUI() cB_Wrapper_Redirection.IsEnabled = false; break; } + + // update dropdown lists + cB_Profiles.Items.Refresh(); + cb_SubProfilePicker.Items.Refresh(); } }); } + private void UpdateSubProfiles() + { + if (selectedMainProfile is null) + return; + + var ind = 0; // default or main profile itself + + // add main profile as first subprofile + cb_SubProfilePicker.Items.Clear(); + cb_SubProfilePicker.Items.Add(selectedMainProfile); + + // if main profile is not default, occupy sub profiles dropdown list + if (!selectedMainProfile.Default) + { + foreach (Profile subprofile in ProfileManager.GetSubProfilesFromPath(selectedMainProfile.Path, false)) + { + cb_SubProfilePicker.Items.Add(subprofile); + + // select sub profile if it's favorite for main profile + if (subprofile.IsFavoriteSubProfile) + ind = cb_SubProfilePicker.Items.IndexOf(subprofile); + } + } + + // refresh sub profiles dropdown + cb_SubProfilePicker.Items.Refresh(); + + // set subprofile to be applied + cb_SubProfilePicker.SelectedIndex = ind; + + // update UI elements + UpdateUI(); + } + private async void b_DeleteProfile_Click(object sender, RoutedEventArgs e) { if (selectedProfile is null) return; var result = Dialog.ShowAsync( - $"{Properties.Resources.ProfilesPage_AreYouSureDelete1} \"{selectedProfile.Name}\"?", + $"{Properties.Resources.ProfilesPage_AreYouSureDelete1} \"{selectedMainProfile.Name}\"?", $"{Properties.Resources.ProfilesPage_AreYouSureDelete2}", ContentDialogButton.Primary, $"{Properties.Resources.ProfilesPage_Cancel}", @@ -555,7 +688,7 @@ private async void b_DeleteProfile_Click(object sender, RoutedEventArgs e) switch (result.Result) { case ContentDialogResult.Primary: - ProfileManager.DeleteProfile(selectedProfile); + ProfileManager.DeleteProfile(selectedMainProfile); cB_Profiles.SelectedIndex = 0; break; } @@ -613,65 +746,6 @@ private void Toggle_EnableProfile_Toggled(object sender, RoutedEventArgs e) UpdateProfile(); } - private void FramerateToggle_Toggled(object sender, RoutedEventArgs e) - { - // UI thread (async) - Application.Current.Dispatcher.BeginInvoke(() => - { - if (FramerateToggle.IsOn) - { - FramerateSlider_ValueChanged(null, null); - } - else - { - foreach (Control control in FramerateModeGrid.Children) - { - if (control is not Label) - continue; - - control.SetResourceReference(Control.ForegroundProperty, "SystemControlForegroundBaseMediumBrush"); - } - } - }); - - // wait until lock is released - if (updateLock) - return; - - selectedProfile.FramerateEnabled = FramerateToggle.IsOn; - UpdateProfile(); - } - - private void FramerateSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) - { - // UI thread (async) - Application.Current.Dispatcher.BeginInvoke(() => - { - var value = (int)FramerateSlider.Value; - - foreach (Control control in FramerateModeGrid.Children) - { - if (control is not Label) - continue; - - control.SetResourceReference(Control.ForegroundProperty, "SystemControlForegroundBaseMediumBrush"); - } - - Label label = (Label)FramerateModeGrid.Children[value]; - label.SetResourceReference(Control.ForegroundProperty, "AccentButtonBackground"); - }); - - if (!FramerateSlider.IsInitialized) - return; - - // wait until lock is released - if (updateLock) - return; - - selectedProfile.FramerateValue = (int)FramerateSlider.Value; - UpdateProfile(); - } - private void ControllerSettingsButton_Click(object sender, RoutedEventArgs e) { // prepare layout editor @@ -715,28 +789,56 @@ private void ProfileApplied(Profile profile, UpdateSource source) public void ProfileUpdated(Profile profile, UpdateSource source, bool isCurrent) { + // self call - update ui and return + switch (source) + { + case UpdateSource.ProfilesPage: + case UpdateSource.ProfilesPageUpdateOnly: + return; + case UpdateSource.QuickProfilesPage: + { + isCurrent = selectedProfile.Path.Equals(profile.Path, StringComparison.InvariantCultureIgnoreCase); + if (!isCurrent) return; + } + break; + } + // UI thread (async) Application.Current.Dispatcher.BeginInvoke(() => { var idx = -1; - foreach (Profile pr in cB_Profiles.Items) + if (!profile.IsSubProfile && cb_SubProfilePicker.Items.IndexOf(profile) != 0) { - var isCurrent = pr.Path.Equals(profile.Path, StringComparison.InvariantCultureIgnoreCase); - if (isCurrent) + foreach (Profile pr in cB_Profiles.Items) { - idx = cB_Profiles.Items.IndexOf(pr); - break; + bool isCurrent = pr.Path.Equals(profile.Path, StringComparison.InvariantCultureIgnoreCase); + if (isCurrent) + { + idx = cB_Profiles.Items.IndexOf(pr); + break; + } } + + if (idx != -1) + cB_Profiles.Items[idx] = profile; + else + cB_Profiles.Items.Add(profile); + + cB_Profiles.Items.Refresh(); + + cB_Profiles.SelectedItem = profile; } - if (idx != -1) - cB_Profiles.Items[idx] = profile; - else - cB_Profiles.Items.Add(profile); + else if (!profile.IsFavoriteSubProfile) + cB_Profiles.SelectedItem = profile; - cB_Profiles.Items.Refresh(); + else // TODO updateUI to show main & sub profile selected + { + Profile mainProfile = ProfileManager.GetProfileForSubProfile(profile); + cB_Profiles.SelectedItem = mainProfile; + } - cB_Profiles.SelectedItem = profile; + UpdateSubProfiles(); // TODO check }); } @@ -745,18 +847,42 @@ public void ProfileDeleted(Profile profile) // UI thread (async) Application.Current.Dispatcher.BeginInvoke(() => { - var idx = -1; - foreach (Profile pr in cB_Profiles.Items) + if (!profile.IsSubProfile) { - var isCurrent = pr.Path.Equals(profile.Path, StringComparison.InvariantCultureIgnoreCase); - if (isCurrent) + // Profiles + var idx = -1; + foreach (Profile pr in cB_Profiles.Items) { - idx = cB_Profiles.Items.IndexOf(pr); - break; + var isCurrent = pr.Path.Equals(profile.Path, StringComparison.InvariantCultureIgnoreCase); + if (isCurrent) + { + idx = cB_Profiles.Items.IndexOf(pr); + break; + } } + + cB_Profiles.Items.RemoveAt(idx); } + else + { + var idx = -1; + foreach (Profile pr in cb_SubProfilePicker.Items) + { + // sub profiles + var isCurrent = profile.Guid == pr.Guid; + if (isCurrent) + { + idx = cb_SubProfilePicker.Items.IndexOf(pr); + break; + } + } - cB_Profiles.Items.RemoveAt(idx); + if (idx == -1) + return; + + cb_SubProfilePicker.Items.RemoveAt(idx); + cb_SubProfilePicker.SelectedIndex = 0; + } }); } @@ -768,16 +894,6 @@ private void ProfileManagerLoaded() #endregion - private void tB_ProfileName_TextChanged(object sender, TextChangedEventArgs e) - { - // wait until lock is released - if (updateLock) - return; - - selectedProfile.Name = tB_ProfileName.Text; - UpdateProfile(); - } - private void tb_ProfileGyroValue_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { if (!tb_ProfileGyroValue.IsInitialized) @@ -869,22 +985,38 @@ public void SubmitProfile(UpdateSource source = UpdateSource.ProfilesPage) { if (selectedProfile is null) return; + + LogManager.LogInformation($"Submitting profile in ProfilesPage: {selectedProfile} - is Sub Profile? {selectedProfile.IsSubProfile}"); - ProfileManager.UpdateOrCreateProfile(selectedProfile, source); + switch (source) + { + case UpdateSource.ProfilesPageUpdateOnly: // when renaming main profile, update main profile only but don't apply it + ProfileManager.UpdateOrCreateProfile(selectedMainProfile, source); + break; + default: + ProfileManager.UpdateOrCreateProfile(selectedProfile, source); + break; + } } private void RSRToggle_Toggled(object sender, RoutedEventArgs e) { + if (selectedProfile is null) + return; + // wait until lock is released if (updateLock) return; - selectedProfile.RSREnabled = RSRToggle.IsOn; + UpdateGraphicsSettings(UpdateGraphicsSettingsSource.RadeonSuperResolution, RSRToggle.IsOn); UpdateProfile(); } private void RSRSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { + if (selectedProfile is null) + return; + if (!RSRSlider.IsInitialized) return; @@ -896,6 +1028,104 @@ private void RSRSlider_ValueChanged(object sender, RoutedPropertyChangedEventArg UpdateProfile(); } + private void RISToggle_Toggled(object sender, RoutedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + UpdateGraphicsSettings(UpdateGraphicsSettingsSource.RadeonImageSharpening, RISToggle.IsOn); + UpdateProfile(); + } + + private void RISSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) + { + if (selectedProfile is null) + return; + + if (!RISSlider.IsInitialized) + return; + + // wait until lock is released + if (updateLock) + return; + + selectedProfile.RISSharpness = (int)RISSlider.Value; + UpdateProfile(); + } + + private void IntegerScalingToggle_Toggled(object sender, RoutedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + UpdateGraphicsSettings(UpdateGraphicsSettingsSource.IntegerScaling, IntegerScalingToggle.IsOn); + UpdateProfile(); + } + + private void IntegerScalingComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (IntegerScalingComboBox.SelectedIndex == -1 || selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + var divider = 1; + if (IntegerScalingComboBox.SelectedItem is ScreenDivider screenDivider) + { + divider = screenDivider.divider; + } + + selectedProfile.IntegerScalingDivider = divider; + UpdateProfile(); + } + + private void GPUScalingComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (GPUScalingComboBox.SelectedIndex == -1 || selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + int selectedIndex = GPUScalingComboBox.SelectedIndex; + // RSR does not work with ScalingMode.Center + if (selectedProfile.RSREnabled && selectedIndex == 2) + { + selectedProfile.ScalingMode = 1; + GPUScalingComboBox.SelectedIndex = 1; + } + else + { + selectedProfile.ScalingMode = GPUScalingComboBox.SelectedIndex; + } + + UpdateProfile(); + } + + private void GPUScaling_Toggled(object sender, RoutedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + UpdateGraphicsSettings(UpdateGraphicsSettingsSource.GPUScaling, GPUScalingToggle.IsOn); + UpdateProfile(); + } + private void cB_EmulatedController_Changed(object sender, SelectionChangedEventArgs e) { // wait until lock is released @@ -916,4 +1146,238 @@ private void cB_EmulatedController_Changed(object sender, SelectionChangedEventA UpdateProfile(); } + private void cb_SubProfilePicker_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + // wait until lock is released + if (updateLock) + return; + + if (cb_SubProfilePicker.SelectedIndex == -1) + return; + + LogManager.LogInformation($"Subprofile changed in ProfilesPage - ind: {cb_SubProfilePicker.SelectedIndex} - {cb_SubProfilePicker.SelectedItem}"); + + // selected sub profile + if (selectedProfile != cb_SubProfilePicker.SelectedItem) + { + selectedProfile = (Profile)cb_SubProfilePicker.SelectedItem; + UpdateProfile(); + } + + UpdateUI(); + } + + private void b_SubProfileCreate_Click(object sender, RoutedEventArgs e) + { + // create a new sub profile matching the original profile's settings + Profile newSubProfile = (Profile)selectedProfile.Clone(); + newSubProfile.Name = "(New Sub Profile)"; + newSubProfile.Guid = Guid.NewGuid(); // must be unique + newSubProfile.IsSubProfile = true; + newSubProfile.IsFavoriteSubProfile = true; + ProfileManager.UpdateOrCreateProfile(newSubProfile); + UpdateSubProfiles(); + } + + private async void b_SubProfileDelete_Click(object sender, RoutedEventArgs e) + { + // return if original profile or nothing is selected + if (cb_SubProfilePicker.SelectedIndex <= 0) + return; + + // get selected subprofile from dropdown + Profile subProfile = (Profile)cb_SubProfilePicker.SelectedItem; + + // user confirmation + var result = Dialog.ShowAsync( + $"{Properties.Resources.ProfilesPage_AreYouSureDelete1} \"{subProfile.Name}\"?", + $"{Properties.Resources.ProfilesPage_AreYouSureDelete2}", + ContentDialogButton.Primary, + $"{Properties.Resources.ProfilesPage_Cancel}", + $"{Properties.Resources.ProfilesPage_Delete}"); + await result; // sync call + + // delete sub profile if confirmed + switch (result.Result) + { + case ContentDialogResult.Primary: + ProfileManager.DeleteSubProfile(subProfile); + break; + } + } + + private void b_SubProfileRename_Click(object sender, RoutedEventArgs e) + { + tb_SubProfileName.Text = selectedProfile.Name; + SubProfileRenameDialog.ShowAsync(); + } + + private void SubProfileRenameDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + if (selectedProfile is null) + return; + + // update subprofile name + selectedProfile.Name = tb_SubProfileName.Text; + + // serialize subprofile + SubmitProfile(); + + UpdateSubProfiles(); + } + + private void SubProfileRenameDialog_CloseButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + // restore subprofile rename dialog + tb_SubProfileName.Text = selectedProfile.Name; + } + + private void ProfileRenameDialog_CloseButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + // restore profile name textbox + tB_ProfileName.Text = selectedMainProfile.Name; + } + + private void ProfileRenameDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + // change main profile name + selectedMainProfile.Name = tB_ProfileName.Text; + + // change it in + int ind = cB_Profiles.Items.IndexOf(selectedMainProfile); + cB_Profiles.Items[ind] = selectedMainProfile; + cB_Profiles.Items.Refresh(); + cB_Profiles.SelectedIndex = ind; + + SubmitProfile(UpdateSource.ProfilesPageUpdateOnly); + } + + private void b_ProfileRename_Click(object sender, RoutedEventArgs e) + { + tB_ProfileName.Text = selectedMainProfile.Name; + ProfileRenameDialog.ShowAsync(); + } + + private void cB_Framerate_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + // return if combobox selected item is null + if (cB_Framerate.SelectedIndex == -1) + return; + + if (cB_Framerate.SelectedItem is ScreenFramelimit screenFramelimit) + { + selectedProfile.FramerateValue = screenFramelimit.limit; + UpdateProfile(); + } + } + + private enum UpdateGraphicsSettingsSource + { + GPUScaling, + RadeonSuperResolution, + RadeonImageSharpening, + IntegerScaling + } + + private void UpdateGraphicsSettings(UpdateGraphicsSettingsSource source, bool isEnabled) + { + using (new ScopedLock(updateLock)) + { + switch (source) + { + case UpdateGraphicsSettingsSource.GPUScaling: + { + selectedProfile.GPUScaling = isEnabled; + if (!isEnabled) + { + selectedProfile.RSREnabled = false; + selectedProfile.IntegerScalingEnabled = false; + + RSRToggle.IsOn = false; + IntegerScalingToggle.IsOn = false; + } + } + break; + // RSR is incompatible with RIS and IS + case UpdateGraphicsSettingsSource.RadeonSuperResolution: + { + selectedProfile.RSREnabled = isEnabled; + if (isEnabled) + { + selectedProfile.RISEnabled = false; + selectedProfile.IntegerScalingEnabled = false; + + RISToggle.IsOn = false; + IntegerScalingToggle.IsOn = false; + + // RSR does not support ScalingMode.Center + if (selectedProfile.ScalingMode == 2) + { + selectedProfile.ScalingMode = 1; + GPUScalingComboBox.SelectedIndex = 1; + } + } + } + break; + // Image Sharpening is incompatible with RSR + case UpdateGraphicsSettingsSource.RadeonImageSharpening: + { + selectedProfile.RISEnabled = isEnabled; + if (isEnabled) + { + selectedProfile.RSREnabled = false; + + RSRToggle.IsOn = false; + } + } + break; + + // Integer Scaling is incompatible with RSR + case UpdateGraphicsSettingsSource.IntegerScaling: + { + selectedProfile.IntegerScalingEnabled = isEnabled; + if (isEnabled) + { + selectedProfile.RSREnabled = false; + + RSRToggle.IsOn = false; + } + } + break; + } + } + } + + private void UseFullscreenOptimizations_Toggled(object sender, RoutedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + selectedProfile.FullScreenOptimization = UseFullscreenOptimizations.IsOn; + UpdateProfile(); + } + + private void UseHighDPIAwareness_Toggled(object sender, RoutedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + selectedProfile.HighDPIAware = UseHighDPIAwareness.IsOn; + UpdateProfile(); + } } \ No newline at end of file diff --git a/HandheldCompanion/Views/Pages/SettingsPage.xaml b/HandheldCompanion/Views/Pages/SettingsPage.xaml index b89085817..fe2a35f9f 100644 --- a/HandheldCompanion/Views/Pages/SettingsPage.xaml +++ b/HandheldCompanion/Views/Pages/SettingsPage.xaml @@ -463,10 +463,8 @@ Margin="12,0,0,0" HorizontalAlignment="Stretch" SelectionChanged="cB_QuicktoolsPosition_SelectionChanged"> - - - - + + @@ -833,44 +831,6 @@ Toggled="Toggle_RTSS_Toggled" /> - - - - - - - - - - - - - - - - - - - - - - diff --git a/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs b/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs index 435b84cca..8ec67e7dd 100644 --- a/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs +++ b/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs @@ -4,9 +4,10 @@ using HandheldCompanion.Managers.Desktop; using HandheldCompanion.Misc; using HandheldCompanion.Platforms; -using Inkore.UI.WPF.Modern; -using Inkore.UI.WPF.Modern.Controls; -using Inkore.UI.WPF.Modern.Controls.Primitives; +using iNKORE.UI.WPF.Modern; +using iNKORE.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls.Helpers; +using iNKORE.UI.WPF.Modern.Helpers.Styles; using Nefarius.Utilities.DeviceManagement.PnP; using System; using System.Collections.Generic; @@ -46,17 +47,15 @@ public SettingsPage() UpdateDevice(); // initialize manager(s) - MainWindow.updateManager.Updated += UpdateManager_Updated; + UpdateManager.Updated += UpdateManager_Updated; SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; ControllerManager.ControllerSelected += ControllerManager_ControllerSelected; PlatformManager.RTSS.Updated += RTSS_Updated; - PlatformManager.HWiNFO.Updated += HWiNFO_Updated; // force call // todo: make PlatformManager static RTSS_Updated(PlatformManager.RTSS.Status); - HWiNFO_Updated(PlatformManager.HWiNFO.Status); } public SettingsPage(string? Tag) : this() @@ -73,23 +72,6 @@ private void ControllerManager_ControllerSelected(IController Controller) }); } - private void HWiNFO_Updated(PlatformStatus status) - { - // UI thread (async) - Application.Current.Dispatcher.BeginInvoke(() => - { - switch (status) - { - case PlatformStatus.Ready: - Toggle_HWiNFO.IsEnabled = true; - break; - case PlatformStatus.Stalled: - Toggle_HWiNFO.IsOn = false; - break; - } - }); - } - private void RTSS_Updated(PlatformStatus status) { // UI thread (async) @@ -226,10 +208,6 @@ private void SettingsManager_SettingValueChanged(string? name, object value) case "PlatformRTSSEnabled": Toggle_RTSS.IsOn = Convert.ToBoolean(value); break; - case "PlatformHWiNFOEnabled": - Toggle_HWiNFO.IsOn = Convert.ToBoolean(value); - break; - case "QuickToolsLocation": cB_QuicktoolsPosition.SelectedIndex = Convert.ToInt32(value); break; @@ -252,7 +230,7 @@ public void UpdateDevice(PnPDevice device = null) private void Page_Loaded(object? sender, RoutedEventArgs? e) { - MainWindow.updateManager.Start(); + UpdateManager.Start(); } public void Page_Closed() @@ -323,7 +301,7 @@ private void UpdateManager_Updated(UpdateStatus status, UpdateFile updateFile, o { LabelUpdate.Text = Properties.Resources.SettingsPage_UpToDate; LabelUpdateDate.Text = Properties.Resources.SettingsPage_LastChecked + - MainWindow.updateManager.GetTime(); + UpdateManager.GetTime(); LabelUpdateDate.Visibility = Visibility.Visible; GridUpdateSymbol.Visibility = Visibility.Visible; @@ -358,13 +336,13 @@ private void UpdateManager_Updated(UpdateStatus status, UpdateFile updateFile, o // Set download button action update.updateDownload.Click += (sender, e) => { - MainWindow.updateManager.DownloadUpdateFile(update); + UpdateManager.DownloadUpdateFile(update); }; // Set button action update.updateInstall.Click += (sender, e) => { - MainWindow.updateManager.InstallUpdate(update); + UpdateManager.InstallUpdate(update); }; CurrentUpdates.Children.Add(border); @@ -408,7 +386,7 @@ private void UpdateManager_Updated(UpdateStatus status, UpdateFile updateFile, o private void B_CheckUpdate_Click(object? sender, RoutedEventArgs? e) { - new Thread(() => { MainWindow.updateManager.StartProcess(); }).Start(); + new Thread(() => { UpdateManager.StartProcess(); }).Start(); } private void cB_Language_SelectionChanged(object? sender, SelectionChangedEventArgs? e) @@ -577,14 +555,6 @@ private void Toggle_RTSS_Toggled(object sender, RoutedEventArgs e) SettingsManager.SetProperty("PlatformRTSSEnabled", Toggle_RTSS.IsOn); } - private void Toggle_HWiNFO_Toggled(object sender, RoutedEventArgs e) - { - if (!IsLoaded) - return; - - SettingsManager.SetProperty("PlatformHWiNFOEnabled", Toggle_HWiNFO.IsOn); - } - private void cB_QuicktoolsPosition_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (!IsLoaded) diff --git a/HandheldCompanion/Views/QuickPages/QuickDevicePage.xaml b/HandheldCompanion/Views/QuickPages/QuickDevicePage.xaml index b12e6427f..8c4d2a828 100644 --- a/HandheldCompanion/Views/QuickPages/QuickDevicePage.xaml +++ b/HandheldCompanion/Views/QuickPages/QuickDevicePage.xaml @@ -15,65 +15,285 @@ KeepAlive="True" mc:Ignorable="d"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + Glyph="" /> - + VerticalAlignment="Center" + Style="{StaticResource BodyTextBlockStyle}" + Text="Wifi" /> + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/HandheldCompanion/Views/QuickPages/QuickDevicePage.xaml.cs b/HandheldCompanion/Views/QuickPages/QuickDevicePage.xaml.cs index 81167047d..f08808f74 100644 --- a/HandheldCompanion/Views/QuickPages/QuickDevicePage.xaml.cs +++ b/HandheldCompanion/Views/QuickPages/QuickDevicePage.xaml.cs @@ -1,10 +1,17 @@ using HandheldCompanion.Devices; using HandheldCompanion.Managers; -using HandheldCompanion.Platforms; -using Inkore.UI.WPF.Modern.Controls; +using HandheldCompanion.Managers.Desktop; +using HandheldCompanion.Misc; +using iNKORE.UI.WPF.Modern.Controls; using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Timers; using System.Windows; using System.Windows.Controls; +using Windows.Devices.Bluetooth; +using Windows.Devices.Radios; using Page = System.Windows.Controls.Page; namespace HandheldCompanion.Views.QuickPages; @@ -14,83 +21,240 @@ namespace HandheldCompanion.Views.QuickPages; /// public partial class QuickDevicePage : Page { - public QuickDevicePage(string Tag) : this() - { - this.Tag = Tag; - } + private IReadOnlyList radios; + private Timer radioTimer; public QuickDevicePage() { InitializeComponent(); - FullFanSpeedToggler.Visibility = MainWindow.CurrentDevice is LegionGo ? Visibility.Visible : Visibility.Collapsed; + SystemManager.PrimaryScreenChanged += DesktopManager_PrimaryScreenChanged; + SystemManager.DisplaySettingsChanged += DesktopManager_DisplaySettingsChanged; SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; + ProfileManager.Applied += ProfileManager_Applied; + ProfileManager.Discarded += ProfileManager_Discarded; + + LegionGoPanel.Visibility = MainWindow.CurrentDevice is LegionGo ? Visibility.Visible : Visibility.Collapsed; + DynamicLightingPanel.IsEnabled = MainWindow.CurrentDevice.Capabilities.HasFlag(DeviceCapabilities.DynamicLighting); + + NightLightToggle.IsEnabled = NightLight.Supported; + NightLightToggle.IsOn = NightLight.Enabled; - PlatformManager.RTSS.Updated += RTSS_Updated; - PlatformManager.HWiNFO.Updated += HWiNFO_Updated; + // manage events + NightLight.Toggled += NightLight_Toggled; - // force call - // todo: make PlatformManager static - RTSS_Updated(PlatformManager.RTSS.Status); - HWiNFO_Updated(PlatformManager.HWiNFO.Status); + radioTimer = new(1000); + radioTimer.Elapsed += RadioTimer_Elapsed; + radioTimer.Start(); } - private void HWiNFO_Updated(PlatformStatus status) + public QuickDevicePage(string Tag) : this() { - // UI thread (async) - Application.Current.Dispatcher.BeginInvoke(() => + this.Tag = Tag; + } + + private void ProfileManager_Applied(Profile profile, UpdateSource source) + { + // Go to profile integer scaling resolution + if (profile.IntegerScalingEnabled) { - switch (status) + DesktopScreen desktopScreen = SystemManager.GetDesktopScreen(); + var profileResolution = desktopScreen?.screenDividers.FirstOrDefault(d => d.divider == profile.IntegerScalingDivider); + if (profileResolution is not null) { - case PlatformStatus.Ready: - OverlayDisplayLevelExtended.IsEnabled = true; - OverlayDisplayLevelFull.IsEnabled = true; - break; - case PlatformStatus.Stalled: - // OverlayDisplayLevelExtended.IsEnabled = false; - // OverlayDisplayLevelFull.IsEnabled = false; - break; + SetResolution(profileResolution.resolution); } + } + else + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + // Revert back to resolution in device settings + SetResolution(); + }); + } + + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + var canChangeDisplay = !profile.IntegerScalingEnabled; + DisplayStack.IsEnabled = canChangeDisplay; + ResolutionOverrideStack.Visibility = canChangeDisplay ? Visibility.Collapsed : Visibility.Visible; + }); } - private void RTSS_Updated(PlatformStatus status) + private void ProfileManager_Discarded(Profile profile) { // UI thread (async) Application.Current.Dispatcher.BeginInvoke(() => { - switch (status) + SetResolution(); + + if (profile.IntegerScalingEnabled) { - case PlatformStatus.Ready: - ComboBoxOverlayDisplayLevel.IsEnabled = true; - break; - case PlatformStatus.Stalled: - ComboBoxOverlayDisplayLevel.SelectedIndex = 0; - break; + DisplayStack.IsEnabled = true; + ResolutionOverrideStack.Visibility = Visibility.Collapsed; } }); } - private void SettingsManager_SettingValueChanged(string name, object value) + private void NightLight_Toggled(bool enabled) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + NightLightToggle.IsOn = enabled; + }); + } + + private void SettingsManager_SettingValueChanged(string? name, object value) { // UI thread (async) Application.Current.Dispatcher.BeginInvoke(() => { switch (name) { - case "OnScreenDisplayLevel": - ComboBoxOverlayDisplayLevel.SelectedIndex = Convert.ToInt32(value); + case "LEDSettingsEnabled": + UseDynamicLightingToggle.IsOn = Convert.ToBoolean(value); break; } }); } - private void ComboBoxOverlayDisplayLevel_SelectionChanged(object sender, SelectionChangedEventArgs e) + private void RadioTimer_Elapsed(object? sender, ElapsedEventArgs e) + { + new Task(async () => + { + // Get the Bluetooth adapter + BluetoothAdapter adapter = await BluetoothAdapter.GetDefaultAsync(); + + // Get the Bluetooth radio + radios = await Radio.GetRadiosAsync(); + + // UI thread (async) + _ = Application.Current.Dispatcher.BeginInvoke(() => + { + // WIFI + WifiToggle.IsEnabled = radios.Where(radio => radio.Kind == RadioKind.WiFi).Any(); + WifiToggle.IsOn = radios.Where(radio => radio.Kind == RadioKind.WiFi && radio.State == RadioState.On).Any(); + + // Bluetooth + BluetoothToggle.IsEnabled = radios.Where(radio => radio.Kind == RadioKind.Bluetooth).Any(); + BluetoothToggle.IsOn = radios.Where(radio => radio.Kind == RadioKind.Bluetooth && radio.State == RadioState.On).Any(); + }); + }).Start(); + } + + private void DesktopManager_PrimaryScreenChanged(DesktopScreen screen) + { + ComboBoxResolution.Items.Clear(); + foreach (ScreenResolution resolution in screen.screenResolutions) + ComboBoxResolution.Items.Add(resolution); + } + + private void DesktopManager_DisplaySettingsChanged(ScreenResolution resolution) + { + // We don't want to change the combobox when it's changed from profile integer scaling + var currentProfile = ProfileManager.GetCurrent(); + if (ComboBoxResolution.SelectedItem is not null && currentProfile is not null && currentProfile.IntegerScalingEnabled) + return; + + ComboBoxResolution.SelectedItem = resolution; + + int screenFrequency = SystemManager.GetDesktopScreen().GetCurrentFrequency(); + foreach (ComboBoxItem comboBoxItem in ComboBoxFrequency.Items) + { + if (comboBoxItem.Tag is int frequency) + { + if (frequency == screenFrequency) + { + ComboBoxFrequency.SelectedItem = comboBoxItem; + break; + } + } + } + } + + private void ComboBoxResolution_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (ComboBoxResolution.SelectedItem is null) + return; + + ScreenResolution resolution = (ScreenResolution)ComboBoxResolution.SelectedItem; + int screenFrequency = SystemManager.GetDesktopScreen().GetCurrentFrequency(); + + ComboBoxFrequency.Items.Clear(); + foreach (int frequency in resolution.Frequencies.Keys) + { + ComboBoxItem comboBoxItem = new() + { + Content = $"{frequency} Hz", + Tag = frequency, + }; + + ComboBoxFrequency.Items.Add(comboBoxItem); + + if (frequency == screenFrequency) + ComboBoxFrequency.SelectedItem = comboBoxItem; + } + + SetResolution(); + } + + private void ComboBoxFrequency_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (ComboBoxFrequency.SelectedItem is null) + return; + + SetResolution(); + } + + private void SetResolution() + { + if (ComboBoxResolution.SelectedItem is null) + return; + + if (ComboBoxFrequency.SelectedItem is null) + return; + + ScreenResolution resolution = (ScreenResolution)ComboBoxResolution.SelectedItem; + int frequency = (int)((ComboBoxItem)ComboBoxFrequency.SelectedItem).Tag; + + // update current screen resolution + SystemManager.SetResolution(resolution.Width, resolution.Height, frequency, resolution.BitsPerPel); + } + + public void SetResolution(ScreenResolution resolution) + { + // update current screen resolution + SystemManager.SetResolution(resolution.Width, resolution.Height, SystemManager.GetDesktopScreen().GetCurrentFrequency(), resolution.BitsPerPel); + } + + private void WIFIToggle_Toggled(object sender, RoutedEventArgs e) + { + foreach (Radio radio in radios.Where(r => r.Kind == RadioKind.WiFi)) + _ = radio.SetStateAsync(WifiToggle.IsOn ? RadioState.On : RadioState.Off); + } + + private void BluetoothToggle_Toggled(object sender, RoutedEventArgs e) + { + foreach (Radio radio in radios.Where(r => r.Kind == RadioKind.Bluetooth)) + _ = radio.SetStateAsync(BluetoothToggle.IsOn ? RadioState.On : RadioState.Off); + } + + private void UseDynamicLightingToggle_Toggled(object sender, RoutedEventArgs e) { if (!IsLoaded) return; - SettingsManager.SetProperty("OnScreenDisplayLevel", ComboBoxOverlayDisplayLevel.SelectedIndex); + SettingsManager.SetProperty("LEDSettingsEnabled", UseDynamicLightingToggle.IsOn); + } + + internal void Close() + { + radioTimer.Stop(); } private void Toggle_cFFanSpeed_Toggled(object sender, RoutedEventArgs e) @@ -101,4 +265,9 @@ private void Toggle_cFFanSpeed_Toggled(object sender, RoutedEventArgs e) device.SetFanFullSpeed(toggleSwitch.IsOn); } } + + private void NightLightToggle_Toggled(object sender, RoutedEventArgs e) + { + NightLight.Enabled = NightLightToggle.IsOn; + } } \ No newline at end of file diff --git a/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml b/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml index ed654d326..dfdbb25c8 100644 --- a/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml +++ b/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml @@ -1,268 +1,301 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml.cs b/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml.cs index 49645cd5d..a3d1e5eb2 100644 --- a/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml.cs +++ b/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml.cs @@ -1,98 +1,188 @@ -using HandheldCompanion.Managers; -using HandheldCompanion.Utils; -using System; -using System.Windows; -using System.Windows.Controls; -using Page = System.Windows.Controls.Page; - -namespace HandheldCompanion.Views.QuickPages; - -/// -/// Interaction logic for QuickHomePage.xaml -/// -public partial class QuickHomePage : Page -{ - private LockObject brightnessLock = new(); - private LockObject volumeLock = new(); - - public QuickHomePage(string Tag) : this() - { - this.Tag = Tag; - - SystemManager.VolumeNotification += SystemManager_VolumeNotification; - SystemManager.BrightnessNotification += SystemManager_BrightnessNotification; - SystemManager.Initialized += SystemManager_Initialized; - } - - public QuickHomePage() - { - InitializeComponent(); - } - - private void QuickButton_Click(object sender, RoutedEventArgs e) - { - Button button = (Button)sender; - MainWindow.overlayquickTools.NavView_Navigate(button.Name); - } - - private void SystemManager_Initialized() - { - // UI thread (async) - Application.Current.Dispatcher.BeginInvoke(() => - { - if (SystemManager.HasBrightnessSupport()) - { - SliderBrightness.IsEnabled = true; - SliderBrightness.Value = SystemManager.GetBrightness(); - } - - if (SystemManager.HasVolumeSupport()) - { - SliderVolume.IsEnabled = true; - SliderVolume.Value = SystemManager.GetVolume(); - } - }); - } - - private void SystemManager_BrightnessNotification(int brightness) - { - // UI thread - Application.Current.Dispatcher.Invoke(() => - { - // wait until lock is released - if (brightnessLock) - SliderBrightness.Value = brightness; - }); - } - - private void SystemManager_VolumeNotification(float volume) - { - // UI thread - Application.Current.Dispatcher.Invoke(() => - { - // todo: update volume icon on update - - // wait until lock is released - if (volumeLock) - SliderVolume.Value = Math.Round(volume); - }); - } - - private void SliderBrightness_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) - { - if (!IsLoaded) - return; - - using (new ScopedLock(brightnessLock)) - SystemManager.SetBrightness(SliderBrightness.Value); - } - - private void SliderVolume_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) - { - if (!IsLoaded) - return; - - using (new ScopedLock(volumeLock)) - SystemManager.SetVolume(SliderVolume.Value); - } -} \ No newline at end of file +using HandheldCompanion.Managers; +using HandheldCompanion.Properties; +using HandheldCompanion.Utils; +using System; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using Page = System.Windows.Controls.Page; + +namespace HandheldCompanion.Views.QuickPages; + +/// +/// Interaction logic for QuickHomePage.xaml +/// +public partial class QuickHomePage : Page +{ + private LockObject brightnessLock = new(); + private LockObject volumeLock = new(); + + public QuickHomePage(string Tag) : this() + { + this.Tag = Tag; + + HotkeysManager.HotkeyCreated += HotkeysManager_HotkeyCreated; + HotkeysManager.HotkeyUpdated += HotkeysManager_HotkeyUpdated; + + SystemManager.VolumeNotification += SystemManager_VolumeNotification; + SystemManager.BrightnessNotification += SystemManager_BrightnessNotification; + SystemManager.Initialized += SystemManager_Initialized; + + ProfileManager.Applied += ProfileManager_Applied; + SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; + } + + public QuickHomePage() + { + InitializeComponent(); + } + + private void HotkeysManager_HotkeyUpdated(Hotkey hotkey) + { + UpdatePins(); + } + + private void HotkeysManager_HotkeyCreated(Hotkey hotkey) + { + UpdatePins(); + } + + private void UpdatePins() + { + // todo, implement quick hotkey order + QuickHotkeys.Children.Clear(); + + foreach (var hotkey in HotkeysManager.Hotkeys.Values.Where(item => item.IsPinned)) + QuickHotkeys.Children.Add(hotkey.GetPin()); + } + + private void QuickButton_Click(object sender, RoutedEventArgs e) + { + Button button = (Button)sender; + MainWindow.overlayquickTools.NavView_Navigate(button.Name); + } + + private void SystemManager_Initialized() + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + if (SystemManager.HasBrightnessSupport()) + { + SliderBrightness.IsEnabled = true; + SliderBrightness.Value = SystemManager.GetBrightness(); + } + + if (SystemManager.HasVolumeSupport()) + { + SliderVolume.IsEnabled = true; + SliderVolume.Value = SystemManager.GetVolume(); + UpdateVolumeIcon((float)SliderVolume.Value); + } + }); + } + + private void SystemManager_BrightnessNotification(int brightness) + { + // UI thread + Application.Current.Dispatcher.Invoke(() => + { + // wait until lock is released + if (brightnessLock) + return; + + SliderBrightness.Value = brightness; + }); + } + + private void SystemManager_VolumeNotification(float volume) + { + // UI thread + Application.Current.Dispatcher.Invoke(() => + { + // wait until lock is released + if (volumeLock) + return; + + UpdateVolumeIcon(volume); + SliderVolume.Value = Math.Round(volume); + }); + } + + private void SliderBrightness_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) + { + if (!IsLoaded) + return; + + using (new ScopedLock(brightnessLock)) + SystemManager.SetBrightness(SliderBrightness.Value); + } + + private void SliderVolume_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) + { + if (!IsLoaded) + return; + + using (new ScopedLock(volumeLock)) + SystemManager.SetVolume(SliderVolume.Value); + } + + private void ProfileManager_Applied(Profile profile, UpdateSource source) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + t_CurrentProfile.Text = profile.ToString(); + }); + } + + private void SettingsManager_SettingValueChanged(string name, object value) + { + string[] onScreenDisplayLevels = { + Properties.Resources.OverlayPage_OverlayDisplayLevel_Disabled, + Properties.Resources.OverlayPage_OverlayDisplayLevel_Minimal, + Properties.Resources.OverlayPage_OverlayDisplayLevel_Extended, + Properties.Resources.OverlayPage_OverlayDisplayLevel_Full, + Properties.Resources.OverlayPage_OverlayDisplayLevel_External, + }; + + switch (name) + { + case "OnScreenDisplayLevel": + { + var overlayLevel = Convert.ToInt16(value); + + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + t_CurrentOverlayLevel.Text = onScreenDisplayLevels[overlayLevel]; + }); + } + break; + } + } + + private void UpdateVolumeIcon(float volume) + { + string glyph; + + if (volume == 0) + { + glyph = "\uE992"; // Mute icon + } + else if (volume <= 33) + { + glyph = "\uE993"; // Low volume icon + } + else if (volume <= 65) + { + glyph = "\uE994"; // Medium volume icon + } + else + { + glyph = "\uE995"; // High volume icon (default) + } + + VolumeIcon.Glyph = glyph; + } +} diff --git a/HandheldCompanion/Views/QuickPages/QuickOverlayPage.xaml b/HandheldCompanion/Views/QuickPages/QuickOverlayPage.xaml new file mode 100644 index 000000000..3b4499326 --- /dev/null +++ b/HandheldCompanion/Views/QuickPages/QuickOverlayPage.xaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HandheldCompanion/Views/QuickPages/QuickOverlayPage.xaml.cs b/HandheldCompanion/Views/QuickPages/QuickOverlayPage.xaml.cs new file mode 100644 index 000000000..85eca2e48 --- /dev/null +++ b/HandheldCompanion/Views/QuickPages/QuickOverlayPage.xaml.cs @@ -0,0 +1,94 @@ +using HandheldCompanion.Devices; +using HandheldCompanion.Managers; +using HandheldCompanion.Platforms; +using iNKORE.UI.WPF.Modern.Controls; +using System; +using System.Windows; +using System.Windows.Controls; +using Page = System.Windows.Controls.Page; + +namespace HandheldCompanion.Views.QuickPages; + +/// +/// Interaction logic for QuickOverlayPage.xaml +/// +public partial class QuickOverlayPage : Page +{ + public QuickOverlayPage(string Tag) : this() + { + this.Tag = Tag; + } + + public QuickOverlayPage() + { + InitializeComponent(); + + SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; + + PlatformManager.RTSS.Updated += RTSS_Updated; + PlatformManager.LibreHardwareMonitor.Updated += LibreHardwareMonitor_Updated; + + // force call + // todo: make PlatformManager static + RTSS_Updated(PlatformManager.RTSS.Status); + LibreHardwareMonitor_Updated(PlatformManager.LibreHardwareMonitor.Status); + } + + private void LibreHardwareMonitor_Updated(PlatformStatus status) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + switch (status) + { + case PlatformStatus.Ready: + OverlayDisplayLevelExtended.IsEnabled = true; + OverlayDisplayLevelFull.IsEnabled = true; + break; + case PlatformStatus.Stalled: + // OverlayDisplayLevelExtended.IsEnabled = false; + // OverlayDisplayLevelFull.IsEnabled = false; + break; + } + }); + } + + private void RTSS_Updated(PlatformStatus status) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + switch (status) + { + case PlatformStatus.Ready: + ComboBoxOverlayDisplayLevel.IsEnabled = true; + break; + case PlatformStatus.Stalled: + ComboBoxOverlayDisplayLevel.SelectedIndex = 0; + break; + } + }); + } + + private void SettingsManager_SettingValueChanged(string name, object value) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + switch (name) + { + case "OnScreenDisplayLevel": + ComboBoxOverlayDisplayLevel.SelectedIndex = Convert.ToInt32(value); + break; + } + }); + } + + private void ComboBoxOverlayDisplayLevel_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (!IsLoaded) + return; + + SettingsManager.SetProperty("OnScreenDisplayLevel", ComboBoxOverlayDisplayLevel.SelectedIndex); + } +} \ No newline at end of file diff --git a/HandheldCompanion/Views/QuickPages/QuickPerformancePage.xaml b/HandheldCompanion/Views/QuickPages/QuickPerformancePage.xaml index c71cc5762..eeb1cb290 100644 --- a/HandheldCompanion/Views/QuickPages/QuickPerformancePage.xaml +++ b/HandheldCompanion/Views/QuickPages/QuickPerformancePage.xaml @@ -17,7 +17,7 @@ - + @@ -28,14 +28,30 @@ - - - - + + + + + + + + + + + + + - - + - - - - - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0} Cores, ElementName=CPUCoreSlider, Mode=OneWay}" /> + + @@ -93,14 +103,30 @@ Spacing="6"> - - - - + + + + + + + + + + + + + - - + - - - - - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0} W, ElementName=TDPSlider, Mode=OneWay}" /> + + @@ -160,14 +180,29 @@ Spacing="6"> - - - - + + + + + + + + + + + + - - - + - - - - - - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0} FPS, ElementName=AutoTDPSlider, Mode=OneWay}" /> + + @@ -227,16 +251,30 @@ CornerRadius="{DynamicResource ControlCornerRadius}"> - - - - - + + + + + + + + + + + + - - + - - - + - - - - - - - - - - - - - - - - + AutoToolTipPrecision="0" + IsMoveToPointEnabled="True" + IsSnapToTickEnabled="True" + LargeChange="10" + Maximum="100" + Minimum="0" + SmallChange="1" + Style="{DynamicResource SliderStyle1}" + TickFrequency="10" + TickPlacement="BottomRight" + ToolTip="{Binding Value, StringFormat=N0, RelativeSource={RelativeSource Self}, Mode=OneWay}" + ValueChanged="EPPSlider_ValueChanged" /> + + + + + + + @@ -306,16 +332,31 @@ CornerRadius="{DynamicResource ControlCornerRadius}"> - - - - - + + + + + + + + + + + + + - - + - - - - - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0} Mhz, ElementName=CPUSlider, Mode=OneWay}" /> + + @@ -373,16 +405,31 @@ Name="StackProfileGPUClock" IsEnabled="False" Spacing="6"> - - - - - + + + + + + + + + + + + + - - + - - - - - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0} Mhz, ElementName=GPUSlider, Mode=OneWay}" /> + + @@ -437,14 +475,30 @@ Background="{DynamicResource ExpanderHeaderBackground}" CornerRadius="{DynamicResource ControlCornerRadius}"> - - - - + + + + + + + + + + + + + - - + + - - - - + + + + + + + + - - + + - - - - + + + + + + + + { - switch (listener) - { - case "increaseTDP": - { - if (selectedProfile is null || !selectedProfile.TDPOverrideEnabled) - return; - - TDPSlider.Value++; - } - break; - case "decreaseTDP": - { - if (selectedProfile is null || !selectedProfile.TDPOverrideEnabled) - return; - - TDPSlider.Value--; - } - break; - } + AutoTDPSlider.Maximum = desktopScreen.devMode.dmDisplayFrequency; }); } @@ -130,7 +110,7 @@ private void RTSS_Updated(PlatformStatus status) switch (status) { case PlatformStatus.Ready: - var Processor = MainWindow.performanceManager.GetProcessor(); + var Processor = PerformanceManager.GetProcessor(); StackProfileAutoTDP.IsEnabled = true && Processor is not null ? Processor.CanChangeTDP : false; break; case PlatformStatus.Stalled: @@ -181,7 +161,7 @@ private void PerformanceManager_EPPChanged(uint EPP) private void PerformanceManager_Initialized() { - Processor processor = MainWindow.performanceManager.GetProcessor(); + Processor processor = PerformanceManager.GetProcessor(); if (processor is null) return; @@ -281,18 +261,8 @@ private void UpdateUI() { using (new ScopedLock(updateLock)) { - switch (selectedProfile.Default) - { - case true: - // we shouldn't allow users to mess with default profile fan mode - FanMode.IsEnabled = false; - break; - case false: - FanMode.IsEnabled = true; - break; - } - // we shouldn't allow users to modify some of default profile settings + PowerSettingsPanel.IsEnabled = !selectedProfile.DeviceDefault; Button_PowerSettings_Delete.IsEnabled = !selectedProfile.Default; // page name @@ -315,7 +285,7 @@ private void UpdateUI() // AutoTDP AutoTDPToggle.IsOn = selectedProfile.AutoTDPEnabled; - AutoTDPRequestedFPSSlider.Value = selectedProfile.AutoTDPRequestedFPS; + AutoTDPSlider.Value = selectedProfile.AutoTDPRequestedFPS; // EPP EPPToggle.IsOn = selectedProfile.EPPOverrideEnabled; @@ -383,7 +353,7 @@ private void AutoTDPToggle_Toggled(object sender, RoutedEventArgs e) return; selectedProfile.AutoTDPEnabled = AutoTDPToggle.IsOn; - AutoTDPRequestedFPSSlider.Value = selectedProfile.AutoTDPRequestedFPS; + AutoTDPSlider.Value = selectedProfile.AutoTDPRequestedFPS; UpdateProfile(); } @@ -396,7 +366,7 @@ private void AutoTDPRequestedFPSSlider_ValueChanged(object sender, RoutedPropert if (updateLock) return; - selectedProfile.AutoTDPRequestedFPS = (int)AutoTDPRequestedFPSSlider.Value; + selectedProfile.AutoTDPRequestedFPS = (int)AutoTDPSlider.Value; UpdateProfile(); } diff --git a/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml b/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml index 96e380cd8..abbbedea3 100644 --- a/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml +++ b/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml @@ -9,7 +9,7 @@ Name="QuickProfiles" Title="{x:Static resx:Resources.QuickProfilesPage_Title}" Margin="15,0,0,0" - d:Background="White" + d:Background="Black" d:DesignHeight="1500" d:DesignWidth="640" KeepAlive="True" @@ -99,10 +99,45 @@ - + + + + + + + + + + + + + + + + + + + - + @@ -120,11 +155,11 @@ Glyph="" /> - + @@ -143,6 +178,7 @@ + @@ -168,6 +204,7 @@ + @@ -188,68 +225,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + @@ -257,247 +236,315 @@ + - - + Style="{DynamicResource InvertedToggleSwitchStyle}" + Toggled="Toggle_ControllerLayout_Toggled" /> - + + - + - - + + - + - - - - + SelectionChanged="cB_Output_SelectionChanged" /> - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + SelectionChanged="cB_Input_SelectionChanged" /> + + + + + + + + + + + + + + + + - - - - - + SelectionChanged="cB_UMC_MotionDefaultOffOn_SelectionChanged"> + + + + + + + + + + - + + - - - - - - - - - - - + + + + + + + - - - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0}, ElementName=SliderUMCAntiDeadzone, Mode=OneWay}" /> + ToolTip="{Binding Value, StringFormat=N0, RelativeSource={RelativeSource Self}, Mode=OneWay}" + ValueChanged="SliderUMCAntiDeadzone_ValueChanged" /> - + + - - - + + + + + + + + + + + + + + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N1}, ElementName=Slider_GyroWeight, Mode=OneWay}" /> + ValueChanged="Slider_GyroWeight_ValueChanged" /> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + @@ -508,36 +555,94 @@ Glyph="" /> - + - + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + @@ -547,136 +652,228 @@ Margin="12,0,0,0" HorizontalAlignment="Right" VerticalAlignment="Center" + IsEnabled="{Binding ElementName=GPUScalingToggle, Path=IsOn}" Style="{DynamicResource InvertedToggleSwitchStyle}" Toggled="RSRToggle_Toggled" /> - - + + + + - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0} %, ElementName=RSRSlider, Mode=OneWay}" /> + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + SelectionChanged="IntegerScalingComboBox_SelectionChanged" /> + + + + + + - - - - + + + + - - + + - + + Toggled="RISToggle_Toggled" /> + + + Visibility="{Binding ElementName=RISToggle, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}"> - - - - - - - - - - - - - - - - + HorizontalContentAlignment="Center" + IsReadOnly="True" + Text="{Binding Value, StringFormat={}{0:N0} %, ElementName=RISSlider, Mode=OneWay}" /> + + + + + + + + + + + + + + + + + + + + + + diff --git a/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs b/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs index d894d48c7..fb71e0a7e 100644 --- a/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs +++ b/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs @@ -6,8 +6,9 @@ using HandheldCompanion.Misc; using HandheldCompanion.Platforms; using HandheldCompanion.Utils; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using System; +using System.Collections.Generic; using System.Linq; using System.Timers; using System.Windows; @@ -42,19 +43,19 @@ public QuickProfilesPage() { InitializeComponent(); + // manage events ProcessManager.ForegroundChanged += ProcessManager_ForegroundChanged; - - ProfileManager.Applied += ProfileApplied; - + ProfileManager.Applied += ProfileManager_Applied; PowerProfileManager.Updated += PowerProfileManager_Updated; PowerProfileManager.Deleted += PowerProfileManager_Deleted; - - SystemManager.DisplaySettingsChanged += SystemManager_DisplaySettingsChanged; - SystemManager.RSRStateChanged += SystemManager_RSRStateChanged; - + SystemManager.Initialized += SystemManager_Initialized; + SystemManager.PrimaryScreenChanged += SystemManager_PrimaryScreenChanged; + SystemManager.StateChanged_RSR += SystemManager_StateChanged_RSR; + SystemManager.StateChanged_IntegerScaling += SystemManager_StateChanged_IntegerScaling; + SystemManager.StateChanged_GPUScaling += SystemManager_StateChanged_GPUScaling; HotkeysManager.HotkeyCreated += TriggerCreated; - InputsManager.TriggerUpdated += TriggerUpdated; + PlatformManager.RTSS.Updated += RTSS_Updated; foreach (var mode in (MotionOuput[])Enum.GetValues(typeof(MotionOuput))) { @@ -160,32 +161,67 @@ public QuickProfilesPage() UpdateTimer.AutoReset = false; UpdateTimer.Elapsed += (sender, e) => SubmitProfile(); - PlatformManager.RTSS.Updated += RTSS_Updated; - // force call RTSS_Updated(PlatformManager.RTSS.Status); } - private void SystemManager_RSRStateChanged(int RSRState, int RSRSharpness) + private void SystemManager_Initialized() + { + bool HasScalingModeSupport = ADLXWrapper.HasScalingModeSupport(); + bool HasIntegerScalingSupport = ADLXWrapper.HasIntegerScalingSupport(); + bool HasRSRSupport = ADLXWrapper.HasRSRSupport(); + bool HasGPUScalingSupport = ADLXWrapper.HasGPUScalingSupport(); + bool IsGPUScalingEnabled = ADLXWrapper.GetGPUScaling(); + + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + StackProfileRSR.IsEnabled = HasGPUScalingSupport && IsGPUScalingEnabled && HasRSRSupport; + StackProfileIS.IsEnabled = HasGPUScalingSupport && IsGPUScalingEnabled && HasIntegerScalingSupport; + StackProfileRIS.IsEnabled = HasGPUScalingSupport; // check if processor is AMD should be enough + GPUScalingToggle.IsEnabled = HasGPUScalingSupport; + GPUScalingComboBox.IsEnabled = HasGPUScalingSupport && HasScalingModeSupport; + + DesktopScreen desktopScreen = SystemManager.GetDesktopScreen(); + desktopScreen.screenDividers.ForEach(d => IntegerScalingComboBox.Items.Add(d)); + }); + } + + private void SystemManager_StateChanged_RSR(bool Supported, bool Enabled, int Sharpness) { // UI thread (async) Application.Current.Dispatcher.BeginInvoke(() => { - switch (RSRState) + using (new ScopedLock(updateLock)) { - case -1: - StackProfileRSR.IsEnabled = false; - break; - case 0: - StackProfileRSR.IsEnabled = true; - RSRToggle.IsOn = false; - RSRSlider.Value = RSRSharpness; - break; - case 1: - StackProfileRSR.IsEnabled = true; - RSRToggle.IsOn = true; - RSRSlider.Value = RSRSharpness; - break; + StackProfileRSR.IsEnabled = Supported; + } + }); + } + + private void SystemManager_StateChanged_GPUScaling(bool Supported, bool Enabled, int Mode) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(async () => + { + using (new ScopedLock(updateLock)) + { + GPUScalingToggle.IsEnabled = Supported; + StackProfileRIS.IsEnabled = Supported; // check if processor is AMD should be enough + StackProfileRSR.IsEnabled = Supported; + StackProfileIS.IsEnabled = Supported; + } + }); + } + + private void SystemManager_StateChanged_IntegerScaling(bool Supported, bool Enabled) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + using (new ScopedLock(updateLock)) + { + StackProfileIS.IsEnabled = Supported; } }); } @@ -198,7 +234,7 @@ private void RTSS_Updated(PlatformStatus status) switch (status) { case PlatformStatus.Ready: - var Processor = MainWindow.performanceManager.GetProcessor(); + var Processor = PerformanceManager.GetProcessor(); StackProfileFramerate.IsEnabled = true; break; case PlatformStatus.Stalled: @@ -209,17 +245,19 @@ private void RTSS_Updated(PlatformStatus status) }); } - private void SystemManager_DisplaySettingsChanged(ScreenResolution resolution) + private void SystemManager_PrimaryScreenChanged(DesktopScreen desktopScreen) { + List frameLimits = desktopScreen.GetFramelimits(); + // UI thread (async) Application.Current.Dispatcher.BeginInvoke(() => { - var screenFrequency = SystemManager.GetDesktopScreen().GetFrequency(); + cB_Framerate.Items.Clear(); + + foreach (ScreenFramelimit frameLimit in frameLimits) + cB_Framerate.Items.Add(frameLimit); - FramerateQuarter.Content = Convert.ToString(screenFrequency.GetValue(Frequency.Quarter)); - FramerateThird.Content = Convert.ToString(screenFrequency.GetValue(Frequency.Third)); - FramerateHalf.Content = Convert.ToString(screenFrequency.GetValue(Frequency.Half)); - FramerateFull.Content = Convert.ToString(screenFrequency.GetValue(Frequency.Full)); + cB_Framerate.SelectedItem = desktopScreen.GetClosest(selectedProfile.FramerateValue); }); } @@ -341,100 +379,140 @@ private void PowerProfile_Clicked(PowerProfile powerProfile) private void PowerProfile_Selected(PowerProfile powerProfile) { + if (selectedProfile is null) + return; + // UI thread (async) Application.Current.Dispatcher.BeginInvoke(() => { - // update UI SelectedPowerProfileName.Text = powerProfile.Name; - - // update profile - selectedProfile.PowerProfile = powerProfile.Guid; - UpdateProfile(); }); + + // update profile + selectedProfile.PowerProfile = powerProfile.Guid; + UpdateProfile(); } - private void ProfileApplied(Profile profile, UpdateSource source) + private DesktopScreen desktopScreen; + private void ProfileManager_Applied(Profile profile, UpdateSource source) { - if (true) + switch (source) { - switch (source) - { - // self update, unlock and exit - case UpdateSource.QuickProfilesPage: - case UpdateSource.Serializer: - return; - } + // self update, unlock and exit + case UpdateSource.QuickProfilesPage: + return; + } - // if an update is pending, execute it and stop timer - if (UpdateTimer.Enabled) - { - UpdateTimer.Stop(); - SubmitProfile(); - } + // if an update is pending, execute it and stop timer + if (UpdateTimer.Enabled) + { + UpdateTimer.Stop(); + SubmitProfile(); + } - // update profile - selectedProfile = profile; + // update profile + selectedProfile = profile; - // UI thread (async) - Application.Current.Dispatcher.BeginInvoke(() => + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + using (new ScopedLock(updateLock)) { - using (new ScopedLock(updateLock)) - { - // update profile name - CurrentProfileName.Text = selectedProfile.Name; - Toggle_ControllerLayout.IsEnabled = selectedProfile.Default ? false : true; - Toggle_ControllerLayout.IsOn = selectedProfile.LayoutEnabled; + // update profile name + CurrentProfileName.Text = selectedProfile.Name; + Toggle_ControllerLayout.IsOn = selectedProfile.LayoutEnabled; + Toggle_ControllerLayout.IsEnabled = !selectedProfile.Default; - // power profile - PowerProfile powerProfile = PowerProfileManager.GetProfile(profile.PowerProfile); - powerProfile.Check(this); + // sub profiles + cb_SubProfiles.Items.Clear(); + int selectedIndex = 0; - // gyro layout - if (!selectedProfile.Layout.GyroLayout.TryGetValue(AxisLayoutFlags.Gyroscope, out IActions currentAction)) + if (profile.Default) + { + cb_SubProfiles.Items.Add(profile); + cb_SubProfiles.IsEnabled = false; + } + else + { + Profile mainProfile = ProfileManager.GetProfileForSubProfile(selectedProfile); + Profile[] subProfiles = ProfileManager.GetSubProfilesFromPath(selectedProfile.Path, false); + + cb_SubProfiles.Items.Add(mainProfile); + foreach (Profile subProfile in subProfiles) { - // no gyro layout available, mark as disabled - cB_Output.SelectedIndex = (int)MotionOuput.Disabled; + cb_SubProfiles.Items.Add(subProfile); + if (subProfile.Guid == selectedProfile.Guid) + selectedIndex = cb_SubProfiles.Items.IndexOf(subProfile); } - else - { - // IActions - GridAntiDeadzone.Visibility = currentAction is AxisActions ? Visibility.Visible : Visibility.Collapsed; - GridGyroWeight.Visibility = currentAction is AxisActions ? Visibility.Visible : Visibility.Collapsed; + cb_SubProfiles.IsEnabled = true; + } - if (currentAction is AxisActions) - { - cB_Output.SelectedIndex = (int)((AxisActions)currentAction).Axis; - SliderUMCAntiDeadzone.Value = ((AxisActions)currentAction).AxisAntiDeadZone; - Slider_GyroWeight.Value = ((AxisActions)currentAction).gyroWeight; - } - else if (currentAction is MouseActions) - { - cB_Output.SelectedIndex = (int)((MouseActions)currentAction).MouseType - 1; - } + cb_SubProfiles.SelectedIndex = selectedIndex; - // GyroActions - cB_Input.SelectedIndex = (int)((GyroActions)currentAction).MotionInput; - cB_UMC_MotionDefaultOffOn.SelectedIndex = (int)((GyroActions)currentAction).MotionMode; + // power profile + PowerProfile powerProfile = PowerProfileManager.GetProfile(profile.PowerProfile); + powerProfile.Check(this); - // todo: move me to layout ? - SliderSensitivityX.Value = selectedProfile.MotionSensivityX; - SliderSensitivityY.Value = selectedProfile.MotionSensivityY; + // gyro layout + if (!selectedProfile.Layout.GyroLayout.TryGetValue(AxisLayoutFlags.Gyroscope, out IActions currentAction)) + { + // no gyro layout available, mark as disabled + cB_Output.SelectedIndex = (int)MotionOuput.Disabled; + } + else + { + // IActions + GridAntiDeadzone.Visibility = currentAction is AxisActions ? Visibility.Visible : Visibility.Collapsed; + GridGyroWeight.Visibility = currentAction is AxisActions ? Visibility.Visible : Visibility.Collapsed; - // todo: improve me ? - GyroHotkey.inputsChord.State = ((GyroActions)currentAction).MotionTrigger.Clone() as ButtonState; - GyroHotkey.DrawInput(); + if (currentAction is AxisActions) + { + cB_Output.SelectedIndex = (int)((AxisActions)currentAction).Axis; + SliderUMCAntiDeadzone.Value = ((AxisActions)currentAction).AxisAntiDeadZone; + Slider_GyroWeight.Value = ((AxisActions)currentAction).gyroWeight; + } + else if (currentAction is MouseActions) + { + cB_Output.SelectedIndex = (int)((MouseActions)currentAction).MouseType - 1; } - // Framerate - FramerateToggle.IsOn = selectedProfile.FramerateEnabled; - FramerateSlider.Value = selectedProfile.FramerateValue; + // GyroActions + cB_Input.SelectedIndex = (int)((GyroActions)currentAction).MotionInput; + cB_UMC_MotionDefaultOffOn.SelectedIndex = (int)((GyroActions)currentAction).MotionMode; + + // todo: move me to layout ? + SliderSensitivityX.Value = selectedProfile.MotionSensivityX; + SliderSensitivityY.Value = selectedProfile.MotionSensivityY; - // RSR - RSRToggle.IsOn = selectedProfile.RSREnabled; - RSRSlider.Value = selectedProfile.RSRSharpness; + // todo: improve me ? + GyroHotkey.inputsChord.State = ((GyroActions)currentAction).MotionTrigger.Clone() as ButtonState; + GyroHotkey.DrawInput(); } - }); - } + + // Framerate limit + desktopScreen = SystemManager.GetDesktopScreen(); + if (desktopScreen is not null) + cB_Framerate.SelectedItem = desktopScreen.GetClosest(selectedProfile.FramerateValue); + + // GPU Scaling + GPUScalingToggle.IsOn = selectedProfile.GPUScaling; + GPUScalingComboBox.SelectedIndex = selectedProfile.ScalingMode; + + // RSR + RSRToggle.IsOn = selectedProfile.RSREnabled; + RSRSlider.Value = selectedProfile.RSRSharpness; + + // Integer Scaling + IntegerScalingToggle.IsOn = selectedProfile.IntegerScalingEnabled; + + if (desktopScreen is not null) + IntegerScalingComboBox.SelectedItem = desktopScreen.screenDividers.FirstOrDefault(d => d.divider == selectedProfile.IntegerScalingDivider); + + // RIS + RISToggle.IsOn = selectedProfile.RISEnabled; + RISSlider.Value = selectedProfile.RISSharpness; + } + }); } private void ProcessManager_ForegroundChanged(ProcessEx processEx, ProcessEx backgroundEx) @@ -455,11 +533,12 @@ private void ProcessManager_ForegroundChanged(ProcessEx processEx, ProcessEx bac if (processEx.MainWindowHandle != IntPtr.Zero) { - var MainWindowTitle = ProcessUtils.GetWindowTitle(processEx.MainWindowHandle); + // string MainWindowTitle = ProcessUtils.GetWindowTitle(processEx.MainWindowHandle); ProfileToggle.IsEnabled = true; ProcessName.Text = currentProcess.Executable; ProcessPath.Text = currentProcess.Path; + SubProfilesBorder.Visibility = Visibility.Visible; } else { @@ -468,6 +547,7 @@ private void ProcessManager_ForegroundChanged(ProcessEx processEx, ProcessEx bac ProfileToggle.IsEnabled = false; ProcessName.Text = Properties.Resources.QuickProfilesPage_Waiting; ProcessPath.Text = string.Empty; + SubProfilesBorder.Visibility = Visibility.Collapsed; } } }); @@ -496,7 +576,7 @@ private void ProfileToggle_Toggled(object sender, RoutedEventArgs e) else { realProfile.Enabled = ProfileToggle.IsOn; - ProfileManager.UpdateOrCreateProfile(realProfile, UpdateSource.Creation); + ProfileManager.UpdateOrCreateProfile(realProfile, UpdateSource.QuickProfilesCreation); } } @@ -514,7 +594,7 @@ private void CreateProfile() if (UpdateTimer.Enabled) UpdateTimer.Stop(); - SubmitProfile(UpdateSource.Creation); + SubmitProfile(UpdateSource.QuickProfilesCreation); } private void cB_Input_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -709,67 +789,36 @@ private void cB_UMC_MotionDefaultOffOn_SelectionChanged(object sender, RoutedEve UpdateProfile(); } - private void FramerateToggle_Toggled(object sender, RoutedEventArgs e) + private void RSRToggle_Toggled(object sender, RoutedEventArgs e) { - // UI thread (async) - Application.Current.Dispatcher.BeginInvoke(() => - { - if (FramerateToggle.IsOn) - { - FramerateSlider_ValueChanged(null, null); - } - else - { - foreach (Control control in FramerateModeGrid.Children) - { - if (control is not Label) - continue; - - control.SetResourceReference(Control.ForegroundProperty, "SystemControlForegroundBaseMediumBrush"); - } - } - }); - if (selectedProfile is null) return; + // wait until lock is released if (updateLock) return; - selectedProfile.FramerateEnabled = FramerateToggle.IsOn; + UpdateGraphicsSettings(UpdateGraphicsSettingsSource.RadeonSuperResolution, RSRToggle.IsOn); UpdateProfile(); } - private void FramerateSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) + private void RSRSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { - // UI thread (async) - Application.Current.Dispatcher.BeginInvoke(() => - { - var value = (int)FramerateSlider.Value; - - foreach (Control control in FramerateModeGrid.Children) - { - if (control is not Label) - continue; - - control.SetResourceReference(Control.ForegroundProperty, "SystemControlForegroundBaseMediumBrush"); - } - - Label label = (Label)FramerateModeGrid.Children[value]; - label.SetResourceReference(Control.ForegroundProperty, "AccentButtonBackground"); - }); - if (selectedProfile is null) return; + if (!RSRSlider.IsInitialized) + return; + + // wait until lock is released if (updateLock) return; - selectedProfile.FramerateValue = (int)FramerateSlider.Value; + selectedProfile.RSRSharpness = (int)RSRSlider.Value; UpdateProfile(); } - private void RSRToggle_Toggled(object sender, RoutedEventArgs e) + private void RISToggle_Toggled(object sender, RoutedEventArgs e) { if (selectedProfile is null) return; @@ -778,23 +827,23 @@ private void RSRToggle_Toggled(object sender, RoutedEventArgs e) if (updateLock) return; - selectedProfile.RSREnabled = RSRToggle.IsOn; + UpdateGraphicsSettings(UpdateGraphicsSettingsSource.RadeonImageSharpening, RISToggle.IsOn); UpdateProfile(); } - private void RSRSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) + private void RISSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { if (selectedProfile is null) return; - if (!RSRSlider.IsInitialized) + if (!RISSlider.IsInitialized) return; // wait until lock is released if (updateLock) return; - selectedProfile.RSRSharpness = (int)RSRSlider.Value; + selectedProfile.RISSharpness = (int)RISSlider.Value; UpdateProfile(); } @@ -820,4 +869,187 @@ private void Button_PowerSettings_Create_Click(object sender, RoutedEventArgs e) PowerProfileManager.UpdateOrCreateProfile(powerProfile, UpdateSource.Creation); } + + private void IntegerScalingToggle_Toggled(object sender, RoutedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + UpdateGraphicsSettings(UpdateGraphicsSettingsSource.IntegerScaling, IntegerScalingToggle.IsOn); + UpdateProfile(); + } + + private void GPUScalingComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (GPUScalingComboBox.SelectedIndex == -1 || selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + int selectedIndex = GPUScalingComboBox.SelectedIndex; + // RSR does not work with ScalingMode.Center + if (selectedProfile.RSREnabled && selectedIndex == 2) + { + selectedProfile.ScalingMode = 1; + GPUScalingComboBox.SelectedIndex = 1; + } + else + { + selectedProfile.ScalingMode = GPUScalingComboBox.SelectedIndex; + } + UpdateProfile(); + } + + private void GPUScaling_Toggled(object sender, RoutedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + UpdateGraphicsSettings(UpdateGraphicsSettingsSource.GPUScaling, GPUScalingToggle.IsOn); + UpdateProfile(); + } + + private void cb_SubProfiles_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + // return if combobox selected item is null + if (cb_SubProfiles.SelectedIndex == -1) + return; + + LogManager.LogInformation($"Subprofile changed in Quick Settings - ind: {cb_SubProfiles.SelectedIndex} - subprofile: {cb_SubProfiles.SelectedItem}"); + selectedProfile = (Profile)cb_SubProfiles.SelectedItem; + UpdateProfile(); + } + + private void cB_Framerate_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + // return if combobox selected item is null + if (cB_Framerate.SelectedIndex == -1) + return; + + if (cB_Framerate.SelectedItem is ScreenFramelimit screenFramelimit) + { + selectedProfile.FramerateValue = screenFramelimit.limit; + UpdateProfile(); + } + } + + private void IntegerScalingComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (IntegerScalingComboBox.SelectedIndex == -1 || selectedProfile is null) + return; + + // wait until lock is released + if (updateLock) + return; + + var divider = 1; + if (IntegerScalingComboBox.SelectedItem is ScreenDivider screenDivider) + { + divider = screenDivider.divider; + } + + selectedProfile.IntegerScalingDivider = divider; + UpdateProfile(); + } + + private enum UpdateGraphicsSettingsSource + { + GPUScaling, + RadeonSuperResolution, + RadeonImageSharpening, + IntegerScaling + } + + private void UpdateGraphicsSettings(UpdateGraphicsSettingsSource source, bool isEnabled) + { + using (new ScopedLock(updateLock)) + { + switch (source) + { + case UpdateGraphicsSettingsSource.GPUScaling: + { + selectedProfile.GPUScaling = isEnabled; + if (!isEnabled) + { + selectedProfile.RSREnabled = false; + selectedProfile.IntegerScalingEnabled = false; + + RSRToggle.IsOn = false; + IntegerScalingToggle.IsOn = false; + } + } + break; + // RSR is incompatible with RIS and IS + case UpdateGraphicsSettingsSource.RadeonSuperResolution: + { + selectedProfile.RSREnabled = isEnabled; + if (isEnabled) + { + selectedProfile.RISEnabled = false; + selectedProfile.IntegerScalingEnabled = false; + + RISToggle.IsOn = false; + IntegerScalingToggle.IsOn = false; + + // RSR does not support ScalingMode.Center + if (selectedProfile.ScalingMode == 2) + { + selectedProfile.ScalingMode = 1; + GPUScalingComboBox.SelectedIndex = 1; + } + } + } + break; + // Image Sharpening is incompatible with RSR + case UpdateGraphicsSettingsSource.RadeonImageSharpening: + { + selectedProfile.RISEnabled = isEnabled; + if (isEnabled) + { + selectedProfile.RSREnabled = false; + + RSRToggle.IsOn = false; + } + } + break; + + // Integer Scaling is incompatible with RSR + case UpdateGraphicsSettingsSource.IntegerScaling: + { + selectedProfile.IntegerScalingEnabled = isEnabled; + if (isEnabled) + { + selectedProfile.RSREnabled = false; + + RSRToggle.IsOn = false; + } + } + break; + } + } + } } \ No newline at end of file diff --git a/HandheldCompanion/Views/QuickPages/QuickSettingsPage.xaml b/HandheldCompanion/Views/QuickPages/QuickSettingsPage.xaml deleted file mode 100644 index 6e952c89d..000000000 --- a/HandheldCompanion/Views/QuickPages/QuickSettingsPage.xaml +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/HandheldCompanion/Views/QuickPages/QuickSettingsPage.xaml.cs b/HandheldCompanion/Views/QuickPages/QuickSettingsPage.xaml.cs deleted file mode 100644 index 83fa53afa..000000000 --- a/HandheldCompanion/Views/QuickPages/QuickSettingsPage.xaml.cs +++ /dev/null @@ -1,154 +0,0 @@ -using HandheldCompanion.Managers; -using HandheldCompanion.Managers.Desktop; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System.Timers; -using System.Windows; -using System.Windows.Controls; -using Windows.Devices.Bluetooth; -using Windows.Devices.Radios; - -namespace HandheldCompanion.Views.QuickPages; - -/// -/// Interaction logic for QuickSettingsPage.xaml -/// -public partial class QuickSettingsPage : Page -{ - private IReadOnlyList radios; - private Timer radioTimer; - - public QuickSettingsPage(string Tag) : this() - { - this.Tag = Tag; - - HotkeysManager.HotkeyCreated += HotkeysManager_HotkeyCreated; - HotkeysManager.HotkeyUpdated += HotkeysManager_HotkeyUpdated; - - SystemManager.PrimaryScreenChanged += DesktopManager_PrimaryScreenChanged; - SystemManager.DisplaySettingsChanged += DesktopManager_DisplaySettingsChanged; - - radioTimer = new(1000); - radioTimer.Elapsed += RadioTimer_Elapsed; - radioTimer.Start(); - } - - private void RadioTimer_Elapsed(object? sender, ElapsedEventArgs e) - { - new Task(async () => - { - // Get the Bluetooth adapter - BluetoothAdapter adapter = await BluetoothAdapter.GetDefaultAsync(); - - // Get the Bluetooth radio - radios = await Radio.GetRadiosAsync(); - - // UI thread (async) - _ = Application.Current.Dispatcher.BeginInvoke(() => - { - // WIFI - WifiToggle.IsEnabled = radios.Where(radio => radio.Kind == RadioKind.WiFi).Any(); - WifiToggle.IsOn = radios.Where(radio => radio.Kind == RadioKind.WiFi && radio.State == RadioState.On).Any(); - - // Bluetooth - BluetoothToggle.IsEnabled = radios.Where(radio => radio.Kind == RadioKind.Bluetooth).Any(); - BluetoothToggle.IsOn = radios.Where(radio => radio.Kind == RadioKind.Bluetooth && radio.State == RadioState.On).Any(); - }); - }).Start(); - } - - public QuickSettingsPage() - { - InitializeComponent(); - } - - private void HotkeysManager_HotkeyUpdated(Hotkey hotkey) - { - UpdatePins(); - } - - private void HotkeysManager_HotkeyCreated(Hotkey hotkey) - { - UpdatePins(); - } - - private void UpdatePins() - { - // todo, implement quick hotkey order - QuickHotkeys.Children.Clear(); - - foreach (var hotkey in HotkeysManager.Hotkeys.Values.Where(item => item.IsPinned)) - QuickHotkeys.Children.Add(hotkey.GetPin()); - } - - private void DesktopManager_PrimaryScreenChanged(DesktopScreen screen) - { - ComboBoxResolution.Items.Clear(); - foreach (var resolution in screen.resolutions) - ComboBoxResolution.Items.Add(resolution); - } - - private void DesktopManager_DisplaySettingsChanged(ScreenResolution resolution) - { - ComboBoxResolution.SelectedItem = resolution; - ComboBoxFrequency.SelectedItem = SystemManager.GetDesktopScreen().GetFrequency(); - } - - private void ComboBoxResolution_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (ComboBoxResolution.SelectedItem is null) - return; - - var resolution = (ScreenResolution)ComboBoxResolution.SelectedItem; - - ComboBoxFrequency.Items.Clear(); - foreach (var frequency in resolution.Frequencies.Values) - ComboBoxFrequency.Items.Add(frequency); - - ComboBoxFrequency.SelectedItem = SystemManager.GetDesktopScreen().GetFrequency(); - - SetResolution(); - } - - private void ComboBoxFrequency_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (ComboBoxFrequency.SelectedItem is null) - return; - - SetResolution(); - } - - private void SetResolution() - { - if (ComboBoxResolution.SelectedItem is null) - return; - - if (ComboBoxFrequency.SelectedItem is null) - return; - - var resolution = (ScreenResolution)ComboBoxResolution.SelectedItem; - var frequency = (ScreenFrequency)ComboBoxFrequency.SelectedItem; - - // update current screen resolution - SystemManager.SetResolution(resolution.Width, resolution.Height, (int)frequency.GetValue(Frequency.Full), resolution.BitsPerPel); - } - - private void WIFIToggle_Toggled(object sender, RoutedEventArgs e) - { - foreach(Radio radio in radios.Where(r => r.Kind == RadioKind.WiFi)) - _ = radio.SetStateAsync(WifiToggle.IsOn ? RadioState.On : RadioState.Off); - } - - private void BluetoothToggle_Toggled(object sender, RoutedEventArgs e) - { - foreach (Radio radio in radios.Where(r => r.Kind == RadioKind.Bluetooth)) - _ = radio.SetStateAsync(BluetoothToggle.IsOn ? RadioState.On : RadioState.Off); - } - - internal void Close() - { - radioTimer.Stop(); - } -} \ No newline at end of file diff --git a/HandheldCompanion/Views/Windows/MainWindow.xaml b/HandheldCompanion/Views/Windows/MainWindow.xaml index 0cfbea380..a89bd9b10 100644 --- a/HandheldCompanion/Views/Windows/MainWindow.xaml +++ b/HandheldCompanion/Views/Windows/MainWindow.xaml @@ -1,240 +1,243 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HandheldCompanion/Views/Windows/MainWindow.xaml.cs b/HandheldCompanion/Views/Windows/MainWindow.xaml.cs index c2311f30e..f122323f7 100644 --- a/HandheldCompanion/Views/Windows/MainWindow.xaml.cs +++ b/HandheldCompanion/Views/Windows/MainWindow.xaml.cs @@ -6,7 +6,7 @@ using HandheldCompanion.Views.Classes; using HandheldCompanion.Views.Pages; using HandheldCompanion.Views.Windows; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using Nefarius.Utilities.DeviceManagement.PnP; using System; using System.Collections.Generic; @@ -59,12 +59,6 @@ public partial class MainWindow : GamepadWindow public static OverlayTrackpad overlayTrackpad; public static OverlayQuickTools overlayquickTools; - // manager(s) vars - private static readonly List _managers = new(); - public static TaskManager taskManager; - public static PerformanceManager performanceManager; - public static UpdateManager updateManager; - public static string CurrentExe, CurrentPath; private static MainWindow CurrentWindow; @@ -197,61 +191,45 @@ public MainWindow(FileVersionInfo _fileVersionInfo, Assembly CurrentAssembly) SettingsManager.SetProperty("FirstStart", false); } - // load manager(s) - // todo: make me static - loadManagers(); - // load window(s) loadWindows(); // load page(s) loadPages(); - // start static managers in sequence - // managers that has to be stopped/started when session status changes shouldn't be put here + // manage events + InputsManager.TriggerRaised += InputsManager_TriggerRaised; + PowerManager.SystemStatusChanged += OnSystemStatusChanged; + DeviceManager.UsbDeviceArrived += GenericDeviceUpdated; + DeviceManager.UsbDeviceRemoved += GenericDeviceUpdated; + ControllerManager.ControllerSelected += ControllerManager_ControllerSelected; + VirtualManager.ControllerSelected += VirtualManager_ControllerSelected; ToastManager.Start(); ToastManager.IsEnabled = SettingsManager.GetBoolean("ToastEnable"); + // start static managers in sequence PowerProfileManager.Start(); ProfileManager.Start(); - - ControllerManager.ControllerSelected += ControllerManager_ControllerSelected; ControllerManager.Start(); HotkeysManager.Start(); - - DeviceManager.UsbDeviceArrived += GenericDeviceUpdated; - DeviceManager.UsbDeviceRemoved += GenericDeviceUpdated; DeviceManager.Start(); - OSDManager.Start(); LayoutManager.Start(); - - // todo: improve overall threading logic - new Thread(() => - { - PlatformManager.Start(); - ProcessManager.Start(); - }).Start(); - - PowerManager.SystemStatusChanged += OnSystemStatusChanged; PowerManager.Start(); - DynamicLightingManager.Start(); - SystemManager.Start(); VirtualManager.Start(); - - InputsManager.TriggerRaised += InputsManager_TriggerRaised; InputsManager.Start(); SensorsManager.Start(); TimerManager.Start(); - VirtualManager.ControllerSelected += VirtualManager_ControllerSelected; - - // start managers asynchroneously - foreach (var manager in _managers) - new Thread(manager.Start).Start(); + // todo: improve overall threading logic + new Thread(() => { PlatformManager.Start(); }).Start(); + new Thread(() => { ProcessManager.Start(); }).Start(); + new Thread(() => { TaskManager.Start(CurrentExe); }).Start(); + new Thread(() => { PerformanceManager.Start(); }).Start(); + new Thread(() => { UpdateManager.Start(); }).Start(); // start setting last SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; @@ -445,19 +423,6 @@ private void loadWindows() overlayquickTools = new OverlayQuickTools(); } - private void loadManagers() - { - // initialize managers - taskManager = new TaskManager("HandheldCompanion", CurrentExe); - performanceManager = new PerformanceManager(); - updateManager = new UpdateManager(); - - // store managers - _managers.Add(taskManager); - _managers.Add(performanceManager); - _managers.Add(updateManager); - } - private void GenericDeviceUpdated(PnPDevice device, DeviceEventArgs obj) { // todo: improve me @@ -689,15 +654,10 @@ private void Window_Closed(object sender, EventArgs e) overlayTrackpad.Close(); overlayquickTools.Close(true); - // TODO: Make static - taskManager.Stop(); - performanceManager.Stop(); - VirtualManager.Stop(); SystemManager.Stop(); MotionManager.Stop(); SensorsManager.Stop(); - ControllerManager.Stop(); InputsManager.Stop(); DeviceManager.Stop(); @@ -709,6 +669,9 @@ private void Window_Closed(object sender, EventArgs e) PowerManager.Stop(); ProcessManager.Stop(); ToastManager.Stop(); + TaskManager.Stop(); + PerformanceManager.Stop(); + UpdateManager.Stop(); // closing page(s) controllerPage.Page_Closed(); diff --git a/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml b/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml index 6696782a8..c9fe51ffe 100644 --- a/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml +++ b/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml @@ -28,55 +28,53 @@ WindowStyle="ToolWindow" mc:Ignorable="d"> - - + - - - + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - + + + + \ No newline at end of file diff --git a/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml.cs b/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml.cs index ebcfd52f5..0f9267f3d 100644 --- a/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml.cs +++ b/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml.cs @@ -3,7 +3,7 @@ using HandheldCompanion.Utils; using HandheldCompanion.Views.Classes; using HandheldCompanion.Views.QuickPages; -using Inkore.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls; using System; using System.Collections.Generic; using System.ComponentModel; @@ -14,18 +14,21 @@ using System.Windows.Forms; using System.Windows.Input; using System.Windows.Interop; +using System.Windows.Media; using System.Windows.Navigation; using System.Windows.Threading; using Windows.System.Power; using WpfScreenHelper; using WpfScreenHelper.Enum; using Application = System.Windows.Application; +using ComboBox = System.Windows.Controls.ComboBox; using KeyEventArgs = System.Windows.Input.KeyEventArgs; using Page = System.Windows.Controls.Page; using PowerLineStatus = System.Windows.Forms.PowerLineStatus; using PowerManager = HandheldCompanion.Managers.PowerManager; using Screen = WpfScreenHelper.Screen; using SystemPowerManager = Windows.System.Power.PowerManager; +using Timer = System.Timers.Timer; namespace HandheldCompanion.Views.Windows; @@ -41,6 +44,9 @@ public partial class OverlayQuickTools : GamepadWindow const UInt32 SWP_NOMOVE = 0x0002; const UInt32 SWP_NOACTIVATE = 0x0010; const UInt32 SWP_NOZORDER = 0x0004; + + // Define the Win32 API constants and functions + const int WM_PAINT = 0x000F; const int WM_ACTIVATEAPP = 0x001C; const int WM_ACTIVATE = 0x0006; const int WM_SETFOCUS = 0x0007; @@ -56,6 +62,9 @@ public partial class OverlayQuickTools : GamepadWindow private HwndSource hwndSource; + private Dictionary cacheModes = new(); + private Timer WM_PAINT_TIMER; + // page vars private readonly Dictionary _pages = new(); @@ -64,10 +73,10 @@ public partial class OverlayQuickTools : GamepadWindow private readonly DispatcherTimer clockUpdateTimer; public QuickHomePage homePage; - public QuickSettingsPage settingsPage; public QuickDevicePage devicePage; public QuickPerformancePage performancePage; public QuickProfilesPage profilesPage; + public QuickOverlayPage overlayPage; public QuickSuspenderPage suspenderPage; private string preNavItemTag; @@ -85,6 +94,9 @@ public OverlayQuickTools() clockUpdateTimer.Interval = TimeSpan.FromMilliseconds(500); clockUpdateTimer.Tick += UpdateTime; + WM_PAINT_TIMER = new(250) { AutoReset = false }; + WM_PAINT_TIMER.Elapsed += WM_PAINT_TIMER_Tick; + // create manager(s) PowerManager.PowerStatusChanged += PowerManager_PowerStatusChanged; @@ -93,22 +105,18 @@ public OverlayQuickTools() // create pages homePage = new("quickhome"); - settingsPage = new("quicksettings"); devicePage = new("quickdevice"); performancePage = new("quickperformance"); profilesPage = new("quickprofiles"); + overlayPage = new("quickoverlay"); suspenderPage = new("quicksuspender"); _pages.Add("QuickHomePage", homePage); - _pages.Add("QuickSettingsPage", settingsPage); _pages.Add("QuickDevicePage", devicePage); _pages.Add("QuickPerformancePage", performancePage); _pages.Add("QuickProfilesPage", profilesPage); + _pages.Add("QuickOverlayPage", overlayPage); _pages.Add("QuickSuspenderPage", suspenderPage); - - // update Position and Size - Height = (int)Math.Max(MinHeight, SettingsManager.GetDouble("QuickToolsHeight")); - navView.IsPaneOpen = SettingsManager.GetBoolean("QuickToolsIsPaneOpen"); } private void SettingsManager_SettingValueChanged(string name, object value) @@ -135,56 +143,38 @@ private void SettingsManager_SettingValueChanged(string name, object value) private void SystemManager_DisplaySettingsChanged(ScreenResolution resolution) { - var QuickToolsLocation = SettingsManager.GetInt("QuickToolsLocation"); + int QuickToolsLocation = SettingsManager.GetInt("QuickToolsLocation"); UpdateLocation(QuickToolsLocation); } private void UpdateLocation(int QuickToolsLocation) { - switch (QuickToolsLocation) + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => { - // top, left - case 0: - { - this.SetWindowPosition(WindowPositions.TopLeft, Screen.PrimaryScreen); - Top += Margin.Top; - Left += Margin.Left; - } - break; - - // top, right - case 1: - { - this.SetWindowPosition(WindowPositions.TopRight, Screen.PrimaryScreen); - Top += Margin.Top; - Left -= Margin.Left; - } - break; - - // bottom, left - case 2: - { - this.SetWindowPosition(WindowPositions.BottomLeft, Screen.PrimaryScreen); - Top -= Margin.Top; + switch (QuickToolsLocation) + { + // top, left + // bottom, left + case 0: + case 2: + this.SetWindowPosition(WindowPositions.Left, Screen.PrimaryScreen); Left += Margin.Left; - } - break; + break; - // bottom, right - default: - case 3: - { - this.SetWindowPosition(WindowPositions.BottomRight, Screen.PrimaryScreen); - Top -= Margin.Top; - Left -= Margin.Left; - } - break; - } + // top, right + // bottom, right + default: + case 1: + case 3: + this.SetWindowPosition(WindowPositions.Right, Screen.PrimaryScreen); + Left -= Margin.Right; + break; + } - // prevent window's from being too tall, add margin for top and bottom - var maxHeight = (int)(Screen.PrimaryScreen.WpfBounds.Height - 2 * Margin.Top); - if (Height > maxHeight) - Height = maxHeight; + Height = MinHeight = MaxHeight = (int)(Screen.PrimaryScreen.WpfBounds.Height - (2.0d * Margin.Top)); + Top = Margin.Top; + }); } private void PowerManager_PowerStatusChanged(PowerStatus status) @@ -253,11 +243,9 @@ private void Window_Loaded(object sender, RoutedEventArgs e) hwndSource = PresentationSource.FromVisual(this) as HwndSource; hwndSource.AddHook(WndProc); - // workaround: fix the stalled UI rendering, at the cost of forcing the window to render over CPU at 30fps if (hwndSource != null) { - hwndSource.CompositionTarget.RenderMode = RenderMode.Default; - // hwndSource.CompositionTarget.RenderMode = RenderMode.SoftwareOnly; + hwndSource.CompositionTarget.RenderMode = RenderMode.SoftwareOnly; WinAPI.SetWindowPos(hwndSource.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); } } @@ -326,14 +314,41 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b } break; - default: - // Debug.WriteLine($"{msg}\t\t{wParam}\t\t\t{lParam}"); + case WM_PAINT: + { + // Loop through all visual elements in the window + foreach (var element in WPFUtils.FindVisualChildren(this)) + { + if (element.CacheMode is not null) + { + // Store the previous CacheMode value + cacheModes[element] = element.CacheMode.Clone(); + + // Set the CacheMode to null + element.CacheMode = null; + } + } + + WM_PAINT_TIMER.Stop(); + WM_PAINT_TIMER.Start(); + } break; } return IntPtr.Zero; } + private void WM_PAINT_TIMER_Tick(object? sender, EventArgs e) + { + // UI thread + Application.Current.Dispatcher.Invoke(() => + { + // Set the CacheMode back to the previous value + foreach (UIElement element in cacheModes.Keys) + element.CacheMode = cacheModes[element]; + }); + } + private void HandleEsc(object sender, KeyEventArgs e) { if (e.Key == Key.Escape) @@ -372,24 +387,14 @@ public void ToggleVisibility() private void Window_Closing(object sender, CancelEventArgs e) { - // position and size settings - switch (WindowState) - { - case WindowState.Normal: - case WindowState.Maximized: - SettingsManager.SetProperty("QuickToolsHeight", Height); - break; - } - - SettingsManager.SetProperty("QuickToolsIsPaneOpen", navView.IsPaneOpen); - e.Cancel = !isClosing; if (!isClosing) ToggleVisibility(); else { - settingsPage.Close(); + // close pages + devicePage.Close(); } } diff --git a/HandheldCompanion/XInputPlus/XInputPlus.cs b/HandheldCompanion/XInputPlus/XInputPlus.cs index 1cc5a52ac..fe4b3a5a0 100644 --- a/HandheldCompanion/XInputPlus/XInputPlus.cs +++ b/HandheldCompanion/XInputPlus/XInputPlus.cs @@ -352,51 +352,59 @@ public static bool UnregisterApplication(Profile profile) return true; } + private static object writeLock = new(); public static bool WriteXInputPlusINI(string directoryPath, bool x64bit) { - var IniPath = Path.Combine(directoryPath, "XInputPlus.ini"); + lock (writeLock) + { + string IniPath = Path.Combine(directoryPath, "XInputPlus.ini"); - if (!FileUtils.IsFileWritable(IniPath)) - return false; + if (!FileUtils.IsFileWritable(IniPath)) + return false; - // prepare index array - List userIndex = new() { 1, 2, 3, 4 }; + // prepare index array + List userIndex = new() { 1, 2, 3, 4 }; - // prepare IniFile - File.WriteAllText(IniPath, IniContent); - IniFile IniFile = new IniFile(IniPath); - IniFile.Write("FileVersion", x64bit ? "X64" : "X86", "Misc"); + // prepare IniFile + try + { + File.WriteAllText(IniPath, IniContent); + IniFile IniFile = new IniFile(IniPath); + IniFile.Write("FileVersion", x64bit ? "X64" : "X86", "Misc"); - // reset controller index values - for (int i = 0; i < userIndex.Count; i++) - IniFile.Write($"Controller{i + 1}", "0", "ControllerNumber"); + // reset controller index values + for (int i = 0; i < userIndex.Count; i++) + IniFile.Write($"Controller{i + 1}", "0", "ControllerNumber"); - // we need to define Controller index overwrite - XInputController vController = ControllerManager.GetVirtualControllers().OfType().FirstOrDefault(); - if (vController is null) - return false; + // we need to define Controller index overwrite + XInputController vController = ControllerManager.GetVirtualControllers().OfType().FirstOrDefault(); + if (vController is null) + return false; - // get virtual controller index and update IniFile - int idx = vController.GetUserIndex() + 1; - IniFile.Write("Controller1", Convert.ToString(idx), "ControllerNumber"); + // get virtual controller index and update IniFile + int idx = vController.GetUserIndex() + 1; + IniFile.Write("Controller1", Convert.ToString(idx), "ControllerNumber"); - // remove virtual controller index from it - userIndex.Remove(idx); + // remove virtual controller index from it + userIndex.Remove(idx); - // remove all hidden physical controllers from the list - foreach(XInputController pController in ControllerManager.GetPhysicalControllers().OfType().Where(c => c.IsHidden())) - userIndex.Remove(pController.GetUserIndex() + 1); + // remove all hidden physical controllers from the list + foreach (XInputController pController in ControllerManager.GetPhysicalControllers().OfType().Where(c => c.IsHidden())) + userIndex.Remove(pController.GetUserIndex() + 1); - for (int i = 0; i < userIndex.Count; i++) - { - int cIdx = userIndex[i]; - IniFile.Write($"Controller{i + 2}", Convert.ToString(cIdx), "ControllerNumber"); - } + for (int i = 0; i < userIndex.Count; i++) + { + int cIdx = userIndex[i]; + IniFile.Write($"Controller{i + 2}", Convert.ToString(cIdx), "ControllerNumber"); + } - LogManager.LogDebug("XInputPlus INI wrote in {0}. Controller1 set to UserIndex: {1}", - directoryPath, idx); + LogManager.LogDebug("XInputPlus INI wrote in {0}. Controller1 set to UserIndex: {1}", + directoryPath, idx); - return true; + return true; + } + catch { return false; } + } } // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684139%28v=vs.85%29.aspx diff --git a/README.md b/README.md index 910637c77..c5cc0f639 100644 --- a/README.md +++ b/README.md @@ -36,14 +36,15 @@ The software is built for Windows 10/Windows 11 (x86 and amd64). - AYA Neo Next and its different versions - AYA Neo Air and it's different versions - AYA Neo 2, Geek, 2S Geek 1S -- Ayn Loki (all models) +- AYA Neo KUN - ONEXPLAYER MINI and its different versions (Intel, AMD, Gundam) -- GPD WIN Max 2 (Intel and AMD) +- GPD WIN Max 2 (INTEL, AMD) - GPD Win 2 - GPD Win 3 - GPD Win 4 -- Steam Deck (LCD and OLED) -- Lenovo Legion Go (WIP) +- Steam Deck (LCD, OLED) +- Ayn Loki (all models) +- Lenovo Legion Go ## Supported Sensors - Bosch BMI160 (and similar) diff --git a/redist/hwi_766.exe b/redist/hwi_766.exe deleted file mode 100644 index d71ef3df8..000000000 Binary files a/redist/hwi_766.exe and /dev/null differ