Compare commits

..

2 Commits

Author SHA1 Message Date
Leilei Zhang
e17116964b remove unuse 2025-06-20 16:14:22 +08:00
Leilei Zhang
14c9a40bfa apps 2025-06-20 16:07:54 +08:00
41 changed files with 222 additions and 452 deletions

View File

@@ -22,7 +22,6 @@
"CalculatorEngineCommon.dll",
"PowerToys.ManagedTelemetry.dll",
"PowerToys.ManagedCommon.dll",
"PowerToys.ManagedCsWin32.dll",
"PowerToys.Common.UI.dll",
"PowerToys.Settings.UI.Lib.dll",
"PowerToys.GPOWrapper.dll",

View File

@@ -9,7 +9,6 @@ Param(
$DirPath = $targetDir; #this file is in pipeline, we need root.
$items = Get-ChildItem -Path $DirPath -File -Include *.exe, *.dll, *.ttf, PTCustomActions -Recurse -Force -ErrorAction SilentlyContinue
$versionExceptions = @(
"AdaptiveCards.Templating.dll",
"Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll",
"Microsoft.Windows.ApplicationModel.Resources.Projection.dll",
"Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll",

View File

@@ -22,7 +22,16 @@ namespace ManagedCommon
private static readonly string Debug = "Debug";
private static readonly string TraceFlag = "Trace";
private static readonly string Version = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? "Unknown";
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
/*
* Please pay more attention!
* If you want to publish it with Native AOT enabled (or publish as a single file).
* You need to find another way to remove Assembly.Location usage.
*/
#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
private static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location).ProductVersion;
#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
/// <summary>
/// Initializes the logger and sets the path for logging.

View File

@@ -4,7 +4,6 @@
#include "pch.h"
#include "MouseHighlighter.h"
#include "trace.h"
#include <cmath>
#ifdef COMPOSITION
namespace winrt
@@ -44,7 +43,7 @@ private:
void AddDrawingPoint(MouseButton button);
void UpdateDrawingPointPosition(MouseButton button);
void StartDrawingPointFading(MouseButton button);
void ClearDrawingPoint();
void ClearDrawingPoint(MouseButton button);
void ClearDrawing();
void BringToFront();
HHOOK m_mouseHook = NULL;
@@ -67,12 +66,10 @@ private:
winrt::CompositionSpriteShape m_leftPointer{ nullptr };
winrt::CompositionSpriteShape m_rightPointer{ nullptr };
winrt::CompositionSpriteShape m_alwaysPointer{ nullptr };
winrt::CompositionSpriteShape m_spotlightPointer{ nullptr };
bool m_leftPointerEnabled = true;
bool m_rightPointerEnabled = true;
bool m_alwaysPointerEnabled = true;
bool m_spotlightMode = false;
bool m_leftButtonPressed = false;
bool m_rightButtonPressed = false;
@@ -98,7 +95,8 @@ bool Highlighter::CreateHighlighter()
try
{
// We need a dispatcher queue.
DispatcherQueueOptions options = {
DispatcherQueueOptions options =
{
sizeof(options),
DQTYPE_THREAD_CURRENT,
DQTAT_COM_ASTA,
@@ -124,8 +122,7 @@ bool Highlighter::CreateHighlighter()
m_root.Children().InsertAtTop(m_shape);
return true;
}
catch (...)
} catch (...)
{
return false;
}
@@ -133,9 +130,6 @@ bool Highlighter::CreateHighlighter()
void Highlighter::AddDrawingPoint(MouseButton button)
{
if (!m_compositor)
return;
POINT pt;
// Applies DPIs.
@@ -147,7 +141,6 @@ void Highlighter::AddDrawingPoint(MouseButton button)
// Create circle and add it.
auto circleGeometry = m_compositor.CreateEllipseGeometry();
circleGeometry.Radius({ m_radius, m_radius });
auto circleShape = m_compositor.CreateSpriteShape(circleGeometry);
circleShape.Offset({ static_cast<float>(pt.x), static_cast<float>(pt.y) });
if (button == MouseButton::Left)
@@ -163,22 +156,9 @@ void Highlighter::AddDrawingPoint(MouseButton button)
else
{
// always
if (m_spotlightMode)
{
float borderThickness = static_cast<float>(std::hypot(GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)));
circleGeometry.Radius({ static_cast<float>(borderThickness / 2.0 + m_radius), static_cast<float>(borderThickness / 2.0 + m_radius) });
circleShape.FillBrush(nullptr);
circleShape.StrokeBrush(m_compositor.CreateColorBrush(m_alwaysColor));
circleShape.StrokeThickness(borderThickness);
m_spotlightPointer = circleShape;
}
else
{
circleShape.FillBrush(m_compositor.CreateColorBrush(m_alwaysColor));
m_alwaysPointer = circleShape;
}
circleShape.FillBrush(m_compositor.CreateColorBrush(m_alwaysColor));
m_alwaysPointer = circleShape;
}
m_shape.Shapes().Append(circleShape);
// TODO: We're leaking shapes for long drawing sessions.
@@ -210,20 +190,7 @@ void Highlighter::UpdateDrawingPointPosition(MouseButton button)
else
{
// always
if (m_spotlightMode)
{
if (m_spotlightPointer)
{
m_spotlightPointer.Offset({ static_cast<float>(pt.x), static_cast<float>(pt.y) });
}
}
else
{
if (m_alwaysPointer)
{
m_alwaysPointer.Offset({ static_cast<float>(pt.x), static_cast<float>(pt.y) });
}
}
m_alwaysPointer.Offset({ static_cast<float>(pt.x), static_cast<float>(pt.y) });
}
}
void Highlighter::StartDrawingPointFading(MouseButton button)
@@ -262,22 +229,20 @@ void Highlighter::StartDrawingPointFading(MouseButton button)
circleShape.FillBrush().StartAnimation(L"Color", animation);
}
void Highlighter::ClearDrawingPoint()
void Highlighter::ClearDrawingPoint(MouseButton _button)
{
if (m_spotlightMode)
winrt::Windows::UI::Composition::CompositionSpriteShape circleShape{ nullptr };
if (nullptr == m_alwaysPointer)
{
if (m_spotlightPointer)
{
m_spotlightPointer.StrokeBrush().as<winrt::Windows::UI::Composition::CompositionColorBrush>().Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
}
}
else
{
if (m_alwaysPointer)
{
m_alwaysPointer.FillBrush().as<winrt::Windows::UI::Composition::CompositionColorBrush>().Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
}
// Guard against alwaysPointer not being initialized.
return;
}
// always
circleShape = m_alwaysPointer;
circleShape.FillBrush().as<winrt::Windows::UI::Composition::CompositionColorBrush>().Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
}
void Highlighter::ClearDrawing()
@@ -304,14 +269,13 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa
if (instance->m_alwaysPointerEnabled && !instance->m_rightButtonPressed)
{
// Clear AlwaysPointer only when it's enabled and RightPointer is not active
instance->ClearDrawingPoint();
instance->ClearDrawingPoint(MouseButton::None);
}
if (instance->m_leftButtonPressed)
{
// There might be a stray point from the user releasing the mouse button on an elevated window, which wasn't caught by us.
instance->StartDrawingPointFading(MouseButton::Left);
}
instance->AddDrawingPoint(MouseButton::Left);
instance->m_leftButtonPressed = true;
// start a timer for the scenario, when the user clicks a pinned window which has no focus.
@@ -329,7 +293,7 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa
if (instance->m_alwaysPointerEnabled && !instance->m_leftButtonPressed)
{
// Clear AlwaysPointer only when it's enabled and LeftPointer is not active
instance->ClearDrawingPoint();
instance->ClearDrawingPoint(MouseButton::None);
}
if (instance->m_rightButtonPressed)
{
@@ -394,21 +358,13 @@ void Highlighter::StartDrawing()
{
Logger::info("Starting draw mode.");
Trace::StartHighlightingSession();
if (m_spotlightMode && m_alwaysColor.A != 0)
{
Trace::StartSpotlightSession();
}
m_visible = true;
// HACK: Draw with 1 pixel off. Otherwise Windows glitches the task bar transparency when a transparent window fill the whole screen.
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN) + 1, GetSystemMetrics(SM_YVIRTUALSCREEN) + 1, GetSystemMetrics(SM_CXVIRTUALSCREEN) - 2, GetSystemMetrics(SM_CYVIRTUALSCREEN) - 2, 0);
ClearDrawing();
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
instance->AddDrawingPoint(Highlighter::MouseButton::None);
instance->AddDrawingPoint(MouseButton::None);
m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0);
}
@@ -421,7 +377,6 @@ void Highlighter::StopDrawing()
m_leftPointer = nullptr;
m_rightPointer = nullptr;
m_alwaysPointer = nullptr;
m_spotlightPointer = nullptr;
ShowWindow(m_hwnd, SW_HIDE);
UnhookWindowsHookEx(m_mouseHook);
ClearDrawing();
@@ -433,8 +388,7 @@ void Highlighter::SwitchActivationMode()
PostMessage(m_hwnd, WM_SWITCH_ACTIVATION_MODE, 0, 0);
}
void Highlighter::ApplySettings(MouseHighlighterSettings settings)
{
void Highlighter::ApplySettings(MouseHighlighterSettings settings) {
m_radius = static_cast<float>(settings.radius);
m_fadeDelay_ms = settings.fadeDelayMs;
m_fadeDuration_ms = settings.fadeDurationMs;
@@ -444,23 +398,9 @@ void Highlighter::ApplySettings(MouseHighlighterSettings settings)
m_leftPointerEnabled = settings.leftButtonColor.A != 0;
m_rightPointerEnabled = settings.rightButtonColor.A != 0;
m_alwaysPointerEnabled = settings.alwaysColor.A != 0;
m_spotlightMode = settings.spotlightMode && settings.alwaysColor.A != 0;
if (m_spotlightMode)
{
m_leftPointerEnabled = false;
m_rightPointerEnabled = false;
}
if (instance->m_visible)
{
instance->StopDrawing();
instance->StartDrawing();
}
}
void Highlighter::BringToFront()
{
void Highlighter::BringToFront() {
// HACK: Draw with 1 pixel off. Otherwise Windows glitches the task bar transparency when a transparent window fill the whole screen.
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN) + 1, GetSystemMetrics(SM_YVIRTUALSCREEN) + 1, GetSystemMetrics(SM_CXVIRTUALSCREEN) - 2, GetSystemMetrics(SM_CYVIRTUALSCREEN) - 2, 0);
}
@@ -548,7 +488,8 @@ bool Highlighter::MyRegisterClass(HINSTANCE hInstance)
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hInstance, nullptr);
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOOLWINDOW;
return CreateWindowExW(exStyle, m_className, m_windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hInstance, nullptr) != nullptr;
return CreateWindowExW(exStyle, m_className, m_windowTitle, WS_POPUP,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hInstance, nullptr) != nullptr;
}
void Highlighter::Terminate()

View File

@@ -18,7 +18,6 @@ struct MouseHighlighterSettings
int fadeDelayMs = MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS;
int fadeDurationMs = MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS;
bool autoActivate = MOUSE_HIGHLIGHTER_DEFAULT_AUTO_ACTIVATE;
bool spotlightMode = false;
};
int MouseHighlighterMain(HINSTANCE hinst, MouseHighlighterSettings settings);

View File

@@ -18,7 +18,6 @@ namespace
const wchar_t JSON_KEY_HIGHLIGHT_FADE_DELAY_MS[] = L"highlight_fade_delay_ms";
const wchar_t JSON_KEY_HIGHLIGHT_FADE_DURATION_MS[] = L"highlight_fade_duration_ms";
const wchar_t JSON_KEY_AUTO_ACTIVATE[] = L"auto_activate";
const wchar_t JSON_KEY_SPOTLIGHT_MODE[] = L"spotlight_mode";
}
extern "C" IMAGE_DOS_HEADER __ImageBase;
@@ -368,16 +367,6 @@ public:
{
Logger::warn("Failed to initialize auto activate from settings. Will use default value");
}
try
{
// Parse spotlight mode
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_MODE);
highlightSettings.spotlightMode = jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE);
}
catch (...)
{
Logger::warn("Failed to initialize spotlight mode settings. Will use default value");
}
}
else
{

View File

@@ -30,13 +30,3 @@ void Trace::StartHighlightingSession() noexcept
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}
// Log that spotlight mode is enabled
void Trace::StartSpotlightSession() noexcept
{
TraceLoggingWriteWrapper(
g_hProvider,
"MouseHighlighter_StartSpotlightSession",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}

View File

@@ -10,7 +10,4 @@ public:
// Log that the user activated the module by starting a highlighting session
static void StartHighlightingSession() noexcept;
// Log that spotlight mode is enabled
static void StartSpotlightSession() noexcept;
};

View File

@@ -155,7 +155,6 @@ public partial class CommandBarViewModel : ObservableObject,
ContextMenuStack.Add(new ContextMenuStackViewModel(command));
OnPropertyChanging(nameof(ContextMenu));
OnPropertyChanged(nameof(ContextMenu));
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(command.Command.Model, command.Model));
return ContextKeybindingResult.KeepOpen;
}
else

View File

@@ -2,7 +2,6 @@
// 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;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.UI.ViewModels.BuiltinCommands;
@@ -21,7 +20,7 @@ internal sealed partial class FallbackReloadItem : FallbackCommandItem
public override void UpdateQuery(string query)
{
_reloadCommand.Name = query.StartsWith("r", StringComparison.OrdinalIgnoreCase) ? "Reload" : string.Empty;
_reloadCommand.Name = query.StartsWith('r') ? "Reload" : string.Empty;
Title = _reloadCommand.Name;
}
}

View File

@@ -121,7 +121,7 @@ public class ExtensionWrapper : IExtensionWrapper
if (hr.Value == -2147024893)
{
Logger.LogError($"Failed to find {ExtensionDisplayName}: {hr}. It may have been uninstalled or deleted.");
Logger.LogDebug($"Failed to find {ExtensionDisplayName}: {hr}. It may have been uninstalled or deleted.");
// We don't really need to throw this exception.
// We'll just return out nothing.

View File

@@ -29,30 +29,8 @@ public partial class ShellViewModel(IServiceProvider _serviceProvider, TaskSched
[ObservableProperty]
public partial bool IsDetailsVisible { get; set; }
private PageViewModel _currentPage = new LoadingPageViewModel(null, _scheduler);
public PageViewModel CurrentPage
{
get => _currentPage;
set
{
var oldValue = _currentPage;
if (SetProperty(ref _currentPage, value))
{
if (oldValue is IDisposable disposable)
{
try
{
disposable.Dispose();
}
catch (Exception ex)
{
Logger.LogError(ex.ToString());
}
}
}
}
}
[ObservableProperty]
public partial PageViewModel CurrentPage { get; set; } = new LoadingPageViewModel(null, _scheduler);
private MainListPage? _mainListPage;

View File

@@ -12,7 +12,7 @@ public delegate bool IsActive();
public delegate bool FilterAccessibleKeyboardEvents(int key, UIntPtr extraInfo);
public partial class HotkeySettingsControlHook : IDisposable
public class HotkeySettingsControlHook : IDisposable
{
private const int WmKeyDown = 0x100;
private const int WmKeyUp = 0x101;

View File

@@ -5,81 +5,82 @@
using System;
using System.Runtime.InteropServices;
namespace Microsoft.PowerToys.Settings.UI.Helpers;
internal static class NativeKeyboardHelper
namespace Microsoft.PowerToys.Settings.UI.Helpers
{
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct INPUT
internal static class NativeKeyboardHelper
{
internal INPUTTYPE type;
internal InputUnion data;
internal static int Size
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct INPUT
{
get { return Marshal.SizeOf<INPUT>(); }
internal INPUTTYPE type;
internal InputUnion data;
internal static int Size
{
get { return Marshal.SizeOf(typeof(INPUT)); }
}
}
[StructLayout(LayoutKind.Explicit)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct InputUnion
{
[FieldOffset(0)]
internal MOUSEINPUT mi;
[FieldOffset(0)]
internal KEYBDINPUT ki;
[FieldOffset(0)]
internal HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct MOUSEINPUT
{
internal int dx;
internal int dy;
internal int mouseData;
internal uint dwFlags;
internal uint time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct KEYBDINPUT
{
internal short wVk;
internal short wScan;
internal uint dwFlags;
internal int time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct HARDWAREINPUT
{
internal int uMsg;
internal short wParamL;
internal short wParamH;
}
internal enum INPUTTYPE : uint
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2,
}
[Flags]
internal enum KeyEventF
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
Unicode = 0x0004,
Scancode = 0x0008,
}
}
[StructLayout(LayoutKind.Explicit)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct InputUnion
{
[FieldOffset(0)]
internal MOUSEINPUT mi;
[FieldOffset(0)]
internal KEYBDINPUT ki;
[FieldOffset(0)]
internal HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct MOUSEINPUT
{
internal int dx;
internal int dy;
internal int mouseData;
internal uint dwFlags;
internal uint time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct KEYBDINPUT
{
internal short wVk;
internal short wScan;
internal uint dwFlags;
internal int time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct HARDWAREINPUT
{
internal int uMsg;
internal short wParamL;
internal short wParamH;
}
internal enum INPUTTYPE : uint
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2,
}
[Flags]
internal enum KeyEventF
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
Unicode = 0x0004,
Scancode = 0x0008,
}
}

View File

@@ -7,7 +7,7 @@ using System.Text;
namespace Microsoft.PowerToys.Settings.UI.Helpers;
public static partial class NativeMethods
public static class NativeMethods
{
private const int WS_POPUP = 1 << 31; // 0x80000000
internal const int GWL_STYLE = -16;
@@ -26,11 +26,11 @@ public static partial class NativeMethods
[DllImport("user32.dll")]
internal static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);
[LibraryImport("user32.dll")]
internal static partial uint SendInput(uint nInputs, NativeKeyboardHelper.INPUT[] pInputs, int cbSize);
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, NativeKeyboardHelper.INPUT[] pInputs, int cbSize);
[LibraryImport("user32.dll")]
internal static partial short GetAsyncKeyState(int vKey);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern short GetAsyncKeyState(int vKey);
[DllImport("user32.dll", SetLastError = true)]
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);

View File

@@ -72,7 +72,7 @@ internal sealed partial class TrayIconService
_largeIcon = GetAppIconHandle();
_trayIconData = new NOTIFYICONDATAW()
{
cbSize = (uint)Marshal.SizeOf<NOTIFYICONDATAW>(),
cbSize = (uint)Marshal.SizeOf(typeof(NOTIFYICONDATAW)),
hWnd = _hwnd,
uID = MY_NOTIFY_ID,
uFlags = NOTIFY_ICON_DATA_FLAGS.NIF_MESSAGE | NOTIFY_ICON_DATA_FLAGS.NIF_ICON | NOTIFY_ICON_DATA_FLAGS.NIF_TIP,
@@ -133,7 +133,7 @@ internal sealed partial class TrayIconService
private DestroyIconSafeHandle GetAppIconHandle()
{
var exePath = Path.Combine(AppContext.BaseDirectory, "Microsoft.CmdPal.UI.exe");
var exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
DestroyIconSafeHandle largeIcon;
PInvoke.ExtractIconEx(exePath, 0, out largeIcon, out _, 1);
return largeIcon;

View File

@@ -1,6 +1,7 @@
GetPhysicallyInstalledSystemMemory
GlobalMemoryStatusEx
GetSystemInfo
CoCreateInstance
GetForegroundWindow
SetForegroundWindow
GetWindowRect
@@ -20,7 +21,10 @@ SetActiveWindow
MonitorFromWindow
GetMonitorInfo
GetDpiForMonitor
SHCreateStreamOnFileEx
CoAllowSetForegroundWindow
SHCreateStreamOnFileEx
SHLoadIndirectString
WM_HOTKEY
WM_NCLBUTTONDBLCLK
@@ -29,6 +33,7 @@ LoadIcon
WM_USER
WM_WINDOWPOSCHANGING
RegisterWindowMessageW
GetModuleHandleW
ExtractIconEx
TRACK_POPUP_MENU_FLAGS
WM_COMMAND

View File

@@ -6,6 +6,8 @@ using System;
using System.Collections.Generic;
using System.IO.Abstractions;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml;
using ManagedCommon;
using Microsoft.CmdPal.Ext.Apps.Commands;
@@ -13,6 +15,7 @@ using Microsoft.CmdPal.Ext.Apps.Properties;
using Microsoft.CmdPal.Ext.Apps.Utils;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Storage.Packaging.Appx;
using PackageVersion = Microsoft.CmdPal.Ext.Apps.Programs.UWP.PackageVersion;
using Theme = Microsoft.CmdPal.Ext.Apps.Utils.Theme;
@@ -71,7 +74,7 @@ public class UWPApplication : IProgram
public List<CommandContextItem> GetCommands()
{
List<CommandContextItem> commands = [];
List<CommandContextItem> commands = new List<CommandContextItem>();
if (CanRunElevated)
{
@@ -170,25 +173,6 @@ public class UWPApplication : IProgram
return false;
}
private static string TryLoadIndirectString(string source, Span<char> buffer, string errorContext)
{
try
{
PInvoke.SHLoadIndirectString(source, buffer).ThrowOnFailure();
var len = buffer.IndexOf('\0');
var loaded = len >= 0
? buffer[..len].ToString()
: buffer.ToString();
return string.IsNullOrEmpty(loaded) ? string.Empty : loaded;
}
catch (Exception ex)
{
Logger.LogError($"Unable to load resource {source} : {errorContext} : {ex.Message}");
return string.Empty;
}
}
internal unsafe string ResourceFromPri(string packageFullName, string resourceReference)
{
const string prefix = "ms-resource:";
@@ -223,16 +207,6 @@ public class UWPApplication : IProgram
parsedFallback = prefix + "///" + key;
}
Span<char> outBuffer = stackalloc char[1024];
var source = $"@{{{packageFullName}? {parsed}}}";
var loaded = TryLoadIndirectString(source, outBuffer, resourceReference);
if (!string.IsNullOrEmpty(loaded))
{
return loaded;
}
if (string.IsNullOrEmpty(parsedFallback))
{
// https://github.com/Wox-launcher/Wox/issues/964
@@ -244,8 +218,31 @@ public class UWPApplication : IProgram
return string.Empty;
}
var sourceFallback = $"@{{{packageFullName}?{parsedFallback}}}";
return TryLoadIndirectString(sourceFallback, outBuffer, $"{resourceReference} (fallback)");
Span<char> outBuffer = stackalloc char[1024];
var source = $"@{{{packageFullName}? {parsed}}}";
try
{
PInvoke.SHLoadIndirectString(source, outBuffer).ThrowOnFailure();
var loaded = outBuffer.ToString();
return string.IsNullOrEmpty(loaded) ? string.Empty : loaded;
}
catch (Exception)
{
try
{
var sourceFallback = $"@{{{packageFullName}?{parsedFallback}}}";
PInvoke.SHLoadIndirectString(sourceFallback, outBuffer).ThrowOnFailure();
var loaded = outBuffer.ToString();
return string.IsNullOrEmpty(loaded) ? string.Empty : loaded;
}
catch (Exception)
{
// ProgramLogger.Exception($"Unable to load resource {resourceReference} from {packageFullName}", new InvalidOperationException(), GetType(), packageFullName);
return string.Empty;
}
}
}
else
{

View File

@@ -82,9 +82,13 @@ public static class CalculateEngine
return default;
}
var decimalResult = Convert.ToDecimal(result, new CultureInfo("en-US"));
var decimalResult = Convert.ToDecimal(result, cultureInfo);
var roundedResult = FormatMax15Digits(decimalResult, cultureInfo);
// Remove trailing zeros from the decimal string representation (e.g., "1.2300" -> "1.23")
// This is necessary because the value extracted from exprtk may contain unnecessary trailing zeros.
var formatted = decimalResult.ToString("G29", cultureInfo);
decimalResult = Convert.ToDecimal(formatted, cultureInfo);
var roundedResult = Round(decimalResult);
return new CalculateResult()
{
@@ -97,28 +101,4 @@ public static class CalculateEngine
{
return Math.Round(value, RoundingDigits, MidpointRounding.AwayFromZero);
}
/// <summary>
/// Format a decimal so that the output contains **at most 15 total digits**
/// (integer + fraction, not counting the decimal point or minus sign).
/// Any extra fractional digits are rounded using “away-from-zero” rounding.
/// Trailing zeros in the fractional part—and a dangling decimal point—are removed.
/// Examples
/// 1.9999999999 → "1.9999999999"
/// 100000.9999999999 → "100001"
/// 1234567890123.45 → "1234567890123.45"
/// </summary>
private static decimal FormatMax15Digits(decimal value, CultureInfo cultureInfo)
{
var absValue = Math.Abs(value);
var integerDigits = absValue >= 1 ? (int)Math.Floor(Math.Log10((double)absValue)) + 1 : 1;
var maxDecimalDigits = Math.Max(0, 15 - integerDigits);
var rounded = Math.Round(value, maxDecimalDigits, MidpointRounding.AwayFromZero);
var formatted = rounded.ToString("G29", cultureInfo);
return Convert.ToDecimal(formatted, cultureInfo);
}
}

View File

@@ -1,47 +0,0 @@
// 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;
using System.Threading;
using System.Threading.Tasks;
using ManagedCommon;
using Windows.AI.Actions;
namespace Microsoft.CmdPal.Ext.Indexer.Data;
public static class ActionRuntimeManager
{
private static readonly Lazy<Task<ActionRuntime>> _lazyRuntime = new(InitializeAsync);
public static Task<ActionRuntime> InstanceAsync => _lazyRuntime.Value;
private static async Task<ActionRuntime> InitializeAsync()
{
// If we tried 3 times and failed, should we think the action runtime is not working?
// then we should not use it anymore.
const int maxAttempts = 3;
for (var attempt = 1; attempt <= maxAttempts; attempt++)
{
try
{
var runtime = ActionRuntimeFactory.CreateActionRuntime();
await Task.Delay(500);
return runtime;
}
catch (Exception ex)
{
Logger.LogError($"Attempt {attempt} to initialize ActionRuntime failed: {ex.Message}");
if (attempt == maxAttempts)
{
Logger.LogError($"Failed to initialize ActionRuntime: {ex.Message}");
}
}
}
return null;
}
}

View File

@@ -14,15 +14,6 @@ namespace Microsoft.CmdPal.Ext.Indexer.Data;
internal sealed partial class IndexerListItem : ListItem
{
internal static readonly bool IsActionsFeatureEnabled = GetFeatureFlag();
private static bool GetFeatureFlag()
{
var env = System.Environment.GetEnvironmentVariable("CMDPAL_ENABLE_ACTIONS_LIST");
return !string.IsNullOrEmpty(env) &&
(env == "1" || env.Equals("true", System.StringComparison.OrdinalIgnoreCase));
}
internal string FilePath { get; private set; }
public IndexerListItem(
@@ -54,7 +45,7 @@ internal sealed partial class IndexerListItem : ListItem
..context,
new CommandContextItem(new OpenWithCommand(indexerItem))];
if (IsActionsFeatureEnabled && ApiInformation.IsApiContractPresent("Windows.AI.Actions.ActionsContract", 4))
if (ApiInformation.IsApiContractPresent("Windows.AI.Actions.ActionsContract", 4))
{
var actionsListContextItem = new ActionsListContextItem(indexerItem.FullPath);
if (actionsListContextItem.AnyActions())

View File

@@ -2,11 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Ext.Indexer.Data;
using Microsoft.CmdPal.Ext.Indexer.Properties;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Foundation.Metadata;
namespace Microsoft.CmdPal.Ext.Indexer;
@@ -19,11 +17,6 @@ public partial class IndexerCommandsProvider : CommandProvider
Id = "Files";
DisplayName = Resources.IndexerCommandsProvider_DisplayName;
Icon = Icons.FileExplorer;
if (IndexerListItem.IsActionsFeatureEnabled && ApiInformation.IsApiContractPresent("Windows.AI.Actions.ActionsContract", 4))
{
_ = ActionRuntimeManager.InstanceAsync;
}
}
public override ICommandItem[] TopLevelCommands()

View File

@@ -2,12 +2,10 @@
// 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;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.CmdPal.Ext.Indexer.Commands;
using Microsoft.CmdPal.Ext.Indexer.Data;
using Microsoft.CmdPal.Ext.Indexer.Properties;
@@ -17,7 +15,7 @@ using Windows.System;
namespace Microsoft.CmdPal.Ext.Indexer.Pages;
internal sealed partial class ActionsListContextItem : CommandContextItem, IDisposable
internal sealed partial class ActionsListContextItem : CommandContextItem
{
private readonly string fullPath;
private readonly List<CommandContextItem> actions = [];
@@ -43,24 +41,20 @@ internal sealed partial class ActionsListContextItem : CommandContextItem, IDisp
private void UpdateMoreCommands()
{
lock (UpdateMoreCommandsLock)
{
if (actionRuntime == null)
{
actionRuntime = ActionRuntimeManager.InstanceAsync.GetAwaiter().GetResult();
}
if (actionRuntime == null)
{
return;
}
actionRuntime.ActionCatalog.Changed -= ActionCatalog_Changed;
actionRuntime.ActionCatalog.Changed += ActionCatalog_Changed;
}
try
{
lock (UpdateMoreCommandsLock)
{
if (actionRuntime == null)
{
actionRuntime = ActionRuntimeFactory.CreateActionRuntime();
Task.Delay(500).Wait();
}
actionRuntime.ActionCatalog.Changed -= ActionCatalog_Changed;
actionRuntime.ActionCatalog.Changed += ActionCatalog_Changed;
}
var extension = System.IO.Path.GetExtension(fullPath).ToLower(CultureInfo.InvariantCulture);
ActionEntity entity = null;
if (extension != null)
@@ -91,20 +85,9 @@ internal sealed partial class ActionsListContextItem : CommandContextItem, IDisp
MoreCommands = [.. actions];
}
}
catch (Exception ex)
catch
{
Logger.LogError($"Error updating commands: {ex.Message}");
}
}
public void Dispose()
{
lock (UpdateMoreCommandsLock)
{
if (actionRuntime != null)
{
actionRuntime.ActionCatalog.Changed -= ActionCatalog_Changed;
}
actionRuntime = null;
}
}
}

View File

@@ -17,7 +17,6 @@ internal sealed partial class TimeDateExtensionPage : DynamicListPage
private readonly Lock _resultsLock = new();
private IList<ListItem> _results = new List<ListItem>();
private bool _dataLoaded;
private SettingsManager _settingsManager;
@@ -34,23 +33,11 @@ internal sealed partial class TimeDateExtensionPage : DynamicListPage
public override IListItem[] GetItems()
{
ListItem[] results;
lock (_resultsLock)
{
if (_dataLoaded)
{
results = _results.ToArray();
_dataLoaded = false;
return results;
}
}
DoExecuteSearch(string.Empty);
lock (_resultsLock)
{
results = _results.ToArray();
_dataLoaded = false;
ListItem[] results = _results.ToArray();
return results;
}
}
@@ -88,7 +75,6 @@ internal sealed partial class TimeDateExtensionPage : DynamicListPage
lock (_resultsLock)
{
this._results = result;
_dataLoaded = true;
}
RaiseItemsChanged(this._results.Count);

View File

@@ -20,7 +20,7 @@ internal sealed partial class CloseWindowCommand : InvokableCommand
public CloseWindowCommand(Window window)
{
Icon = new IconInfo("\uE894");
Icon = new IconInfo("\xE8BB");
Name = $"{Resources.windowwalker_Close}";
_window = window;
}

View File

@@ -15,13 +15,13 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Commands;
internal sealed partial class EndTaskCommand : InvokableCommand
internal sealed partial class KillProcessCommand : InvokableCommand
{
private readonly Window _window;
public EndTaskCommand(Window window)
public KillProcessCommand(Window window)
{
Icon = new IconInfo("\uF140");
Icon = new IconInfo("\xE74D"); // Delete symbol
Name = $"{Resources.windowwalker_Kill}";
_window = window;
}

View File

@@ -33,7 +33,7 @@ internal sealed class ContextMenuHelper
if (!windowData.Process.IsShellProcess && !(windowData.Process.IsUwpApp && string.Equals(windowData.Process.Name, "ApplicationFrameHost.exe", StringComparison.OrdinalIgnoreCase))
&& !(windowData.Process.IsFullAccessDenied && SettingsManager.Instance.HideKillProcessOnElevatedProcesses))
{
contextMenu.Add(new CommandContextItem(new EndTaskCommand(windowData))
contextMenu.Add(new CommandContextItem(new KillProcessCommand(windowData))
{
RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.Delete, 0),
IsCritical = true,

View File

@@ -124,7 +124,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties {
}
/// <summary>
/// Looks up a localized string similar to Info: Ending the Explorer process isn&apos;t possible..
/// Looks up a localized string similar to Info: Killing the Explorer process isn&apos;t possible..
/// </summary>
public static string windowwalker_ExplorerInfoTitle {
get {
@@ -133,7 +133,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties {
}
/// <summary>
/// Looks up a localized string similar to End task.
/// Looks up a localized string similar to Kill process.
/// </summary>
public static string windowwalker_Kill {
get {
@@ -142,7 +142,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties {
}
/// <summary>
/// Looks up a localized string similar to You are going to end the following process:.
/// Looks up a localized string similar to Your are going to kill the following process:.
/// </summary>
public static string windowwalker_KillMessage {
get {
@@ -160,7 +160,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties {
}
/// <summary>
/// Looks up a localized string similar to End task confirmation.
/// Looks up a localized string similar to Kill process confirmation.
/// </summary>
public static string windowwalker_KillMessageTitle {
get {

View File

@@ -166,23 +166,23 @@
<comment>Explorer is here the program File Explorer</comment>
</data>
<data name="windowwalker_ExplorerInfoTitle" xml:space="preserve">
<value>Info: Ending the Explorer process isn't possible.</value>
<value>Info: Killing the Explorer process isn't possible.</value>
<comment>Explorer is here the program File Explorer</comment>
</data>
<data name="windowwalker_Close" xml:space="preserve">
<value>Close window</value>
</data>
<data name="windowwalker_Kill" xml:space="preserve">
<value>End task</value>
<value>Kill process</value>
</data>
<data name="windowwalker_KillMessage" xml:space="preserve">
<value>The following process will be ended:</value>
<value>Your are going to kill the following process:</value>
</data>
<data name="windowwalker_KillMessageQuestion" xml:space="preserve">
<value>Continue?</value>
</data>
<data name="windowwalker_KillMessageTitle" xml:space="preserve">
<value>End task confirmation</value>
<value>Kill process confirmation</value>
</data>
<data name="windowwalker_KillMessageUwp" xml:space="preserve">
<value>Because this is an app process, all instances of the app will be killed. Continue?</value>

View File

@@ -25,7 +25,7 @@ public class Program
server.RegisterExtension(() => extensionInstance);
// This will make the main thread wait until the event is signalled by the extension class.
// Since we have a single instance of the extension object, we exit as soon as it is disposed.
// Since we have single instance of the extension object, we exit as soon as it is disposed.
extensionDisposedEvent.WaitOne();
}
else

View File

@@ -12,4 +12,4 @@ To view the full docs, you can head over to [our docs site](https://go.microsoft
There are samples of just about everything you can do in [the samples project].
Head over there to see basic usage of the APIs.
[the samples project]: https://github.com/microsoft/PowerToys/tree/main/src/modules/cmdpal/ext/SamplePagesExtension
[the samples project]: https://github.com/microsoft/PowerToys/tree/main/src/modules/cmdpal/Exts/SamplePagesExtension

View File

@@ -363,7 +363,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
RenamedEventArgs e = new RenamedEventArgs(WatcherChangeTypes.Renamed, directory, path, oldpath);
string oldFullPath = directory + "\\" + oldpath;
string newFullPath = directory + "\\" + path;
string fullPath = directory + "\\" + path;
string linkingTo = Directory.GetCurrentDirectory();
// ShellLinkHelper must be mocked for lnk applications
@@ -372,8 +372,19 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
Win32Program.ShellLinkHelper = mockShellLink.Object;
// old item and new item are the actual items when they are in existence
Win32Program olditem = Win32Program.GetAppFromPath(oldFullPath);
Win32Program newitem = Win32Program.GetAppFromPath(newFullPath);
Win32Program olditem = new Win32Program
{
Name = "oldpath",
ExecutableName = oldpath,
FullPath = linkingTo,
};
Win32Program newitem = new Win32Program
{
Name = "path",
ExecutableName = path,
FullPath = linkingTo,
};
win32ProgramRepository.Add(olditem);

View File

@@ -180,6 +180,9 @@
<value>Exit</value>
<comment>Exit as a verb, as in Exit the application</comment>
</data>
<data name="SHOW_TRAY_ICON_MENU_TEXT" xml:space="preserve">
<value>Show icon</value>
</data>
<data name="SUBMIT_BUG_TEXT" xml:space="preserve">
<value>Report bug</value>
</data>

View File

@@ -164,8 +164,7 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
else
{
delete_auto_start_task_for_this_user();
if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled || gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_not_configured)
{
if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled || gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_not_configured) {
create_auto_start_task_for_this_user(run_as_elevated);
}
}

View File

@@ -21,3 +21,4 @@
#define ID_REPORT_BUG_COMMAND 40004
#define ID_DOCUMENTATION_MENU_COMMAND 40005
#define ID_QUICK_ACCESS_MENU_COMMAND 40006
#define ID_SHOW_TRAY_ICON_MENU_COMMAND 40007

Binary file not shown.

View File

@@ -91,6 +91,13 @@ void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam)
}
DestroyWindow(window);
break;
case ID_SHOW_TRAY_ICON_MENU_COMMAND:
{
GeneralSettings settings = get_general_settings();
settings.showSystemTrayIcon = true;
apply_general_settings(settings.to_json(), true);
break;
}
case ID_ABOUT_MENU_COMMAND:
if (!about_box_shown)
{
@@ -192,11 +199,13 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
{
static std::wstring settings_menuitem_label = GET_RESOURCE_STRING(IDS_SETTINGS_MENU_TEXT);
static std::wstring exit_menuitem_label = GET_RESOURCE_STRING(IDS_EXIT_MENU_TEXT);
static std::wstring show_tray_icon_menuitem_label = GET_RESOURCE_STRING(IDS_SHOW_TRAY_ICON_MENU_TEXT);
static std::wstring submit_bug_menuitem_label = GET_RESOURCE_STRING(IDS_SUBMIT_BUG_TEXT);
static std::wstring documentation_menuitem_label = GET_RESOURCE_STRING(IDS_DOCUMENTATION_MENU_TEXT);
static std::wstring quick_access_menuitem_label = GET_RESOURCE_STRING(IDS_QUICK_ACCESS_MENU_TEXT);
change_menu_item_text(ID_SETTINGS_MENU_COMMAND, settings_menuitem_label.data());
change_menu_item_text(ID_EXIT_MENU_COMMAND, exit_menuitem_label.data());
change_menu_item_text(ID_SHOW_TRAY_ICON_MENU_COMMAND, show_tray_icon_menuitem_label.data());
change_menu_item_text(ID_REPORT_BUG_COMMAND, submit_bug_menuitem_label.data());
bool bug_report_disabled = is_bug_report_running();
EnableMenuItem(h_sub_menu, ID_REPORT_BUG_COMMAND, MF_BYCOMMAND | (bug_report_disabled ? MF_GRAYED : MF_ENABLED));

View File

@@ -41,9 +41,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonPropertyName("auto_activate")]
public BoolProperty AutoActivate { get; set; }
[JsonPropertyName("spotlight_mode")]
public BoolProperty SpotlightMode { get; set; }
public MouseHighlighterProperties()
{
ActivationShortcut = DefaultActivationShortcut;
@@ -55,7 +52,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
HighlightFadeDelayMs = new IntProperty(500);
HighlightFadeDurationMs = new IntProperty(250);
AutoActivate = new BoolProperty(false);
SpotlightMode = new BoolProperty(false);
}
}
}

View File

@@ -214,24 +214,15 @@
HeaderIcon="{ui:FontIcon Glyph=&#xEB3C;}"
IsEnabled="{x:Bind ViewModel.IsMouseHighlighterEnabled, Mode=OneWay}">
<tkcontrols:SettingsExpander.Items>
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_PrimaryButtonClickColor" IsEnabled="{x:Bind ViewModel.IsSpotlightModeEnabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_PrimaryButtonClickColor">
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterLeftButtonClickColor, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_SecondaryButtonClickColor" IsEnabled="{x:Bind ViewModel.IsSpotlightModeEnabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_SecondaryButtonClickColor">
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterRightButtonClickColor, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_AlwaysColor">
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterAlwaysColor, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard x:Uid="HighlightMode">
<ComboBox
x:Uid="MouseUtils_MouseHighlighter_SpotlightModeType"
MinWidth="{StaticResource SettingActionControlMinWidth}"
SelectedIndex="{x:Bind ViewModel.IsSpotlightModeEnabled, Converter={StaticResource ReverseBoolToComboBoxIndexConverter}, Mode=TwoWay}">
<ComboBoxItem x:Uid="HighlightMode_Spotlight_Mode" />
<ComboBoxItem x:Uid="HighlightMode_Circle_Highlight_Mode" />
</ComboBox>
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_HighlightRadius">
<NumberBox
MinWidth="{StaticResource SettingActionControlMinWidth}"

View File

@@ -5068,16 +5068,4 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
<data name="BugReportUnderConstruction" xml:space="preserve">
<value>Bug report package is being created</value>
</data>
<data name="HighlightMode.Description" xml:space="preserve">
<value>Highlight the cursor or dim the screen to spotlight it</value>
</data>
<data name="HighlightMode.Header" xml:space="preserve">
<value>Highlight mode</value>
</data>
<data name="HighlightMode_Circle_Highlight_Mode.Content" xml:space="preserve">
<value>Circle highlight</value>
</data>
<data name="HighlightMode_Spotlight_Mode.Content" xml:space="preserve">
<value>Spotlight</value>
</data>
</root>

View File

@@ -72,7 +72,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
string alwaysColor = MouseHighlighterSettingsConfig.Properties.AlwaysColor.Value;
_highlighterAlwaysColor = !string.IsNullOrEmpty(alwaysColor) ? alwaysColor : "#00FF0000";
_isSpotlightModeEnabled = MouseHighlighterSettingsConfig.Properties.SpotlightMode.Value;
_highlighterRadius = MouseHighlighterSettingsConfig.Properties.HighlightRadius.Value;
_highlightFadeDelayMs = MouseHighlighterSettingsConfig.Properties.HighlightFadeDelayMs.Value;
@@ -561,20 +560,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
public bool IsSpotlightModeEnabled
{
get => _isSpotlightModeEnabled;
set
{
if (_isSpotlightModeEnabled != value)
{
_isSpotlightModeEnabled = value;
MouseHighlighterSettingsConfig.Properties.SpotlightMode.Value = value;
NotifyMouseHighlighterPropertyChanged();
}
}
}
public int MouseHighlighterRadius
{
get
@@ -931,7 +916,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private string _highlighterLeftButtonClickColor;
private string _highlighterRightButtonClickColor;
private string _highlighterAlwaysColor;
private bool _isSpotlightModeEnabled;
private int _highlighterRadius;
private int _highlightFadeDelayMs;
private int _highlightFadeDurationMs;