Skip to content

Commit f1f16e6

Browse files
authored
Merge pull request #42 from carterscode/feat/debloat-and-update-fix
feat: update-newest fix, Microsoft 365 Copilot removal, Windows 11 Debloat tab
2 parents 81985de + 29ad8fb commit f1f16e6

26 files changed

Lines changed: 2116 additions & 19 deletions

docs/SETTINGS-REFERENCE.md

Lines changed: 416 additions & 0 deletions
Large diffs are not rendered by default.

src/GamerGuardian/App.xaml.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,17 @@ protected override void OnStartup(StartupEventArgs e)
122122
new TailoredExperiencesMonitor(),
123123
new CdpMonitor(),
124124
new ActivityHistoryMonitor(),
125+
new OnlineSpeechMonitor(),
126+
new InkingTypingMonitor(),
127+
// Debloat tab -- ads, nags, suggested content & background bloat:
128+
new SuggestedContentMonitor(),
129+
new LockScreenSpotlightMonitor(),
130+
new FinishSetupNagMonitor(),
131+
new StartRecommendationsMonitor(),
132+
new ExplorerAdsMonitor(),
133+
new FeedbackNagMonitor(),
134+
new WidgetsMonitor(),
135+
new EdgeBackgroundMonitor(),
125136
// System toggles:
126137
new PowerThrottlingMonitor(), // CPU/Power tab
127138
new FastStartupMonitor(), // Global gaming tab

src/GamerGuardian/Models/AppConfig.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,23 @@ public sealed class GlobalPreferences
135135
public ToggleSettingPref Cdp { get; set; } = new() { DesiredOn = true };
136136
public ToggleSettingPref ActivityHistory { get; set; } = new() { DesiredOn = true };
137137

138+
// ---- Privacy data-collection toggles (Privacy tab). Intuitive Enabled/Disabled;
139+
// DesiredOn=feature enabled, so the privacy-optimized default is DesiredOn=false. ----
140+
public ToggleSettingPref OnlineSpeech { get; set; } = new() { DesiredOn = false };
141+
public ToggleSettingPref InkingTyping { get; set; } = new() { DesiredOn = false };
142+
143+
// ---- Debloat toggles (Debloat tab). Intuitive Enabled/Disabled; DesiredOn maps
144+
// to the bloat feature being enabled, so the debloated default is DesiredOn=false.
145+
// Monitor=false by default: zero behavior change until the user opts in. ----
146+
public ToggleSettingPref SuggestedContent { get; set; } = new() { DesiredOn = false };
147+
public ToggleSettingPref LockScreenSpotlight { get; set; } = new() { DesiredOn = false };
148+
public ToggleSettingPref FinishSetupNag { get; set; } = new() { DesiredOn = false };
149+
public ToggleSettingPref StartRecommendations { get; set; } = new() { DesiredOn = false };
150+
public ToggleSettingPref ExplorerAds { get; set; } = new() { DesiredOn = false };
151+
public ToggleSettingPref FeedbackNag { get; set; } = new() { DesiredOn = false };
152+
public ToggleSettingPref Widgets { get; set; } = new() { DesiredOn = false };
153+
public ToggleSettingPref EdgeBackground { get; set; } = new() { DesiredOn = false };
154+
138155
// ---- System toggles (inverted Gaming/Default; DesiredOn=true = gaming) ----
139156
public ToggleSettingPref PowerThrottling { get; set; } = new() { DesiredOn = true };
140157
public ToggleSettingPref FastStartup { get; set; } = new() { DesiredOn = true };
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using GamerGuardian.Models;
2+
using GamerGuardian.Services;
3+
using Microsoft.Win32;
4+
5+
namespace GamerGuardian.Monitors;
6+
7+
/// <summary>
8+
/// Microsoft Edge "startup boost" + "background mode" -- the pair that keeps
9+
/// Edge processes resident at boot and running after every window is closed,
10+
/// costing idle RAM/CPU on a machine where Edge isn't the daily browser. Set via
11+
/// the HKLM Edge enterprise policies (which survive Edge updates, unlike the
12+
/// in-app toggles). Intuitive Enabled/Disabled: <c>DesiredOn</c> = the
13+
/// boost/background behavior enabled; recommended OFF. HKLM write needs elevation.
14+
///
15+
/// <para>This does not block Edge itself -- it still launches on demand and
16+
/// WebView2-dependent apps keep working.</para>
17+
/// </summary>
18+
public sealed class EdgeBackgroundMonitor : IMonitoredSetting
19+
{
20+
public string Id => "debloat.edge";
21+
private const string PolicyKey = @"SOFTWARE\Policies\Microsoft\Edge";
22+
private const string StartupBoost = "StartupBoostEnabled";
23+
private const string BackgroundMode = "BackgroundModeEnabled";
24+
25+
public IEnumerable<DriftItem> CheckDrift(AppConfig config)
26+
{
27+
var pref = config.Global.EdgeBackground;
28+
var current = ReadCurrent();
29+
if (current is null) yield break;
30+
if (current.Value == pref.DesiredOn) yield break;
31+
32+
bool desired = pref.DesiredOn;
33+
yield return new DriftItem(
34+
SettingId: Id,
35+
DisplayKey: "debloat",
36+
DisplayLabel: "Debloat",
37+
Description: "Edge startup boost & background mode",
38+
CurrentValue: current.Value ? "Enabled" : "Disabled",
39+
DesiredValue: desired ? "Enabled" : "Disabled",
40+
AutoApply: pref.AutoApply,
41+
Apply: () => Task.Run(() => Apply(desired)),
42+
IsMonitored: pref.Monitor,
43+
RawBefore: current.Value ? "(default / Edge prelaunch on)" : "StartupBoostEnabled=0, BackgroundModeEnabled=0",
44+
RawDesired: desired ? "(policies deleted / Windows default)" : "StartupBoostEnabled=0, BackgroundModeEnabled=0");
45+
}
46+
47+
/// <summary>True (on) unless the startup-boost policy explicitly disables it.</summary>
48+
public static bool? ReadCurrent()
49+
{
50+
try
51+
{
52+
using var k = Registry.LocalMachine.OpenSubKey(PolicyKey, writable: false);
53+
return (k?.GetValue(StartupBoost) as int?) != 0;
54+
}
55+
catch { return null; }
56+
}
57+
58+
public static void Apply(bool on)
59+
{
60+
if (on)
61+
ElevatedRegistry.DeleteHklmMulti(new[]
62+
{
63+
(PolicyKey, StartupBoost),
64+
(PolicyKey, BackgroundMode),
65+
});
66+
else
67+
ElevatedRegistry.SetHklmMulti(new[]
68+
{
69+
(PolicyKey, StartupBoost, "REG_DWORD", "0"),
70+
(PolicyKey, BackgroundMode, "REG_DWORD", "0"),
71+
});
72+
}
73+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using GamerGuardian.Models;
2+
using Microsoft.Win32;
3+
4+
namespace GamerGuardian.Monitors;
5+
6+
/// <summary>
7+
/// File Explorer "sync provider" notifications -- the OneDrive / Microsoft 365
8+
/// upsell banners that appear in the Explorer navigation pane and status bar.
9+
/// Single per-user Explorer\Advanced DWORD (0 = off). Intuitive Enabled/Disabled:
10+
/// <c>DesiredOn</c> = the banners enabled; recommended OFF.
11+
/// </summary>
12+
public sealed class ExplorerAdsMonitor : IMonitoredSetting
13+
{
14+
public string Id => "debloat.explorerads";
15+
private const string SubKey = @"Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced";
16+
private const string ValueName = "ShowSyncProviderNotifications";
17+
18+
public IEnumerable<DriftItem> CheckDrift(AppConfig config)
19+
{
20+
var pref = config.Global.ExplorerAds;
21+
var current = ReadCurrent();
22+
if (current is null) yield break;
23+
if (current.Value == pref.DesiredOn) yield break;
24+
25+
bool desired = pref.DesiredOn;
26+
yield return new DriftItem(
27+
SettingId: Id,
28+
DisplayKey: "debloat",
29+
DisplayLabel: "Debloat",
30+
Description: "File Explorer OneDrive / Office ad banners",
31+
CurrentValue: current.Value ? "Enabled" : "Disabled",
32+
DesiredValue: desired ? "Enabled" : "Disabled",
33+
AutoApply: pref.AutoApply,
34+
Apply: () => Task.Run(() => Apply(desired)),
35+
IsMonitored: pref.Monitor,
36+
RawBefore: current.Value ? "(default / banners on)" : "ShowSyncProviderNotifications=0",
37+
RawDesired: desired ? "(deleted / Windows default)" : "ShowSyncProviderNotifications=0");
38+
}
39+
40+
/// <summary>True (on) unless the value is explicitly 0. Absent = Windows default on.</summary>
41+
public static bool? ReadCurrent()
42+
{
43+
try
44+
{
45+
using var k = Registry.CurrentUser.OpenSubKey(SubKey, writable: false);
46+
return (k?.GetValue(ValueName) as int?) != 0;
47+
}
48+
catch { return null; }
49+
}
50+
51+
public static void Apply(bool on)
52+
{
53+
try
54+
{
55+
if (on)
56+
{
57+
using var k = Registry.CurrentUser.OpenSubKey(SubKey, writable: true);
58+
k?.DeleteValue(ValueName, throwOnMissingValue: false);
59+
}
60+
else
61+
{
62+
using var k = Registry.CurrentUser.CreateSubKey(SubKey, writable: true)!;
63+
k.SetValue(ValueName, 0, RegistryValueKind.DWord);
64+
}
65+
}
66+
catch { }
67+
}
68+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using GamerGuardian.Models;
2+
using Microsoft.Win32;
3+
4+
namespace GamerGuardian.Monitors;
5+
6+
/// <summary>
7+
/// Windows Feedback request frequency -- the periodic "rate your experience"
8+
/// dialogs the OS pops (and which can fire often on fresh installs). Controlled
9+
/// by the per-user Siuf\Rules\NumberOfSIUFInPeriod DWORD; 0 = never ask. We also
10+
/// remove PeriodInNanoSeconds, whose presence overrides the count. Intuitive
11+
/// Enabled/Disabled: <c>DesiredOn</c> = feedback prompts enabled; recommended OFF.
12+
/// </summary>
13+
public sealed class FeedbackNagMonitor : IMonitoredSetting
14+
{
15+
public string Id => "debloat.feedback";
16+
private const string SubKey = @"Software\Microsoft\Siuf\Rules";
17+
private const string CountVal = "NumberOfSIUFInPeriod";
18+
private const string PeriodVal = "PeriodInNanoSeconds";
19+
20+
public IEnumerable<DriftItem> CheckDrift(AppConfig config)
21+
{
22+
var pref = config.Global.FeedbackNag;
23+
var current = ReadCurrent();
24+
if (current is null) yield break;
25+
if (current.Value == pref.DesiredOn) yield break;
26+
27+
bool desired = pref.DesiredOn;
28+
yield return new DriftItem(
29+
SettingId: Id,
30+
DisplayKey: "debloat",
31+
DisplayLabel: "Debloat",
32+
Description: "Windows feedback request popups",
33+
CurrentValue: current.Value ? "Enabled" : "Disabled",
34+
DesiredValue: desired ? "Enabled" : "Disabled",
35+
AutoApply: pref.AutoApply,
36+
Apply: () => Task.Run(() => Apply(desired)),
37+
IsMonitored: pref.Monitor,
38+
RawBefore: current.Value ? "(default / Windows asks for feedback)" : "NumberOfSIUFInPeriod=0",
39+
RawDesired: desired ? "(deleted / Windows default)" : "NumberOfSIUFInPeriod=0 (PeriodInNanoSeconds removed)");
40+
}
41+
42+
/// <summary>True (on) unless the count is explicitly 0.</summary>
43+
public static bool? ReadCurrent()
44+
{
45+
try
46+
{
47+
using var k = Registry.CurrentUser.OpenSubKey(SubKey, writable: false);
48+
return (k?.GetValue(CountVal) as int?) != 0;
49+
}
50+
catch { return null; }
51+
}
52+
53+
public static void Apply(bool on)
54+
{
55+
try
56+
{
57+
if (on)
58+
{
59+
using var k = Registry.CurrentUser.OpenSubKey(SubKey, writable: true);
60+
k?.DeleteValue(CountVal, throwOnMissingValue: false);
61+
}
62+
else
63+
{
64+
using var k = Registry.CurrentUser.CreateSubKey(SubKey, writable: true)!;
65+
k.SetValue(CountVal, 0, RegistryValueKind.DWord);
66+
k.DeleteValue(PeriodVal, throwOnMissingValue: false);
67+
}
68+
}
69+
catch { }
70+
}
71+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using GamerGuardian.Models;
2+
using Microsoft.Win32;
3+
4+
namespace GamerGuardian.Monitors;
5+
6+
/// <summary>
7+
/// The "Let's finish setting up your device" / SCOOBE full-screen and
8+
/// notification nags that prompt to set up OneDrive, a Microsoft account, or a
9+
/// Microsoft 365 subscription -- and resurface after feature updates. Driven by
10+
/// the per-user UserProfileEngagement flag plus the device-setup notification
11+
/// under ContentDeliveryManager. Intuitive Enabled/Disabled: <c>DesiredOn</c> =
12+
/// the nag enabled; recommended OFF.
13+
/// </summary>
14+
public sealed class FinishSetupNagMonitor : IMonitoredSetting
15+
{
16+
public string Id => "debloat.finishsetup";
17+
private const string EngagementKey = @"Software\Microsoft\Windows\CurrentVersion\UserProfileEngagement";
18+
private const string EngagementVal = "ScoobeSystemSettingEnabled";
19+
private const string CdmKey = @"Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager";
20+
private const string CdmVal = "SubscribedContent-310093Enabled"; // device-setup "finish setup" notifications
21+
22+
public IEnumerable<DriftItem> CheckDrift(AppConfig config)
23+
{
24+
var pref = config.Global.FinishSetupNag;
25+
var current = ReadCurrent();
26+
if (current is null) yield break;
27+
if (current.Value == pref.DesiredOn) yield break;
28+
29+
bool desired = pref.DesiredOn;
30+
yield return new DriftItem(
31+
SettingId: Id,
32+
DisplayKey: "debloat",
33+
DisplayLabel: "Debloat",
34+
Description: "\"Finish setting up your device\" nag",
35+
CurrentValue: current.Value ? "Enabled" : "Disabled",
36+
DesiredValue: desired ? "Enabled" : "Disabled",
37+
AutoApply: pref.AutoApply,
38+
Apply: () => Task.Run(() => Apply(desired)),
39+
IsMonitored: pref.Monitor,
40+
RawBefore: current.Value ? "(default / nag on)" : "ScoobeSystemSettingEnabled=0, SubscribedContent-310093Enabled=0",
41+
RawDesired: desired ? "(deleted / Windows default)" : "ScoobeSystemSettingEnabled=0, SubscribedContent-310093Enabled=0");
42+
}
43+
44+
/// <summary>True (on) unless both nag flags are explicitly 0. Absent values
45+
/// count as on (the SCOOBE default), so the toggle applies on a fresh machine.</summary>
46+
public static bool? ReadCurrent()
47+
{
48+
try
49+
{
50+
using var e = Registry.CurrentUser.OpenSubKey(EngagementKey, writable: false);
51+
if ((e?.GetValue(EngagementVal) as int?) != 0) return true;
52+
using var c = Registry.CurrentUser.OpenSubKey(CdmKey, writable: false);
53+
if ((c?.GetValue(CdmVal) as int?) != 0) return true;
54+
return false;
55+
}
56+
catch { return null; }
57+
}
58+
59+
public static void Apply(bool on)
60+
{
61+
try
62+
{
63+
if (on)
64+
{
65+
using (var e = Registry.CurrentUser.OpenSubKey(EngagementKey, writable: true))
66+
e?.DeleteValue(EngagementVal, throwOnMissingValue: false);
67+
using (var c = Registry.CurrentUser.OpenSubKey(CdmKey, writable: true))
68+
c?.DeleteValue(CdmVal, throwOnMissingValue: false);
69+
}
70+
else
71+
{
72+
using (var e = Registry.CurrentUser.CreateSubKey(EngagementKey, writable: true)!)
73+
e.SetValue(EngagementVal, 0, RegistryValueKind.DWord);
74+
using (var c = Registry.CurrentUser.CreateSubKey(CdmKey, writable: true)!)
75+
c.SetValue(CdmVal, 0, RegistryValueKind.DWord);
76+
}
77+
}
78+
catch { }
79+
}
80+
}

0 commit comments

Comments
 (0)