diff --git a/src/common/utils/color.h b/src/common/utils/color.h index 3996ecd61b..6a424f8811 100644 --- a/src/common/utils/color.h +++ b/src/common/utils/color.h @@ -19,3 +19,23 @@ inline bool checkValidRGB(std::wstring_view hex, uint8_t* R, uint8_t* G, uint8_t } return true; } + +// helper function to get the ARGB from a #FFFFFFFF string. +inline bool checkValidARGB(std::wstring_view hex, uint8_t* A, uint8_t* R, uint8_t* G, uint8_t* B) +{ + if (hex.length() != 9) + return false; + hex = hex.substr(1, 8); // remove # + for (auto& c : hex) + { + if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))) + { + return false; + } + } + if (swscanf_s(hex.data(), L"%2hhx%2hhx%2hhx%2hhx", A, R, G, B) != 4) + { + return false; + } + return true; +} diff --git a/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp b/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp index 2a10ff648d..49f04a75ef 100644 --- a/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp +++ b/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp @@ -31,7 +31,8 @@ private: enum class MouseButton { Left, - Right + Right, + None }; void DestroyHighlighter(); @@ -42,6 +43,7 @@ private: void AddDrawingPoint(MouseButton button); void UpdateDrawingPointPosition(MouseButton button); void StartDrawingPointFading(MouseButton button); + void ClearDrawingPoint(MouseButton button); void ClearDrawing(); HHOOK m_mouseHook = NULL; static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept; @@ -62,6 +64,12 @@ private: winrt::CompositionSpriteShape m_leftPointer{ nullptr }; winrt::CompositionSpriteShape m_rightPointer{ nullptr }; + winrt::CompositionSpriteShape m_alwaysPointer{ nullptr }; + + bool m_leftPointerEnabled = true; + bool m_rightPointerEnabled = true; + bool m_alwaysPointerEnabled = true; + bool m_leftButtonPressed = false; bool m_rightButtonPressed = false; @@ -75,6 +83,7 @@ private: winrt::Windows::UI::Color m_leftClickColor = MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR; winrt::Windows::UI::Color m_rightClickColor = MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR; + winrt::Windows::UI::Color m_alwaysColor = MOUSE_HIGHLIGHTER_DEFAULT_ALWAYS_COLOR; }; Highlighter* Highlighter::instance = nullptr; @@ -132,18 +141,23 @@ void Highlighter::AddDrawingPoint(MouseButton button) auto circleGeometry = m_compositor.CreateEllipseGeometry(); circleGeometry.Radius({ m_radius, m_radius }); auto circleShape = m_compositor.CreateSpriteShape(circleGeometry); - circleShape.Offset({ static_cast(pt.x), static_cast(pt.y )}); + circleShape.Offset({ static_cast(pt.x), static_cast(pt.y) }); if (button == MouseButton::Left) { circleShape.FillBrush(m_compositor.CreateColorBrush(m_leftClickColor)); m_leftPointer = circleShape; } - else + else if (button == MouseButton::Right) { - //right circleShape.FillBrush(m_compositor.CreateColorBrush(m_rightClickColor)); m_rightPointer = circleShape; } + else + { + // always + circleShape.FillBrush(m_compositor.CreateColorBrush(m_alwaysColor)); + m_alwaysPointer = circleShape; + } m_shape.Shapes().Append(circleShape); // TODO: We're leaking shapes for long drawing sessions. @@ -166,12 +180,16 @@ void Highlighter::UpdateDrawingPointPosition(MouseButton button) if (button == MouseButton::Left) { - m_leftPointer.Offset({ static_cast(pt.x), static_cast(pt.y )}); + m_leftPointer.Offset({ static_cast(pt.x), static_cast(pt.y) }); + } + else if (button == MouseButton::Right) + { + m_rightPointer.Offset({ static_cast(pt.x), static_cast(pt.y) }); } else { - //right - m_rightPointer.Offset({ static_cast(pt.x), static_cast(pt.y )}); + // always + m_alwaysPointer.Offset({ static_cast(pt.x), static_cast(pt.y) }); } } void Highlighter::StartDrawingPointFading(MouseButton button) @@ -183,7 +201,7 @@ void Highlighter::StartDrawingPointFading(MouseButton button) } else { - //right + // right circleShape = m_rightPointer; } @@ -201,6 +219,15 @@ void Highlighter::StartDrawingPointFading(MouseButton button) circleShape.FillBrush().StartAnimation(L"Color", animation); } +void Highlighter::ClearDrawingPoint(MouseButton _button) +{ + winrt::Windows::UI::Composition::CompositionSpriteShape circleShape{ nullptr }; + + // always + circleShape = m_alwaysPointer; + + circleShape.FillBrush().as().Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0)); +} void Highlighter::ClearDrawing() { @@ -221,12 +248,28 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa switch (wParam) { case WM_LBUTTONDOWN: - instance->AddDrawingPoint(MouseButton::Left); - instance->m_leftButtonPressed = true; + if (instance->m_leftPointerEnabled) + { + if (instance->m_alwaysPointerEnabled && !instance->m_rightButtonPressed) + { + // Clear AlwaysPointer only when it's enabled and RightPointer is not active + instance->ClearDrawingPoint(MouseButton::None); + } + instance->AddDrawingPoint(MouseButton::Left); + instance->m_leftButtonPressed = true; + } break; case WM_RBUTTONDOWN: - instance->AddDrawingPoint(MouseButton::Right); - instance->m_rightButtonPressed = true; + if (instance->m_rightPointerEnabled) + { + if (instance->m_alwaysPointerEnabled && !instance->m_leftButtonPressed) + { + // Clear AlwaysPointer only when it's enabled and LeftPointer is not active + instance->ClearDrawingPoint(MouseButton::None); + } + instance->AddDrawingPoint(MouseButton::Right); + instance->m_rightButtonPressed = true; + } break; case WM_MOUSEMOVE: if (instance->m_leftButtonPressed) @@ -237,12 +280,21 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa { instance->UpdateDrawingPointPosition(MouseButton::Right); } + if (instance->m_alwaysPointerEnabled && !instance->m_leftButtonPressed && !instance->m_rightButtonPressed) + { + instance->UpdateDrawingPointPosition(MouseButton::None); + } break; case WM_LBUTTONUP: if (instance->m_leftButtonPressed) { instance->StartDrawingPointFading(MouseButton::Left); instance->m_leftButtonPressed = false; + if (instance->m_alwaysPointerEnabled && !instance->m_rightButtonPressed) + { + // Add AlwaysPointer only when it's enabled and RightPointer is not active + instance->AddDrawingPoint(MouseButton::None); + } } break; case WM_RBUTTONUP: @@ -250,6 +302,11 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa { instance->StartDrawingPointFading(MouseButton::Right); instance->m_rightButtonPressed = false; + if (instance->m_alwaysPointerEnabled && !instance->m_leftButtonPressed) + { + // Add AlwaysPointer only when it's enabled and LeftPointer is not active + instance->AddDrawingPoint(MouseButton::None); + } } break; default: @@ -270,6 +327,7 @@ void Highlighter::StartDrawing() 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(MouseButton::None); m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0); } @@ -281,6 +339,7 @@ void Highlighter::StopDrawing() m_rightButtonPressed = false; m_leftPointer = nullptr; m_rightPointer = nullptr; + m_alwaysPointer = nullptr; ShowWindow(m_hwnd, SW_HIDE); UnhookWindowsHookEx(m_mouseHook); ClearDrawing(); @@ -298,6 +357,10 @@ void Highlighter::ApplySettings(MouseHighlighterSettings settings) { m_fadeDuration_ms = settings.fadeDurationMs; m_leftClickColor = settings.leftButtonColor; m_rightClickColor = settings.rightButtonColor; + m_alwaysColor = settings.alwaysColor; + m_leftPointerEnabled = settings.leftButtonColor.A != 0; + m_rightPointerEnabled = settings.rightButtonColor.A != 0; + m_alwaysPointerEnabled = settings.alwaysColor.A != 0; } void Highlighter::DestroyHighlighter() diff --git a/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.h b/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.h index e98024d100..6ec069f7cc 100644 --- a/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.h +++ b/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.h @@ -1,9 +1,9 @@ #pragma once #include "pch.h" -constexpr int MOUSE_HIGHLIGHTER_DEFAULT_OPACITY = 65; -const winrt::Windows::UI::Color MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(MOUSE_HIGHLIGHTER_DEFAULT_OPACITY, 255, 255, 0); -const winrt::Windows::UI::Color MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(MOUSE_HIGHLIGHTER_DEFAULT_OPACITY, 0, 0, 255); +const winrt::Windows::UI::Color MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(166, 255, 255, 0); +const winrt::Windows::UI::Color MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(166, 0, 0, 255); +const winrt::Windows::UI::Color MOUSE_HIGHLIGHTER_DEFAULT_ALWAYS_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(0, 255, 0, 0); constexpr int MOUSE_HIGHLIGHTER_DEFAULT_RADIUS = 20; constexpr int MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS = 500; constexpr int MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS = 250; @@ -12,6 +12,7 @@ struct MouseHighlighterSettings { winrt::Windows::UI::Color leftButtonColor = MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR; winrt::Windows::UI::Color rightButtonColor = MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR; + winrt::Windows::UI::Color alwaysColor = MOUSE_HIGHLIGHTER_DEFAULT_ALWAYS_COLOR; int radius = MOUSE_HIGHLIGHTER_DEFAULT_RADIUS; int fadeDelayMs = MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS; int fadeDurationMs = MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS; diff --git a/src/modules/MouseUtils/MouseHighlighter/dllmain.cpp b/src/modules/MouseUtils/MouseHighlighter/dllmain.cpp index b3860a227b..ed259e2a54 100644 --- a/src/modules/MouseUtils/MouseHighlighter/dllmain.cpp +++ b/src/modules/MouseUtils/MouseHighlighter/dllmain.cpp @@ -13,6 +13,7 @@ namespace const wchar_t JSON_KEY_LEFT_BUTTON_CLICK_COLOR[] = L"left_button_click_color"; const wchar_t JSON_KEY_RIGHT_BUTTON_CLICK_COLOR[] = L"right_button_click_color"; const wchar_t JSON_KEY_HIGHLIGHT_OPACITY[] = L"highlight_opacity"; + const wchar_t JSON_KEY_ALWAYS_COLOR[] = L"always_color"; const wchar_t JSON_KEY_HIGHLIGHT_RADIUS[] = L"highlight_radius"; 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"; @@ -210,45 +211,53 @@ public: { Logger::warn("Failed to initialize Mouse Highlighter activation shortcut"); } - uint8_t opacity = MOUSE_HIGHLIGHTER_DEFAULT_OPACITY; - try + // Migration from <=1.1 + auto version = (std::wstring)settingsObject.GetNamedString(L"version"); + auto migration = false; + uint8_t opacity = 166; + if (version == L"1.0" || version == L"1.1") { - // Parse Opacity - auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_OPACITY); - int value = static_cast(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE)); - if (value >= 0) + migration = true; + try { - opacity = value; + // Parse Opacity + auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_OPACITY); + int value = static_cast(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE)); + if (value >= 0) + { + if (version == L"1.0") + { + opacity = value; + } + else + { + // 1.1 + opacity = value * 255 / 100; + } + } + else + { + throw; + } } - else + catch (...) { - throw; + Logger::warn("Failed to initialize Opacity from settings. Will use default value"); } } - catch (...) - { - Logger::warn("Failed to initialize Opacity from settings. Will use default value"); - } - - // Convert % to uint8_t - if ((std::wstring)settingsObject.GetNamedString(L"version") != L"1.0") - { - opacity = opacity * 255 / 100; - } - try { // Parse left button click color auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_LEFT_BUTTON_CLICK_COLOR); auto leftColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE); - uint8_t r, g, b; - if (!checkValidRGB(leftColor, &r, &g, &b)) + uint8_t a = opacity, r, g, b; + if (!migration && !checkValidARGB(leftColor, &a, &r, &g, &b) || migration && !checkValidRGB(leftColor, &r, &g, &b)) { - Logger::error("Left click color RGB value is invalid. Will use default value"); + Logger::error("Left click color ARGB value is invalid. Will use default value"); } else { - highlightSettings.leftButtonColor = winrt::Windows::UI::ColorHelper::FromArgb(opacity, r, g, b); + highlightSettings.leftButtonColor = winrt::Windows::UI::ColorHelper::FromArgb(a, r, g, b); } } catch (...) @@ -260,14 +269,14 @@ public: // Parse right button click color auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_RIGHT_BUTTON_CLICK_COLOR); auto rightColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE); - uint8_t r, g, b; - if (!checkValidRGB(rightColor, &r, &g, &b)) + uint8_t a = opacity, r, g, b; + if (!migration && !checkValidARGB(rightColor, &a, &r, &g, &b) || migration && !checkValidRGB(rightColor, &r, &g, &b)) { - Logger::error("Right click color RGB value is invalid. Will use default value"); + Logger::error("Right click color ARGB value is invalid. Will use default value"); } else { - highlightSettings.rightButtonColor = winrt::Windows::UI::ColorHelper::FromArgb(opacity, r, g, b); + highlightSettings.rightButtonColor = winrt::Windows::UI::ColorHelper::FromArgb(a, r, g, b); } } catch (...) @@ -275,6 +284,25 @@ public: Logger::warn("Failed to initialize right click color from settings. Will use default value"); } try + { + // Parse always color + auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ALWAYS_COLOR); + auto alwaysColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE); + uint8_t a, r, g, b; + if (!migration && !checkValidARGB(alwaysColor, &a, &r, &g, &b)) + { + Logger::error("Always color ARGB value is invalid. Will use default value"); + } + else + { + highlightSettings.alwaysColor = winrt::Windows::UI::ColorHelper::FromArgb(a, r, g, b); + } + } + catch (...) + { + Logger::warn("Failed to initialize always color from settings. Will use default value"); + } + try { // Parse Radius auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_RADIUS); @@ -346,4 +374,4 @@ public: extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create() { return new MouseHighlighter(); -} \ No newline at end of file +} diff --git a/src/settings-ui/Settings.UI.Library/Helpers/SettingsUtilities.cs b/src/settings-ui/Settings.UI.Library/Helpers/SettingsUtilities.cs index 913948921c..a8a25c19e3 100644 --- a/src/settings-ui/Settings.UI.Library/Helpers/SettingsUtilities.cs +++ b/src/settings-ui/Settings.UI.Library/Helpers/SettingsUtilities.cs @@ -35,5 +35,33 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Helpers return "#FFFFFF"; } } + + public static string ToARGBHex(string color) + { + if (color == null) + { + return "#FFFFFFFF"; + } + + // Using InvariantCulture as these are expected to be hex codes. + bool success = int.TryParse( + color.Replace("#", string.Empty), + System.Globalization.NumberStyles.HexNumber, + CultureInfo.InvariantCulture, + out int argb); + + if (success) + { + Color clr = Color.FromArgb(argb); + return "#" + clr.A.ToString("X2", CultureInfo.InvariantCulture) + + clr.R.ToString("X2", CultureInfo.InvariantCulture) + + clr.G.ToString("X2", CultureInfo.InvariantCulture) + + clr.B.ToString("X2", CultureInfo.InvariantCulture); + } + else + { + return "#FFFFFFFF"; + } + } } } diff --git a/src/settings-ui/Settings.UI.Library/MouseHighlighterProperties.cs b/src/settings-ui/Settings.UI.Library/MouseHighlighterProperties.cs index 2f11ff33b2..66b08e9418 100644 --- a/src/settings-ui/Settings.UI.Library/MouseHighlighterProperties.cs +++ b/src/settings-ui/Settings.UI.Library/MouseHighlighterProperties.cs @@ -22,6 +22,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library [JsonPropertyName("highlight_opacity")] public IntProperty HighlightOpacity { get; set; } + [JsonPropertyName("always_color")] + public StringProperty AlwaysColor { get; set; } + [JsonPropertyName("highlight_radius")] public IntProperty HighlightRadius { get; set; } @@ -34,9 +37,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library public MouseHighlighterProperties() { ActivationShortcut = DefaultActivationShortcut; - LeftButtonClickColor = new StringProperty("#FFFF00"); - RightButtonClickColor = new StringProperty("#0000FF"); - HighlightOpacity = new IntProperty(65); + LeftButtonClickColor = new StringProperty("#a6FFFF00"); + RightButtonClickColor = new StringProperty("#a60000FF"); + AlwaysColor = new StringProperty("#00FF0000"); + HighlightOpacity = new IntProperty(166); // for migration from <=1.1 to 1.2 HighlightRadius = new IntProperty(20); HighlightFadeDelayMs = new IntProperty(500); HighlightFadeDurationMs = new IntProperty(250); diff --git a/src/settings-ui/Settings.UI.Library/MouseHighlighterSettings.cs b/src/settings-ui/Settings.UI.Library/MouseHighlighterSettings.cs index c25869c969..b677ee2175 100644 --- a/src/settings-ui/Settings.UI.Library/MouseHighlighterSettings.cs +++ b/src/settings-ui/Settings.UI.Library/MouseHighlighterSettings.cs @@ -2,6 +2,8 @@ // 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.Globalization; +using System.Runtime.InteropServices; using System.Text.Json.Serialization; using Microsoft.PowerToys.Settings.UI.Library.Interfaces; @@ -18,7 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library { Name = ModuleName; Properties = new MouseHighlighterProperties(); - Version = "1.1"; + Version = "1.2"; } public string GetModuleName() @@ -29,11 +31,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library // This can be utilized in the future if the settings.json file is to be modified/deleted. public bool UpgradeSettingsConfiguration() { - // Migrate settings from 1.0 to 1.1 - if (Version == "1.0") + if (Version == "1.0" || Version == "1.1") { - Version = "1.1"; - Properties.HighlightOpacity = new IntProperty(Properties.HighlightOpacity.Value * 100 / 255); + string opacity; + if (Version == "1.0") + { + opacity = string.Format(CultureInfo.InvariantCulture, "{0:X2}", Properties.HighlightOpacity.Value); + } + else + { + // 1.1 + opacity = string.Format(CultureInfo.InvariantCulture, "{0:X2}", Properties.HighlightOpacity.Value * 255 / 100); + } + + Properties.LeftButtonClickColor = new StringProperty(string.Concat("#", opacity, Properties.LeftButtonClickColor.Value.ToString().Substring(1, 6))); + Properties.RightButtonClickColor = new StringProperty(string.Concat("#", opacity, Properties.RightButtonClickColor.Value.ToString().Substring(1, 6))); + Version = "1.2"; return true; } diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml new file mode 100644 index 0000000000..0eaf6916b4 --- /dev/null +++ b/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml.cs new file mode 100644 index 0000000000..24a0d0e448 --- /dev/null +++ b/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml.cs @@ -0,0 +1,59 @@ +// 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 Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Windows.UI; + +namespace Microsoft.PowerToys.Settings.UI.Controls +{ + public sealed partial class AlphaColorPickerButton : UserControl + { + private Color _selectedColor; + + public Color SelectedColor + { + get + { + return _selectedColor; + } + + set + { + if (_selectedColor != value) + { + _selectedColor = value; + SetValue(SelectedColorProperty, value); + } + } + } + + public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register("SelectedColor", typeof(Color), typeof(AlphaColorPickerButton), new PropertyMetadata(null)); + + public AlphaColorPickerButton() + { + this.InitializeComponent(); + IsEnabledChanged -= AlphaColorPickerButton_IsEnabledChanged; + SetEnabledState(); + IsEnabledChanged += AlphaColorPickerButton_IsEnabledChanged; + } + + private void AlphaColorPickerButton_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) + { + SetEnabledState(); + } + + private void SetEnabledState() + { + if (this.IsEnabled) + { + ColorPreviewBorder.Opacity = 1; + } + else + { + ColorPreviewBorder.Opacity = 0.2; + } + } + } +} diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml index e0cdac3d63..2df5b2e824 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml @@ -163,17 +163,13 @@ IsEnabled="{x:Bind ViewModel.IsMouseHighlighterEnabled, Mode=OneWay}"> - + - + - - + + Secondary button highlight color - - Opacity (%) - Radius (px) px = pixels @@ -3590,6 +3587,9 @@ Activate by holding the key for the character you want to add an accent to, then UTF-8 with BOM + + Always highlight color + Automatically hide crosshairs when the mouse pointer is hidden diff --git a/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs index 2b4b4abe25..b8fe2460be 100644 --- a/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs @@ -71,12 +71,14 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels MouseHighlighterSettingsConfig = mouseHighlighterSettingsRepository.SettingsConfig; string leftClickColor = MouseHighlighterSettingsConfig.Properties.LeftButtonClickColor.Value; - _highlighterLeftButtonClickColor = !string.IsNullOrEmpty(leftClickColor) ? leftClickColor : "#FFFF00"; + _highlighterLeftButtonClickColor = !string.IsNullOrEmpty(leftClickColor) ? leftClickColor : "#a6FFFF00"; string rightClickColor = MouseHighlighterSettingsConfig.Properties.RightButtonClickColor.Value; - _highlighterRightButtonClickColor = !string.IsNullOrEmpty(rightClickColor) ? rightClickColor : "#0000FF"; + _highlighterRightButtonClickColor = !string.IsNullOrEmpty(rightClickColor) ? rightClickColor : "#a60000FF"; + + string alwaysColor = MouseHighlighterSettingsConfig.Properties.AlwaysColor.Value; + _highlighterAlwaysColor = !string.IsNullOrEmpty(alwaysColor) ? alwaysColor : "#00FF0000"; - _highlighterOpacity = MouseHighlighterSettingsConfig.Properties.HighlightOpacity.Value; _highlighterRadius = MouseHighlighterSettingsConfig.Properties.HighlightRadius.Value; _highlightFadeDelayMs = MouseHighlighterSettingsConfig.Properties.HighlightFadeDelayMs.Value; _highlightFadeDurationMs = MouseHighlighterSettingsConfig.Properties.HighlightFadeDurationMs.Value; @@ -445,7 +447,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels set { - value = SettingsUtilities.ToRGBHex(value); + value = SettingsUtilities.ToARGBHex(value); if (!value.Equals(_highlighterLeftButtonClickColor, StringComparison.OrdinalIgnoreCase)) { _highlighterLeftButtonClickColor = value; @@ -464,7 +466,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels set { - value = SettingsUtilities.ToRGBHex(value); + value = SettingsUtilities.ToARGBHex(value); if (!value.Equals(_highlighterRightButtonClickColor, StringComparison.OrdinalIgnoreCase)) { _highlighterRightButtonClickColor = value; @@ -474,19 +476,20 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } } - public int MouseHighlighterOpacity + public string MouseHighlighterAlwaysColor { get { - return _highlighterOpacity; + return _highlighterAlwaysColor; } set { - if (value != _highlighterOpacity) + value = SettingsUtilities.ToARGBHex(value); + if (!value.Equals(_highlighterAlwaysColor, StringComparison.OrdinalIgnoreCase)) { - _highlighterOpacity = value; - MouseHighlighterSettingsConfig.Properties.HighlightOpacity.Value = value; + _highlighterAlwaysColor = value; + MouseHighlighterSettingsConfig.Properties.AlwaysColor.Value = value; NotifyMouseHighlighterPropertyChanged(); } } @@ -889,7 +892,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels private bool _isMouseHighlighterEnabled; private string _highlighterLeftButtonClickColor; private string _highlighterRightButtonClickColor; - private int _highlighterOpacity; + private string _highlighterAlwaysColor; private int _highlighterRadius; private int _highlightFadeDelayMs; private int _highlightFadeDurationMs;