[MouseHighlighter]Add always-on pointer (#27186)

* [MouseHighlighter]Add always pointer

Make color pick UI ARGB
Delete Opacity setting

* Fix opacity and color

Fix "always color" incorrectly initialized
Revert default opacity to 65%, which was unintentionally lowered to 25% when
changing to percent

* Fix crash when opening MouseUtils settings page

Migration code was bugged, made malformed json and led to settings page crash.

* Implement migration in module side
This commit is contained in:
hayatogh 2023-07-26 23:48:00 +09:00 committed by GitHub
parent a99b2e0bc0
commit a71411d931
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 331 additions and 74 deletions

View File

@ -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;
}

View File

@ -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<float>(pt.x), static_cast<float>(pt.y )});
circleShape.Offset({ static_cast<float>(pt.x), static_cast<float>(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<float>(pt.x), static_cast<float>(pt.y )});
m_leftPointer.Offset({ static_cast<float>(pt.x), static_cast<float>(pt.y) });
}
else if (button == MouseButton::Right)
{
m_rightPointer.Offset({ static_cast<float>(pt.x), static_cast<float>(pt.y) });
}
else
{
//right
m_rightPointer.Offset({ static_cast<float>(pt.x), static_cast<float>(pt.y )});
// always
m_alwaysPointer.Offset({ static_cast<float>(pt.x), static_cast<float>(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<winrt::Windows::UI::Composition::CompositionColorBrush>().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()

View File

@ -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;

View File

@ -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<int>(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<int>(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();
}
}

View File

@ -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";
}
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -0,0 +1,42 @@
<UserControl
x:Class="Microsoft.PowerToys.Settings.UI.Controls.AlphaColorPickerButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<Grid>
<!--TODO(stefan): ToDisplayName is no longer available in ColorHelper
<DropDownButton Padding="4,4,8,4" AutomationProperties.FullDescription="{x:Bind clr:ColorHelper.ToDisplayName(SelectedColor), Mode=OneWay }">
-->
<DropDownButton Padding="4,4,8,4">
<Border
x:Name="ColorPreviewBorder"
Width="48"
Height="24"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{ThemeResource ControlCornerRadius}">
<Border.Background>
<SolidColorBrush Color="{x:Bind SelectedColor, Mode=OneWay}" />
</Border.Background>
</Border>
<DropDownButton.Flyout>
<Flyout>
<ColorPicker
IsAlphaEnabled="True"
IsAlphaSliderVisible="True"
IsAlphaTextInputVisible="True"
IsColorChannelTextInputVisible="True"
IsColorSliderVisible="True"
IsHexInputVisible="True"
Color="{x:Bind SelectedColor, Mode=TwoWay}" />
</Flyout>
</DropDownButton.Flyout>
</DropDownButton>
</Grid>
</UserControl>

View File

@ -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;
}
}
}
}

View File

@ -163,17 +163,13 @@
IsEnabled="{x:Bind ViewModel.IsMouseHighlighterEnabled, Mode=OneWay}">
<labs:SettingsExpander.Items>
<labs:SettingsCard x:Uid="MouseUtils_MouseHighlighter_PrimaryButtonClickColor">
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterLeftButtonClickColor, Mode=TwoWay}" />
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterLeftButtonClickColor, Mode=TwoWay}" />
</labs:SettingsCard>
<labs:SettingsCard x:Uid="MouseUtils_MouseHighlighter_SecondaryButtonClickColor">
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterRightButtonClickColor, Mode=TwoWay}" />
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterRightButtonClickColor, Mode=TwoWay}" />
</labs:SettingsCard>
<labs:SettingsCard x:Uid="MouseUtils_MouseHighlighter_HighlightOpacity">
<Slider
MinWidth="{StaticResource SettingActionControlMinWidth}"
Maximum="100"
Minimum="1"
Value="{x:Bind Mode=TwoWay, Path=ViewModel.MouseHighlighterOpacity}" />
<labs:SettingsCard x:Uid="MouseUtils_MouseHighlighter_AlwaysColor">
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterAlwaysColor, Mode=TwoWay}" />
</labs:SettingsCard>
<labs:SettingsCard x:Uid="MouseUtils_MouseHighlighter_HighlightRadius">
<NumberBox

View File

@ -2601,9 +2601,6 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
<data name="MouseUtils_MouseHighlighter_SecondaryButtonClickColor.Header" xml:space="preserve">
<value>Secondary button highlight color</value>
</data>
<data name="MouseUtils_MouseHighlighter_HighlightOpacity.Header" xml:space="preserve">
<value>Opacity (%)</value>
</data>
<data name="MouseUtils_MouseHighlighter_HighlightRadius.Header" xml:space="preserve">
<value>Radius (px)</value>
<comment>px = pixels</comment>
@ -3590,6 +3587,9 @@ Activate by holding the key for the character you want to add an accent to, then
<data name="Hosts_Encoding_Utf8Bom.Content" xml:space="preserve">
<value>UTF-8 with BOM</value>
</data>
<data name="MouseUtils_MouseHighlighter_AlwaysColor.Header" xml:space="preserve">
<value>Always highlight color</value>
</data>
<data name="MouseUtils_MousePointerCrosshairs_CrosshairsAutoHide.Content" xml:space="preserve">
<value>Automatically hide crosshairs when the mouse pointer is hidden</value>
</data>

View File

@ -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;