From c077cc46f18e95cb14652bd88ba1729afee7674a Mon Sep 17 00:00:00 2001 From: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:21:47 -0500 Subject: [PATCH] Adding telemetry events for Light Switch --- DATA_AND_PRIVACY.md | 24 +++++++++ LightSwitchActionsUpdated.cs | 36 +++++++++++++ LightSwitchModeUpdated.cs | 30 +++++++++++ LightSwitchScheduleToggled.cs | 30 +++++++++++ LightSwitchShortcutInvoked.cs | 36 +++++++++++++ .../LightSwitchModuleInterface/dllmain.cpp | 6 +++ .../LightSwitchSettings.cpp | 12 +++++ .../LightSwitch/LightSwitchService/trace.cpp | 54 +++++++++++++++++++ .../LightSwitch/LightSwitchService/trace.h | 17 ++++++ 9 files changed, 245 insertions(+) create mode 100644 LightSwitchActionsUpdated.cs create mode 100644 LightSwitchModeUpdated.cs create mode 100644 LightSwitchScheduleToggled.cs create mode 100644 LightSwitchShortcutInvoked.cs create mode 100644 src/modules/LightSwitch/LightSwitchService/trace.cpp create mode 100644 src/modules/LightSwitch/LightSwitchService/trace.h diff --git a/DATA_AND_PRIVACY.md b/DATA_AND_PRIVACY.md index 8aba94f12f..7c310e03f0 100644 --- a/DATA_AND_PRIVACY.md +++ b/DATA_AND_PRIVACY.md @@ -681,6 +681,30 @@ _If you want to find diagnostic data events in the source code, these two links +### Light Switch + + + + + + + + + + + + + + + + + + + + + +
Event NameDescription
Microsoft.PowerToys.LightSwitch_EnableLightSwitchTriggered when Light Switch is enabled or disabled.
Microsoft.PowerToys.LightSwitch_ShortcutInvokedOccurs when the shortcut for Light Switch is invoked.
Microsoft.PowerToys.LightSwitch_ScheduleModeToggledOccurs when a new schedule mode is selected for Light Switch.
Microsoft.PowerToys.LightSwitch_ThemeTargetChangedOccurs when a the options for targeting the system or apps is updated.
+ ### Mouse Highlighter diff --git a/LightSwitchActionsUpdated.cs b/LightSwitchActionsUpdated.cs new file mode 100644 index 0000000000..85b4e83546 --- /dev/null +++ b/LightSwitchActionsUpdated.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +/// +/// Tracks which actions the users are using to apply theme changes +/// Purpose: Identify which parts of the OS it is important for users to control. +/// +[EventData] +[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] +public class LightSwitchActionsUpdated : EventBase, IEvent +{ + /// + /// Gets or sets whether the user is changing their app theme. + /// + public bool ChangeApps { get; set; } + + /// + /// Gets or sets whether the user is changing their system theme. + /// + public bool ChangeSystem { get; set; } + + public LightSwitchActionsUpdated(bool, ChangeApps, bool ChangeSystem) + { + EventName = "LightSwitch_ModeUpdated"; + ChangeApps = changeApps; + ChangeSystem = changeSystem + } + + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; +} diff --git a/LightSwitchModeUpdated.cs b/LightSwitchModeUpdated.cs new file mode 100644 index 0000000000..2cd19a304c --- /dev/null +++ b/LightSwitchModeUpdated.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +/// +/// Tracks which mode users are using to schedule theme changes +/// Purpose: Identify which modes users are using the most. +/// +[EventData] +[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] +public class LightSwitchModeUpdated : EventBase, IEvent +{ + /// + /// Gets or sets the mode the user is using. + /// + public string Mode { get; set; } + + public LightSwitchModeUpdated(bool mode) + { + EventName = "LightSwitch_ModeUpdated"; + Mode = mode; + } + + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; +} diff --git a/LightSwitchScheduleToggled.cs b/LightSwitchScheduleToggled.cs new file mode 100644 index 0000000000..42531224f3 --- /dev/null +++ b/LightSwitchScheduleToggled.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +/// +/// Tracks if users are using the schedule to control their themeing. +/// Purpose: Identify how users are using Light Switch to control their theme. +/// +[EventData] +[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] +public class LightSwitchScheduleToggled : EventBase, IEvent +{ + /// + /// Gets or sets whether the schedule is on or off. + /// + public bool OnOrOff { get; set; } + + public LightSwitchScheduleToggled(bool onOrOff) + { + EventName = "LightSwitch_ScheduleToggled"; + OnOrOff = onOrOff; + } + + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; +} diff --git a/LightSwitchShortcutInvoked.cs b/LightSwitchShortcutInvoked.cs new file mode 100644 index 0000000000..221984d8cf --- /dev/null +++ b/LightSwitchShortcutInvoked.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +/// +/// Tracks shortcut usage and which mode are we toggling from and to. +/// Purpose: Identify how users are using the shortcut in their workflows. +/// +[EventData] +[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] +public class LightSwitchShortcutInvoked : EventBase, IEvent +{ + /// + /// Gets or sets the target the mode the user is switching to + /// + public string TargetMode { get; set; } + + /// + /// Gets or sets the time of day the user is using this command + /// + public int MinuteOfDay { get; set; } + + public LightSwitchShortcutInvoked(string targetMode, int minuteOfDay) + { + EventName = "LightSwitch_ShortcutInvoked"; + TargetMode = targetMode; + MinuteOfDay = minuteOfDay; + } + + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; +} diff --git a/src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp b/src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp index a5973a396f..74caa5d0c9 100644 --- a/src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp +++ b/src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp @@ -8,6 +8,7 @@ #include #include #include "ThemeHelper.h" +#include extern "C" IMAGE_DOS_HEADER __ImageBase; @@ -394,6 +395,7 @@ public: { m_enabled = true; Logger::info(L"Enabling Light Switch module..."); + Trace::LightSwitch::Enable(true); unsigned long powertoys_pid = GetCurrentProcessId(); std::wstring args = L"--pid " + std::to_wstring(powertoys_pid); @@ -469,6 +471,7 @@ public: CloseHandle(m_process); m_process = nullptr; } + Trace::LightSwitch::Enable(false); } // Returns if the powertoys is enabled @@ -524,6 +527,8 @@ public: if (m_enabled) { Logger::trace(L"Light Switch hotkey pressed"); + Trace::LightSwitch::ShortcutInvoked(); + if (!is_process_running()) { enable(); @@ -541,6 +546,7 @@ public: SetAppsTheme(!GetCurrentAppsTheme()); } + if (!m_manual_override_event_handle) { m_manual_override_event_handle = OpenEventW(SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, L"POWERTOYS_LIGHTSWITCH_MANUAL_OVERRIDE"); diff --git a/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.cpp b/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.cpp index 5221a197fe..488142b95b 100644 --- a/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.cpp +++ b/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using namespace std; @@ -151,6 +152,7 @@ void LightSwitchSettings::LoadSettings() if (m_settings.scheduleMode != newMode) { m_settings.scheduleMode = newMode; + Trace::LightSwitch::ScheduleModeToggled(val); NotifyObservers(SettingId::ScheduleMode); } } @@ -220,6 +222,8 @@ void LightSwitchSettings::LoadSettings() } } + bool themeTargetChanged = false; + // ChangeSystem if (const auto jsonVal = values.get_bool_value(L"changeSystem")) { @@ -227,6 +231,7 @@ void LightSwitchSettings::LoadSettings() if (m_settings.changeSystem != val) { m_settings.changeSystem = val; + themeTargetChanged = true; NotifyObservers(SettingId::ChangeSystem); } } @@ -238,9 +243,16 @@ void LightSwitchSettings::LoadSettings() if (m_settings.changeApps != val) { m_settings.changeApps = val; + themeTargetChanged = true; NotifyObservers(SettingId::ChangeApps); } } + + // For ChangeSystem/ChangeApps changes, log telemetry + if (themeTargetChanged) + { + Trace::LightSwitch::ThemeTargetChanged(m_settings.changeApps, m_settings.changeSystem); + } } catch (...) { diff --git a/src/modules/LightSwitch/LightSwitchService/trace.cpp b/src/modules/LightSwitch/LightSwitchService/trace.cpp new file mode 100644 index 0000000000..e65d1d969d --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchService/trace.cpp @@ -0,0 +1,54 @@ +#include "pch.h" +#include "trace.h" + +#include + +// Telemetry strings should not be localized. +#define LoggingProviderKey "Microsoft.PowerToys" + +TRACELOGGING_DEFINE_PROVIDER( + g_hProvider, + LoggingProviderKey, + // {38e8889b-9731-53f5-e901-e8a7c1753074} + (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74), + TraceLoggingOptionProjectTelemetry()); + +void Trace::LightSwitch::Enable(bool enabled) noexcept +{ + TraceLoggingWriteWrapper( + g_hProvider, + "LightSwitch_EnableLightSwitch", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE), + TraceLoggingBoolean(enabled, "Enabled")); +} + +void Trace::LightSwitch::ShortcutInvoked() noexcept +{ + TraceLoggingWriteWrapper( + g_hProvider, + "LightSwitch_ShortcutInvoked", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); +} + +void Trace::LightSwitch::ScheduleModeToggled(const std::wstring& newMode) noexcept +{ + TraceLoggingWriteWrapper( + g_hProvider, + "LightSwitch_ScheduleModeToggled", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE), + TraceLoggingWideString(newMode.c_str(), "NewMode")); +} + +void Trace::LightSwitch::ThemeTargetChanged(bool changeApps, bool changeSystem) noexcept +{ + TraceLoggingWriteWrapper( + g_hProvider, + "LightSwitch_ThemeTargetChanged", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE), + TraceLoggingBoolean(changeApps, "ChangeApps"), + TraceLoggingBoolean(changeSystem, "ChangeSystem")); +} \ No newline at end of file diff --git a/src/modules/LightSwitch/LightSwitchService/trace.h b/src/modules/LightSwitch/LightSwitchService/trace.h new file mode 100644 index 0000000000..fb951d3da1 --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchService/trace.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +class Trace +{ +public: + class LightSwitch : public telemetry::TraceBase + { + public: + static void Enable(bool enabled) noexcept; + static void ShortcutInvoked() noexcept; + static void ScheduleModeToggled(const std::wstring& newMode) noexcept; + static void ThemeTargetChanged(bool changeApps, bool changeSystem) noexcept; + }; +};