From 9a3119ccc255e1d88e270ba5ce6ef40a4f41b66b Mon Sep 17 00:00:00 2001 From: strifeforlyfe Date: Fri, 5 Jun 2026 15:53:21 -0500 Subject: [PATCH 01/47] Fix trigger full pull threshold --- DS4Windows/DS4Control/DS4StateFieldMapping.cs | 10 +++- DS4Windows/DS4Control/Mapping.cs | 14 ++--- DS4WindowsTests/TriggerFullPullTests.cs | 54 +++++++++++++++++++ 3 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 DS4WindowsTests/TriggerFullPullTests.cs diff --git a/DS4Windows/DS4Control/DS4StateFieldMapping.cs b/DS4Windows/DS4Control/DS4StateFieldMapping.cs index 3da1ac7..2631d48 100644 --- a/DS4Windows/DS4Control/DS4StateFieldMapping.cs +++ b/DS4Windows/DS4Control/DS4StateFieldMapping.cs @@ -22,6 +22,7 @@ public class DS4StateFieldMapping { public enum ControlType : int { Unknown = 0, Button, AxisDir, Trigger, Touch, GyroDir, SwipeDir } public const byte LAST_DS4_ACTION = (byte)DS4Controls.TouchEnded; + public const byte TRIGGER_FULL_PULL_THRESHOLD = 250; public bool[] buttons = new bool[(int)LAST_DS4_ACTION + 1]; public byte[] axisdirs = new byte[(int)LAST_DS4_ACTION + 1]; @@ -121,10 +122,10 @@ public void PopulateFieldMapping(DS4State cState, DS4StateExposed exposeState, M triggers[(int)DS4Controls.R2] = cState.R2; buttons[(int)DS4Controls.L1] = cState.L1; - buttons[(int)DS4Controls.L2FullPull] = cState.L2Raw == 255; + buttons[(int)DS4Controls.L2FullPull] = IsTriggerFullPull(cState.L2Raw); buttons[(int)DS4Controls.L3] = cState.L3; buttons[(int)DS4Controls.R1] = cState.R1; - buttons[(int)DS4Controls.R2FullPull] = cState.R2Raw == 255; + buttons[(int)DS4Controls.R2FullPull] = IsTriggerFullPull(cState.R2Raw); buttons[(int)DS4Controls.R3] = cState.R3; buttons[(int)DS4Controls.Cross] = cState.Cross; @@ -183,6 +184,11 @@ public void PopulateFieldMapping(DS4State cState, DS4StateExposed exposeState, M } } + public static bool IsTriggerFullPull(byte rawTriggerValue) + { + return rawTriggerValue >= TRIGGER_FULL_PULL_THRESHOLD; + } + public void PopulateState(DS4State state) { unchecked diff --git a/DS4Windows/DS4Control/Mapping.cs b/DS4Windows/DS4Control/Mapping.cs index 1d86600..e251d88 100644 --- a/DS4Windows/DS4Control/Mapping.cs +++ b/DS4Windows/DS4Control/Mapping.cs @@ -3112,14 +3112,14 @@ private static void ProcessTwoStageTrigger(int device, DS4State cState, byte tri switch (outputSettings.twoStageMode) { case TwoStageTriggerMode.Normal: - if (triggerRawValue == 255) + if (DS4StateFieldMapping.IsTriggerFullPull(triggerRawValue)) { dcsFullPull = inputFullPull; } break; case TwoStageTriggerMode.ExclusiveButtons: - if (triggerRawValue == 255) + if (DS4StateFieldMapping.IsTriggerFullPull(triggerRawValue)) { dcsFullPull = inputFullPull; dcsTemp = null; @@ -3145,7 +3145,7 @@ private static void ProcessTwoStageTrigger(int device, DS4State cState, byte tri triggerData.actionStateMode = TwoStageTriggerMappingData.EngageButtonsMode.Both; - if (triggerRawValue == 255) + if (DS4StateFieldMapping.IsTriggerFullPull(triggerRawValue)) { // Full pull now activates both. Soft pull action // no longer engaged with threshold @@ -3189,7 +3189,7 @@ private static void ProcessTwoStageTrigger(int device, DS4State cState, byte tri { triggerData.outputActive = true; - if (triggerRawValue == 255) + if (DS4StateFieldMapping.IsTriggerFullPull(triggerRawValue)) { dcsFullPull = inputFullPull; triggerData.fullPullActActive = true; @@ -3206,7 +3206,7 @@ private static void ProcessTwoStageTrigger(int device, DS4State cState, byte tri else if (triggerData.outputActive) { //DS4State pState = d.getPreviousStateRef(); - if (triggerRawValue == 255) + if (DS4StateFieldMapping.IsTriggerFullPull(triggerRawValue)) { dcsFullPull = inputFullPull; triggerData.fullPullActActive = true; @@ -3249,7 +3249,7 @@ private static void ProcessTwoStageTrigger(int device, DS4State cState, byte tri { triggerData.outputActive = true; - if (triggerRawValue == 255) + if (DS4StateFieldMapping.IsTriggerFullPull(triggerRawValue)) { dcsFullPull = inputFullPull; triggerData.fullPullActActive = true; @@ -3268,7 +3268,7 @@ private static void ProcessTwoStageTrigger(int device, DS4State cState, byte tri else if (triggerData.outputActive) { //DS4State pState = d.getPreviousStateRef(); - if (triggerRawValue == 255 && + if (DS4StateFieldMapping.IsTriggerFullPull(triggerRawValue) && triggerData.actionStateMode == TwoStageTriggerMappingData.EngageButtonsMode.FullPullOnly) { dcsFullPull = inputFullPull; diff --git a/DS4WindowsTests/TriggerFullPullTests.cs b/DS4WindowsTests/TriggerFullPullTests.cs new file mode 100644 index 0000000..ece0fba --- /dev/null +++ b/DS4WindowsTests/TriggerFullPullTests.cs @@ -0,0 +1,54 @@ +/* +DS4Windows +Copyright (C) 2026 Travis Nickles + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +using DS4Windows; + +namespace DS4WindowsTests +{ + [TestClass] + public class TriggerFullPullTests + { + [DataTestMethod] + [DataRow(0, false)] + [DataRow(249, false)] + [DataRow(250, true)] + [DataRow(255, true)] + public void FullPullThresholdAllowsSmallRawInputTolerance(int rawTriggerValue, bool expectedFullPull) + { + Assert.AreEqual(expectedFullPull, DS4StateFieldMapping.IsTriggerFullPull((byte)rawTriggerValue)); + } + + [TestMethod] + public void FieldMappingUsesFullPullThresholdForTriggerButtons() + { + DS4State state = new DS4State + { + L2Raw = DS4StateFieldMapping.TRIGGER_FULL_PULL_THRESHOLD, + R2Raw = DS4StateFieldMapping.TRIGGER_FULL_PULL_THRESHOLD - 1 + }; + + DS4StateFieldMapping mapping = new DS4StateFieldMapping( + state, + new DS4StateExposed(state), + tp: null); + + Assert.IsTrue(mapping.buttons[(int)DS4Controls.L2FullPull]); + Assert.IsFalse(mapping.buttons[(int)DS4Controls.R2FullPull]); + } + } +} From f9afbb00ac847d630a4179352dce91dbe3118eb3 Mon Sep 17 00:00:00 2001 From: strifeforlyfe Date: Sat, 6 Jun 2026 01:00:30 -0500 Subject: [PATCH 02/47] Prioritize Game Bar profiles over auto profiles --- DS4Windows/AutoProfileChecker.cs | 43 +++++- DS4Windows/DS4Control/ControlService.cs | 189 +++++++++++++++++++----- DS4Windows/DS4Forms/MainWindow.xaml.cs | 2 + 3 files changed, 197 insertions(+), 37 deletions(-) diff --git a/DS4Windows/AutoProfileChecker.cs b/DS4Windows/AutoProfileChecker.cs index 02fa51e..24c14ce 100644 --- a/DS4Windows/AutoProfileChecker.cs +++ b/DS4Windows/AutoProfileChecker.cs @@ -67,6 +67,15 @@ public void Process() if (GetTopWindowName(out topProcessName, out topWindowTitle)) { + if (Program.rootHub.IsAnyGameBarProfilePriorityActive() && + IsGameBarForegroundWindow(topProcessName, topWindowTitle)) + { + if (autoProfileDebugLogLevel > 0) + DS4Windows.AppLogger.LogToGui($"DEBUG: Auto-Profile. Game Bar has priority; preserving underlying auto-profile while Game Bar is foreground", false, true); + + return; + } + // Find a profile match based on autoprofile program path and wnd title list. // The same program may set different profiles for each of the controllers, so we need an array of newProfileName[controllerIdx] values. for (int i = 0, pathsLen = profileHolder.AutoProfileColl.Count; i < pathsLen; i++) @@ -122,6 +131,11 @@ public void Process() controllerProfileEntity.ProfileNames[0] : controllerProfileEntity.ProfileNames[j]; if (tempname != string.Empty && tempname != "(none)") { + if (Program.rootHub.TryDeferAutoProfileForGameBar(j, tempname)) + { + continue; + } + if ((Global.useTempProfile[j] && tempname != Global.tempprofilename[j]) || (!Global.useTempProfile[j] && tempname != Global.ProfilePath[j]) || forceLoadProfile) @@ -162,13 +176,21 @@ public void Process() if (turnOffDS4WinApp) { - turnOffTemp = true; - if (App.rootHub.running) + if (Program.rootHub.IsAnyGameBarProfilePriorityActive()) { if (autoProfileDebugLogLevel > 0) - DS4Windows.AppLogger.LogToGui($"DEBUG: Auto-Profile. Turning DS4Windows temporarily off", false, true); + DS4Windows.AppLogger.LogToGui($"DEBUG: Auto-Profile. Turnoff rule deferred while Game Bar has priority", false, true); + } + else + { + turnOffTemp = true; + if (App.rootHub.running) + { + if (autoProfileDebugLogLevel > 0) + DS4Windows.AppLogger.LogToGui($"DEBUG: Auto-Profile. Turning DS4Windows temporarily off", false, true); - SetAndWaitServiceStatus(false); + SetAndWaitServiceStatus(false); + } } } @@ -195,6 +217,11 @@ public void Process() { if (DS4Windows.Global.AutoProfileRevertDefaultProfile) { + if (Program.rootHub.TryDeferAutoProfileDefaultForGameBar(j)) + { + continue; + } + if (autoProfileDebugLogLevel > 0) DS4Windows.AppLogger.LogToGui($"DEBUG: Auto-Profile. Unknown process. Reverting to default profile. Controller {j + 1}={Global.ProfilePath[j]} (default)", false, true); @@ -250,6 +277,14 @@ private AutoProfileEntity SelectProfileEntityForController(List= 0 || + topProcessName.IndexOf("xboxgamingoverlay", StringComparison.OrdinalIgnoreCase) >= 0 || + topWndTitleName.IndexOf("game bar", StringComparison.OrdinalIgnoreCase) >= 0 || + topWndTitleName.IndexOf("xbox game bar", StringComparison.OrdinalIgnoreCase) >= 0; + } + private bool GetTopWindowName(out string topProcessName, out string topWndTitleName) { IntPtr hWnd = GetForegroundWindow(); diff --git a/DS4Windows/DS4Control/ControlService.cs b/DS4Windows/DS4Control/ControlService.cs index 2d9c723..ddbcc1c 100644 --- a/DS4Windows/DS4Control/ControlService.cs +++ b/DS4Windows/DS4Control/ControlService.cs @@ -2653,6 +2653,139 @@ protected void On_DS4Removal(object sender, EventArgs e) private bool gameBarHasDiagnosticVisibleState = false; private bool gameBarAdminWarningLogged = false; + public bool IsGameBarProfilePriorityActive(int ind) + { + return ind >= 0 && ind < MAX_DS4_CONTROLLER_COUNT && + (gameBarProfileActive[ind] || gameBarProfilePending[ind]); + } + + public bool IsAnyGameBarProfilePriorityActive() + { + for (int i = 0; i < MAX_DS4_CONTROLLER_COUNT; i++) + { + if (IsGameBarProfilePriorityActive(i)) + { + return true; + } + } + + return false; + } + + public bool TryDeferAutoProfileForGameBar(int ind, string profileName) + { + if (!IsGameBarProfilePriorityActive(ind)) + { + return false; + } + + bool changed = !gameBarPreviousUseTempProfile[ind] || + gameBarPreviousTempProfileName[ind] != profileName; + + gameBarPreviousUseTempProfile[ind] = true; + gameBarPreviousTempProfileName[ind] = profileName; + if (!string.IsNullOrEmpty(Global.ProfilePath[ind])) + { + gameBarPreviousProfileName[ind] = Global.ProfilePath[ind]; + } + + if (changed) + { + LogDebug($"Controller {ind + 1} deferred auto-profile '{profileName}' while Game Bar has priority."); + } + + return true; + } + + public bool TryDeferAutoProfileDefaultForGameBar(int ind) + { + if (!IsGameBarProfilePriorityActive(ind)) + { + return false; + } + + bool changed = gameBarPreviousUseTempProfile[ind] || + !string.IsNullOrEmpty(gameBarPreviousTempProfileName[ind]); + + gameBarPreviousUseTempProfile[ind] = false; + gameBarPreviousTempProfileName[ind] = string.Empty; + if (!string.IsNullOrEmpty(Global.ProfilePath[ind])) + { + gameBarPreviousProfileName[ind] = Global.ProfilePath[ind]; + } + + if (changed) + { + LogDebug($"Controller {ind + 1} deferred auto-profile default restore while Game Bar has priority."); + } + + return true; + } + + private bool HasAnyConfiguredGameBarProfile() + { + for (int i = 0; i < MAX_DS4_CONTROLLER_COUNT; i++) + { + if (DS4Controllers[i] != null && + Global.GameBarHomeButtonSupport[i] && + !string.IsNullOrEmpty(Global.GameBarProfileName[i])) + { + return true; + } + } + + return false; + } + + private bool TryGetConfiguredGameBarProfileName(int ind, out string profileName, bool logInvalid) + { + profileName = string.Empty; + if (!Global.GameBarHomeButtonSupport[ind]) + { + return false; + } + + profileName = Global.GameBarProfileName[ind]; + if (string.IsNullOrEmpty(profileName)) + { + if (logInvalid) + { + LogDebug($"Game Bar Home button support is enabled for controller {ind + 1}, but no Game Bar profile is selected.", true); + } + + return false; + } + + string profilePath = Path.Combine(appdatapath, "Profiles", $"{profileName}.xml"); + if (!File.Exists(profilePath)) + { + if (logInvalid) + { + LogDebug($"Game Bar profile '{profileName}' does not exist for controller {ind + 1}.", true); + } + + return false; + } + + return true; + } + + private void RequestGameBarProfilePriority(int ind, string profileName, DateTime now, string reason) + { + if (IsGameBarProfilePriorityActive(ind)) + { + return; + } + + gameBarPreviousUseTempProfile[ind] = Global.useTempProfile[ind]; + gameBarPreviousTempProfileName[ind] = Global.tempprofilename[ind]; + gameBarPreviousProfileName[ind] = Global.ProfilePath[ind]; + gameBarRequestedProfileName[ind] = profileName; + gameBarProfileRequestedUtc[ind] = now; + gameBarProfilePending[ind] = true; + LogDebug($"Controller {ind + 1} requested Game Bar profile '{profileName}' ({reason}). Waiting for Game Bar to become visible."); + } + private void CheckGameBarHomeButton(int ind, DS4State cState, DS4State tempControlState, DS4State pState) { if (!cState.PS) @@ -2682,22 +2815,8 @@ private void CheckGameBarHomeButton(int ind, DS4State cState, DS4State tempContr return; } - if (!Global.GameBarHomeButtonSupport[ind]) - { - return; - } - - string profileName = Global.GameBarProfileName[ind]; - if (string.IsNullOrEmpty(profileName)) - { - LogDebug($"Game Bar Home button support is enabled for controller {ind + 1}, but no Game Bar profile is selected.", true); - return; - } - - string profilePath = Path.Combine(appdatapath, "Profiles", $"{profileName}.xml"); - if (!File.Exists(profilePath)) + if (!TryGetConfiguredGameBarProfileName(ind, out string profileName, true)) { - LogDebug($"Game Bar profile '{profileName}' does not exist for controller {ind + 1}.", true); return; } @@ -2710,30 +2829,17 @@ private void CheckGameBarHomeButton(int ind, DS4State cState, DS4State tempContr cState.PS = false; tempControlState.PS = false; gameBarHomeButtonIgnoreUntilUtc[ind] = now + TimeSpan.FromSeconds(1); + RequestGameBarProfilePriority(ind, profileName, now, "Home button request"); LogDebug($"Game Bar open request: {gameBarIntegration.OpenGameBar()}"); - gameBarPreviousUseTempProfile[ind] = Global.useTempProfile[ind]; - gameBarPreviousTempProfileName[ind] = Global.tempprofilename[ind]; - gameBarPreviousProfileName[ind] = Global.ProfilePath[ind]; - gameBarRequestedProfileName[ind] = profileName; - gameBarProfileRequestedUtc[ind] = now; - gameBarProfilePending[ind] = true; - LogDebug($"Controller {ind + 1} requested Game Bar profile '{profileName}'. Waiting for Game Bar to become visible."); LogGameBarDiagnostics("Home button request"); } - private void UpdateGameBarProfileState() + public void UpdateGameBarProfileState() { - bool anyActiveOrPending = false; - for (int i = 0; i < MAX_DS4_CONTROLLER_COUNT; i++) - { - if (gameBarProfileActive[i] || gameBarProfilePending[i]) - { - anyActiveOrPending = true; - break; - } - } + bool anyActiveOrPending = IsAnyGameBarProfilePriorityActive(); + bool anyConfigured = HasAnyConfiguredGameBarProfile(); - if (!anyActiveOrPending) + if (!anyActiveOrPending && !anyConfigured) { return; } @@ -2751,6 +2857,7 @@ private void UpdateGameBarProfileState() { gameBarLastVisibleUtc = now; gameBarInvisibleSinceUtc = DateTime.MinValue; + RequestVisibleGameBarProfiles(now); ActivatePendingGameBarProfiles(now); return; } @@ -2792,6 +2899,22 @@ private void UpdateGameBarProfileState() } } + private void RequestVisibleGameBarProfiles(DateTime now) + { + for (int i = 0; i < MAX_DS4_CONTROLLER_COUNT; i++) + { + if (DS4Controllers[i] == null || IsGameBarProfilePriorityActive(i)) + { + continue; + } + + if (TryGetConfiguredGameBarProfileName(i, out string profileName, false)) + { + RequestGameBarProfilePriority(i, profileName, now, "Game Bar visible"); + } + } + } + private void ActivatePendingGameBarProfiles(DateTime now) { for (int i = 0; i < MAX_DS4_CONTROLLER_COUNT; i++) diff --git a/DS4Windows/DS4Forms/MainWindow.xaml.cs b/DS4Windows/DS4Forms/MainWindow.xaml.cs index 83c77cc..a79bca0 100644 --- a/DS4Windows/DS4Forms/MainWindow.xaml.cs +++ b/DS4Windows/DS4Forms/MainWindow.xaml.cs @@ -845,7 +845,9 @@ private void AutoProfilesTimer_Elapsed(object sender, System.Timers.ElapsedEvent { autoProfilesTimer.Stop(); //Console.WriteLine("Event triggered"); + App.rootHub.UpdateGameBarProfileState(); autoprofileChecker.Process(); + App.rootHub.UpdateGameBarProfileState(); if (autoprofileChecker.Running) { From d19d922cd36df6f8979fda3050e9524a7baad2c2 Mon Sep 17 00:00:00 2001 From: strifeforlyfe Date: Sat, 6 Jun 2026 08:28:50 -0500 Subject: [PATCH 03/47] Quiet Game Bar profile logging --- DS4Windows/AutoProfileChecker.cs | 21 ++----- DS4Windows/DS4Control/ControlService.cs | 83 +++---------------------- 2 files changed, 13 insertions(+), 91 deletions(-) diff --git a/DS4Windows/AutoProfileChecker.cs b/DS4Windows/AutoProfileChecker.cs index 24c14ce..1d2937c 100644 --- a/DS4Windows/AutoProfileChecker.cs +++ b/DS4Windows/AutoProfileChecker.cs @@ -70,9 +70,6 @@ public void Process() if (Program.rootHub.IsAnyGameBarProfilePriorityActive() && IsGameBarForegroundWindow(topProcessName, topWindowTitle)) { - if (autoProfileDebugLogLevel > 0) - DS4Windows.AppLogger.LogToGui($"DEBUG: Auto-Profile. Game Bar has priority; preserving underlying auto-profile while Game Bar is foreground", false, true); - return; } @@ -174,23 +171,15 @@ public void Process() } } - if (turnOffDS4WinApp) + if (turnOffDS4WinApp && !Program.rootHub.IsAnyGameBarProfilePriorityActive()) { - if (Program.rootHub.IsAnyGameBarProfilePriorityActive()) + turnOffTemp = true; + if (App.rootHub.running) { if (autoProfileDebugLogLevel > 0) - DS4Windows.AppLogger.LogToGui($"DEBUG: Auto-Profile. Turnoff rule deferred while Game Bar has priority", false, true); - } - else - { - turnOffTemp = true; - if (App.rootHub.running) - { - if (autoProfileDebugLogLevel > 0) - DS4Windows.AppLogger.LogToGui($"DEBUG: Auto-Profile. Turning DS4Windows temporarily off", false, true); + DS4Windows.AppLogger.LogToGui($"DEBUG: Auto-Profile. Turning DS4Windows temporarily off", false, true); - SetAndWaitServiceStatus(false); - } + SetAndWaitServiceStatus(false); } } diff --git a/DS4Windows/DS4Control/ControlService.cs b/DS4Windows/DS4Control/ControlService.cs index ddbcc1c..7623f2f 100644 --- a/DS4Windows/DS4Control/ControlService.cs +++ b/DS4Windows/DS4Control/ControlService.cs @@ -2648,10 +2648,6 @@ protected void On_DS4Removal(object sender, EventArgs e) private DateTime gameBarLastVisibleUtc = DateTime.MinValue; private DateTime gameBarInvisibleSinceUtc = DateTime.MinValue; private DateTime gameBarLastVisibilityCheckUtc = DateTime.MinValue; - private DateTime gameBarLastDiagnosticLogUtc = DateTime.MinValue; - private bool gameBarLastDiagnosticVisible = false; - private bool gameBarHasDiagnosticVisibleState = false; - private bool gameBarAdminWarningLogged = false; public bool IsGameBarProfilePriorityActive(int ind) { @@ -2679,9 +2675,6 @@ public bool TryDeferAutoProfileForGameBar(int ind, string profileName) return false; } - bool changed = !gameBarPreviousUseTempProfile[ind] || - gameBarPreviousTempProfileName[ind] != profileName; - gameBarPreviousUseTempProfile[ind] = true; gameBarPreviousTempProfileName[ind] = profileName; if (!string.IsNullOrEmpty(Global.ProfilePath[ind])) @@ -2689,11 +2682,6 @@ public bool TryDeferAutoProfileForGameBar(int ind, string profileName) gameBarPreviousProfileName[ind] = Global.ProfilePath[ind]; } - if (changed) - { - LogDebug($"Controller {ind + 1} deferred auto-profile '{profileName}' while Game Bar has priority."); - } - return true; } @@ -2704,9 +2692,6 @@ public bool TryDeferAutoProfileDefaultForGameBar(int ind) return false; } - bool changed = gameBarPreviousUseTempProfile[ind] || - !string.IsNullOrEmpty(gameBarPreviousTempProfileName[ind]); - gameBarPreviousUseTempProfile[ind] = false; gameBarPreviousTempProfileName[ind] = string.Empty; if (!string.IsNullOrEmpty(Global.ProfilePath[ind])) @@ -2714,11 +2699,6 @@ public bool TryDeferAutoProfileDefaultForGameBar(int ind) gameBarPreviousProfileName[ind] = Global.ProfilePath[ind]; } - if (changed) - { - LogDebug($"Controller {ind + 1} deferred auto-profile default restore while Game Bar has priority."); - } - return true; } @@ -2737,7 +2717,7 @@ private bool HasAnyConfiguredGameBarProfile() return false; } - private bool TryGetConfiguredGameBarProfileName(int ind, out string profileName, bool logInvalid) + private bool TryGetConfiguredGameBarProfileName(int ind, out string profileName) { profileName = string.Empty; if (!Global.GameBarHomeButtonSupport[ind]) @@ -2748,29 +2728,19 @@ private bool TryGetConfiguredGameBarProfileName(int ind, out string profileName, profileName = Global.GameBarProfileName[ind]; if (string.IsNullOrEmpty(profileName)) { - if (logInvalid) - { - LogDebug($"Game Bar Home button support is enabled for controller {ind + 1}, but no Game Bar profile is selected.", true); - } - return false; } string profilePath = Path.Combine(appdatapath, "Profiles", $"{profileName}.xml"); if (!File.Exists(profilePath)) { - if (logInvalid) - { - LogDebug($"Game Bar profile '{profileName}' does not exist for controller {ind + 1}.", true); - } - return false; } return true; } - private void RequestGameBarProfilePriority(int ind, string profileName, DateTime now, string reason) + private void RequestGameBarProfilePriority(int ind, string profileName, DateTime now) { if (IsGameBarProfilePriorityActive(ind)) { @@ -2783,7 +2753,6 @@ private void RequestGameBarProfilePriority(int ind, string profileName, DateTime gameBarRequestedProfileName[ind] = profileName; gameBarProfileRequestedUtc[ind] = now; gameBarProfilePending[ind] = true; - LogDebug($"Controller {ind + 1} requested Game Bar profile '{profileName}' ({reason}). Waiting for Game Bar to become visible."); } private void CheckGameBarHomeButton(int ind, DS4State cState, DS4State tempControlState, DS4State pState) @@ -2810,28 +2779,21 @@ private void CheckGameBarHomeButton(int ind, DS4State cState, DS4State tempContr { cState.PS = false; tempControlState.PS = false; - LogDebug($"Game Bar open request: {gameBarIntegration.OpenGameBar()}"); + gameBarIntegration.OpenGameBar(); gameBarHomeButtonIgnoreUntilUtc[ind] = now + TimeSpan.FromSeconds(1); return; } - if (!TryGetConfiguredGameBarProfileName(ind, out string profileName, true)) + if (!TryGetConfiguredGameBarProfileName(ind, out string profileName)) { return; } - if (!gameBarIntegration.IsRunningElevated() && !gameBarAdminWarningLogged) - { - LogDebug("Game Bar support needs DS4Windows to be run as administrator to reliably detect Game Bar overlay windows.", true); - gameBarAdminWarningLogged = true; - } - cState.PS = false; tempControlState.PS = false; gameBarHomeButtonIgnoreUntilUtc[ind] = now + TimeSpan.FromSeconds(1); - RequestGameBarProfilePriority(ind, profileName, now, "Home button request"); - LogDebug($"Game Bar open request: {gameBarIntegration.OpenGameBar()}"); - LogGameBarDiagnostics("Home button request"); + RequestGameBarProfilePriority(ind, profileName, now); + gameBarIntegration.OpenGameBar(); } public void UpdateGameBarProfileState() @@ -2852,7 +2814,6 @@ public void UpdateGameBarProfileState() gameBarLastVisibilityCheckUtc = now; bool gameBarVisible = gameBarIntegration.IsGameBarVisible(); - MaybeLogGameBarDiagnostics(now, gameBarVisible); if (gameBarVisible) { gameBarLastVisibleUtc = now; @@ -2872,7 +2833,6 @@ public void UpdateGameBarProfileState() if (gameBarProfilePending[i] && now - gameBarProfileRequestedUtc[i] > TimeSpan.FromSeconds(6)) { ClearPendingGameBarProfile(i); - LogDebug($"Controller {i + 1} did not switch to Game Bar profile because Game Bar was not detected.", true); } if (!gameBarProfileActive[i]) @@ -2894,7 +2854,6 @@ public void UpdateGameBarProfileState() gameBarPreviousTempProfileName[i] = string.Empty; gameBarPreviousProfileName[i] = string.Empty; gameBarRequestedProfileName[i] = string.Empty; - LogDebug($"Controller {i + 1} reverted from Game Bar profile."); } } } @@ -2908,9 +2867,9 @@ private void RequestVisibleGameBarProfiles(DateTime now) continue; } - if (TryGetConfiguredGameBarProfileName(i, out string profileName, false)) + if (TryGetConfiguredGameBarProfileName(i, out string profileName)) { - RequestGameBarProfilePriority(i, profileName, now, "Game Bar visible"); + RequestGameBarProfilePriority(i, profileName, now); } } } @@ -2929,38 +2888,12 @@ private void ActivatePendingGameBarProfiles(DateTime now) { gameBarProfileActive[i] = true; gameBarProfileActivatedUtc[i] = now; - LogDebug($"Controller {i + 1} switched to Game Bar profile '{profileName}'."); - } - else - { - LogDebug($"Controller {i + 1} could not load Game Bar profile '{profileName}'.", true); } ClearPendingGameBarProfile(i); } } - private void MaybeLogGameBarDiagnostics(DateTime now, bool gameBarVisible) - { - bool changed = !gameBarHasDiagnosticVisibleState || gameBarLastDiagnosticVisible != gameBarVisible; - bool intervalElapsed = now - gameBarLastDiagnosticLogUtc > TimeSpan.FromSeconds(10); - - if (!changed && !intervalElapsed) - { - return; - } - - gameBarLastDiagnosticVisible = gameBarVisible; - gameBarHasDiagnosticVisibleState = true; - gameBarLastDiagnosticLogUtc = now; - LogGameBarDiagnostics(changed ? $"Visibility changed to {gameBarVisible}" : $"Visibility still {gameBarVisible}"); - } - - private void LogGameBarDiagnostics(string reason) - { - LogDebug($"Game Bar diagnostics ({reason}):\n{gameBarIntegration.GetGameBarStateDiagnostics()}"); - } - private void ClearPendingGameBarProfile(int ind) { gameBarProfilePending[ind] = false; From fda967930c0c66aa9d917ff5af9ccefa1cd68dc0 Mon Sep 17 00:00:00 2001 From: strifeforlyfe Date: Sat, 6 Jun 2026 08:35:35 -0500 Subject: [PATCH 04/47] Update fork branding and release checks --- DS4Windows/App.xaml.cs | 2 +- DS4Windows/DS4Control/ScpUtil.cs | 38 +++++++++++++---- DS4Windows/DS4Forms/About.xaml | 2 +- DS4Windows/DS4Forms/About.xaml.cs | 6 +-- .../DS4Forms/ViewModels/LogViewModel.cs | 2 +- .../ViewModels/MainWindowsViewModel.cs | 9 ++-- .../DS4Forms/ViewModels/TrayIconViewModel.cs | 2 +- DS4Windows/DS4WinWPF.csproj | 9 ++-- README.md | 42 ++++--------------- 9 files changed, 55 insertions(+), 57 deletions(-) diff --git a/DS4Windows/App.xaml.cs b/DS4Windows/App.xaml.cs index 93bdbdd..0e13d69 100644 --- a/DS4Windows/App.xaml.cs +++ b/DS4Windows/App.xaml.cs @@ -181,7 +181,7 @@ private void Application_Startup(object sender, StartupEventArgs e) DispatcherUnhandledException += App_DispatcherUnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; Logger logger = logHolder.Logger; - string version = DS4Windows.Global.exeversion; + string version = DS4Windows.Global.exeDisplayVersion; logger.Info($"DS4Windows version {version}"); logger.Info($"DS4Windows exe file: {DS4Windows.Global.exeFileName}"); logger.Info($"DS4Windows Assembly Architecture: {(Environment.Is64BitProcess ? "x64" : "x86")}"); diff --git a/DS4Windows/DS4Control/ScpUtil.cs b/DS4Windows/DS4Control/ScpUtil.cs index 5f4fcca..a63d300 100644 --- a/DS4Windows/DS4Control/ScpUtil.cs +++ b/DS4Windows/DS4Control/ScpUtil.cs @@ -34,6 +34,7 @@ You should have received a copy of the GNU General Public License using System.Runtime.InteropServices; using System.Security.Principal; using System.Text; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -558,6 +559,8 @@ public class Global public static string exeFileName = Path.GetFileName(exelocation); public static FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(exelocation); public static string exeversion = fileVersion.FileVersion; + public static string exeDisplayVersion = string.IsNullOrWhiteSpace(fileVersion.ProductVersion) ? + exeversion : fileVersion.ProductVersion; public static ulong exeversionLong = (ulong)fileVersion.ProductMajorPart << 48 | (ulong)fileVersion.ProductMinorPart << 32 | (ulong)fileVersion.ProductBuildPart << 16; public static ulong fullExeVersionLong = exeversionLong | (ushort)fileVersion.ProductPrivatePart; @@ -3366,12 +3369,21 @@ public static IEnumerable GrabCurrentMonitors() public class Changelog { - public const string GITHUB_RELEASES_API_URI = "https://api.github.com/repos/schmaldeo/DS4Windows/releases"; - public const string GITHUB_LATEST_RELEASE_API_URI = "https://api.github.com/repos/schmaldeo/DS4Windows/releases/latest"; + public const string GITHUB_RELEASES_API_URI = "https://api.github.com/repos/hbashton/DS4Windows/releases"; + public const string GITHUB_LATEST_RELEASE_API_URI = "https://api.github.com/repos/hbashton/DS4Windows/releases/latest"; private static bool? _newerVersionAvailable = null; private static Version _latestVersion; + public static bool TryParseReleaseVersion(string tagName, out Version version) + { + version = Version.Parse("0.0.0"); + if (string.IsNullOrWhiteSpace(tagName)) return false; + + Match versionMatch = Regex.Match(tagName, @"\d+(?:\.\d+){1,3}"); + return versionMatch.Success && Version.TryParse(versionMatch.Value, out version); + } + // Much more compact and elegant way of checking if there is a new update available than the // shenanigans with fetching newest.txt and using a .txt file as a DTO instead of simply // passing a string to the function that displays the updater window. @@ -3390,15 +3402,20 @@ public static bool CheckNewerVersionExists(out Version version, bool allowCached return (bool)_newerVersionAvailable; } - var request = App.requestClient.GetAsync(GITHUB_LATEST_RELEASE_API_URI); + var request = App.requestClient.GetAsync(GITHUB_RELEASES_API_URI); request.Wait(); if (request.Result.IsSuccessStatusCode) { - var task = request.Result.Content.ReadFromJsonAsync(); + var task = request.Result.Content.ReadFromJsonAsync(); task.Wait(); - // if can't parse the newest version - if (!Version.TryParse(task.Result.TagName[1..], out version)) return false; + foreach (var release in task.Result ?? Array.Empty()) + { + if (!TryParseReleaseVersion(release.TagName, out var parsedVersion)) continue; + if (parsedVersion > version) version = parsedVersion; + } + + if (version <= Version.Parse("0.0.0")) return false; // if there is a newer version available if (currentVersion < version) @@ -3423,15 +3440,18 @@ public static async Task> GetChangelog(bool allVersi if (!Version.TryParse(Global.exeversion, out var currentVersion)) return dict; var request = await App.requestClient.GetAsync(GITHUB_RELEASES_API_URI); + if (!request.IsSuccessStatusCode) return dict; + var releases = await request.Content.ReadFromJsonAsync(); + if (releases is null) return dict; foreach (var release in releases) { - if (release.PreRelease) continue; - - if (!Version.TryParse(release.TagName[1..], out var parsedVersion)) continue; + if (!TryParseReleaseVersion(release.TagName, out var parsedVersion)) continue; if (!allVersions && parsedVersion <= currentVersion) break; + if (dict.ContainsKey(parsedVersion)) continue; + dict.Add(parsedVersion, release.Body); } diff --git a/DS4Windows/DS4Forms/About.xaml b/DS4Windows/DS4Forms/About.xaml index ed6484a..acc5b7f 100644 --- a/DS4Windows/DS4Forms/About.xaml +++ b/DS4Windows/DS4Forms/About.xaml @@ -9,7 +9,7 @@ Title="{lex:LocExtension HotkeysAbout}" Height="450" Width="800" Style="{DynamicResource WindowStyle}"> -