mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-11 05:52:19 +02:00
Mouse highlighter: support a spotlight mode - inner transparent, out a backdrop (#40043)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] **Closes:** #15512 - [x] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [x] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed https://github.com/user-attachments/assets/0748c526-fcf5-4859-b832-14a413d2cad1
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "MouseHighlighter.h"
|
#include "MouseHighlighter.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#ifdef COMPOSITION
|
#ifdef COMPOSITION
|
||||||
namespace winrt
|
namespace winrt
|
||||||
@@ -43,7 +44,7 @@ private:
|
|||||||
void AddDrawingPoint(MouseButton button);
|
void AddDrawingPoint(MouseButton button);
|
||||||
void UpdateDrawingPointPosition(MouseButton button);
|
void UpdateDrawingPointPosition(MouseButton button);
|
||||||
void StartDrawingPointFading(MouseButton button);
|
void StartDrawingPointFading(MouseButton button);
|
||||||
void ClearDrawingPoint(MouseButton button);
|
void ClearDrawingPoint();
|
||||||
void ClearDrawing();
|
void ClearDrawing();
|
||||||
void BringToFront();
|
void BringToFront();
|
||||||
HHOOK m_mouseHook = NULL;
|
HHOOK m_mouseHook = NULL;
|
||||||
@@ -66,10 +67,12 @@ private:
|
|||||||
winrt::CompositionSpriteShape m_leftPointer{ nullptr };
|
winrt::CompositionSpriteShape m_leftPointer{ nullptr };
|
||||||
winrt::CompositionSpriteShape m_rightPointer{ nullptr };
|
winrt::CompositionSpriteShape m_rightPointer{ nullptr };
|
||||||
winrt::CompositionSpriteShape m_alwaysPointer{ nullptr };
|
winrt::CompositionSpriteShape m_alwaysPointer{ nullptr };
|
||||||
|
winrt::CompositionSpriteShape m_spotlightPointer{ nullptr };
|
||||||
|
|
||||||
bool m_leftPointerEnabled = true;
|
bool m_leftPointerEnabled = true;
|
||||||
bool m_rightPointerEnabled = true;
|
bool m_rightPointerEnabled = true;
|
||||||
bool m_alwaysPointerEnabled = true;
|
bool m_alwaysPointerEnabled = true;
|
||||||
|
bool m_spotlightMode = false;
|
||||||
|
|
||||||
bool m_leftButtonPressed = false;
|
bool m_leftButtonPressed = false;
|
||||||
bool m_rightButtonPressed = false;
|
bool m_rightButtonPressed = false;
|
||||||
@@ -95,8 +98,7 @@ bool Highlighter::CreateHighlighter()
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// We need a dispatcher queue.
|
// We need a dispatcher queue.
|
||||||
DispatcherQueueOptions options =
|
DispatcherQueueOptions options = {
|
||||||
{
|
|
||||||
sizeof(options),
|
sizeof(options),
|
||||||
DQTYPE_THREAD_CURRENT,
|
DQTYPE_THREAD_CURRENT,
|
||||||
DQTAT_COM_ASTA,
|
DQTAT_COM_ASTA,
|
||||||
@@ -122,7 +124,8 @@ bool Highlighter::CreateHighlighter()
|
|||||||
m_root.Children().InsertAtTop(m_shape);
|
m_root.Children().InsertAtTop(m_shape);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (...)
|
}
|
||||||
|
catch (...)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -130,6 +133,9 @@ bool Highlighter::CreateHighlighter()
|
|||||||
|
|
||||||
void Highlighter::AddDrawingPoint(MouseButton button)
|
void Highlighter::AddDrawingPoint(MouseButton button)
|
||||||
{
|
{
|
||||||
|
if (!m_compositor)
|
||||||
|
return;
|
||||||
|
|
||||||
POINT pt;
|
POINT pt;
|
||||||
|
|
||||||
// Applies DPIs.
|
// Applies DPIs.
|
||||||
@@ -141,6 +147,7 @@ void Highlighter::AddDrawingPoint(MouseButton button)
|
|||||||
// Create circle and add it.
|
// Create circle and add it.
|
||||||
auto circleGeometry = m_compositor.CreateEllipseGeometry();
|
auto circleGeometry = m_compositor.CreateEllipseGeometry();
|
||||||
circleGeometry.Radius({ m_radius, m_radius });
|
circleGeometry.Radius({ m_radius, m_radius });
|
||||||
|
|
||||||
auto circleShape = m_compositor.CreateSpriteShape(circleGeometry);
|
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)
|
if (button == MouseButton::Left)
|
||||||
@@ -156,9 +163,22 @@ void Highlighter::AddDrawingPoint(MouseButton button)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// always
|
// always
|
||||||
circleShape.FillBrush(m_compositor.CreateColorBrush(m_alwaysColor));
|
if (m_spotlightMode)
|
||||||
m_alwaysPointer = circleShape;
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_shape.Shapes().Append(circleShape);
|
m_shape.Shapes().Append(circleShape);
|
||||||
|
|
||||||
// TODO: We're leaking shapes for long drawing sessions.
|
// TODO: We're leaking shapes for long drawing sessions.
|
||||||
@@ -190,7 +210,20 @@ void Highlighter::UpdateDrawingPointPosition(MouseButton button)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// always
|
// always
|
||||||
m_alwaysPointer.Offset({ static_cast<float>(pt.x), static_cast<float>(pt.y) });
|
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) });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Highlighter::StartDrawingPointFading(MouseButton button)
|
void Highlighter::StartDrawingPointFading(MouseButton button)
|
||||||
@@ -229,20 +262,22 @@ void Highlighter::StartDrawingPointFading(MouseButton button)
|
|||||||
circleShape.FillBrush().StartAnimation(L"Color", animation);
|
circleShape.FillBrush().StartAnimation(L"Color", animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Highlighter::ClearDrawingPoint(MouseButton _button)
|
void Highlighter::ClearDrawingPoint()
|
||||||
{
|
{
|
||||||
winrt::Windows::UI::Composition::CompositionSpriteShape circleShape{ nullptr };
|
if (m_spotlightMode)
|
||||||
|
|
||||||
if (nullptr == m_alwaysPointer)
|
|
||||||
{
|
{
|
||||||
// Guard against alwaysPointer not being initialized.
|
if (m_spotlightPointer)
|
||||||
return;
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
void Highlighter::ClearDrawing()
|
||||||
@@ -269,13 +304,14 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa
|
|||||||
if (instance->m_alwaysPointerEnabled && !instance->m_rightButtonPressed)
|
if (instance->m_alwaysPointerEnabled && !instance->m_rightButtonPressed)
|
||||||
{
|
{
|
||||||
// Clear AlwaysPointer only when it's enabled and RightPointer is not active
|
// Clear AlwaysPointer only when it's enabled and RightPointer is not active
|
||||||
instance->ClearDrawingPoint(MouseButton::None);
|
instance->ClearDrawingPoint();
|
||||||
}
|
}
|
||||||
if (instance->m_leftButtonPressed)
|
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.
|
// 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->StartDrawingPointFading(MouseButton::Left);
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->AddDrawingPoint(MouseButton::Left);
|
instance->AddDrawingPoint(MouseButton::Left);
|
||||||
instance->m_leftButtonPressed = true;
|
instance->m_leftButtonPressed = true;
|
||||||
// start a timer for the scenario, when the user clicks a pinned window which has no focus.
|
// start a timer for the scenario, when the user clicks a pinned window which has no focus.
|
||||||
@@ -293,7 +329,7 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa
|
|||||||
if (instance->m_alwaysPointerEnabled && !instance->m_leftButtonPressed)
|
if (instance->m_alwaysPointerEnabled && !instance->m_leftButtonPressed)
|
||||||
{
|
{
|
||||||
// Clear AlwaysPointer only when it's enabled and LeftPointer is not active
|
// Clear AlwaysPointer only when it's enabled and LeftPointer is not active
|
||||||
instance->ClearDrawingPoint(MouseButton::None);
|
instance->ClearDrawingPoint();
|
||||||
}
|
}
|
||||||
if (instance->m_rightButtonPressed)
|
if (instance->m_rightButtonPressed)
|
||||||
{
|
{
|
||||||
@@ -358,13 +394,21 @@ void Highlighter::StartDrawing()
|
|||||||
{
|
{
|
||||||
Logger::info("Starting draw mode.");
|
Logger::info("Starting draw mode.");
|
||||||
Trace::StartHighlightingSession();
|
Trace::StartHighlightingSession();
|
||||||
|
|
||||||
|
if (m_spotlightMode && m_alwaysColor.A != 0)
|
||||||
|
{
|
||||||
|
Trace::StartSpotlightSession();
|
||||||
|
}
|
||||||
|
|
||||||
m_visible = true;
|
m_visible = true;
|
||||||
|
|
||||||
// HACK: Draw with 1 pixel off. Otherwise Windows glitches the task bar transparency when a transparent window fill the whole screen.
|
// 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);
|
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN) + 1, GetSystemMetrics(SM_YVIRTUALSCREEN) + 1, GetSystemMetrics(SM_CXVIRTUALSCREEN) - 2, GetSystemMetrics(SM_CYVIRTUALSCREEN) - 2, 0);
|
||||||
ClearDrawing();
|
ClearDrawing();
|
||||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||||
instance->AddDrawingPoint(MouseButton::None);
|
|
||||||
|
instance->AddDrawingPoint(Highlighter::MouseButton::None);
|
||||||
|
|
||||||
m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0);
|
m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +421,7 @@ void Highlighter::StopDrawing()
|
|||||||
m_leftPointer = nullptr;
|
m_leftPointer = nullptr;
|
||||||
m_rightPointer = nullptr;
|
m_rightPointer = nullptr;
|
||||||
m_alwaysPointer = nullptr;
|
m_alwaysPointer = nullptr;
|
||||||
|
m_spotlightPointer = nullptr;
|
||||||
ShowWindow(m_hwnd, SW_HIDE);
|
ShowWindow(m_hwnd, SW_HIDE);
|
||||||
UnhookWindowsHookEx(m_mouseHook);
|
UnhookWindowsHookEx(m_mouseHook);
|
||||||
ClearDrawing();
|
ClearDrawing();
|
||||||
@@ -388,7 +433,8 @@ void Highlighter::SwitchActivationMode()
|
|||||||
PostMessage(m_hwnd, WM_SWITCH_ACTIVATION_MODE, 0, 0);
|
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_radius = static_cast<float>(settings.radius);
|
||||||
m_fadeDelay_ms = settings.fadeDelayMs;
|
m_fadeDelay_ms = settings.fadeDelayMs;
|
||||||
m_fadeDuration_ms = settings.fadeDurationMs;
|
m_fadeDuration_ms = settings.fadeDurationMs;
|
||||||
@@ -398,9 +444,23 @@ void Highlighter::ApplySettings(MouseHighlighterSettings settings) {
|
|||||||
m_leftPointerEnabled = settings.leftButtonColor.A != 0;
|
m_leftPointerEnabled = settings.leftButtonColor.A != 0;
|
||||||
m_rightPointerEnabled = settings.rightButtonColor.A != 0;
|
m_rightPointerEnabled = settings.rightButtonColor.A != 0;
|
||||||
m_alwaysPointerEnabled = settings.alwaysColor.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.
|
// 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);
|
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN) + 1, GetSystemMetrics(SM_YVIRTUALSCREEN) + 1, GetSystemMetrics(SM_CXVIRTUALSCREEN) - 2, GetSystemMetrics(SM_CYVIRTUALSCREEN) - 2, 0);
|
||||||
}
|
}
|
||||||
@@ -488,8 +548,7 @@ bool Highlighter::MyRegisterClass(HINSTANCE hInstance)
|
|||||||
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hInstance, nullptr);
|
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;
|
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOOLWINDOW;
|
||||||
return CreateWindowExW(exStyle, m_className, m_windowTitle, WS_POPUP,
|
return CreateWindowExW(exStyle, m_className, m_windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hInstance, nullptr) != nullptr;
|
||||||
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hInstance, nullptr) != nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Highlighter::Terminate()
|
void Highlighter::Terminate()
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ struct MouseHighlighterSettings
|
|||||||
int fadeDelayMs = MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS;
|
int fadeDelayMs = MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS;
|
||||||
int fadeDurationMs = MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS;
|
int fadeDurationMs = MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS;
|
||||||
bool autoActivate = MOUSE_HIGHLIGHTER_DEFAULT_AUTO_ACTIVATE;
|
bool autoActivate = MOUSE_HIGHLIGHTER_DEFAULT_AUTO_ACTIVATE;
|
||||||
|
bool spotlightMode = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
int MouseHighlighterMain(HINSTANCE hinst, MouseHighlighterSettings settings);
|
int MouseHighlighterMain(HINSTANCE hinst, MouseHighlighterSettings settings);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ namespace
|
|||||||
const wchar_t JSON_KEY_HIGHLIGHT_FADE_DELAY_MS[] = L"highlight_fade_delay_ms";
|
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_HIGHLIGHT_FADE_DURATION_MS[] = L"highlight_fade_duration_ms";
|
||||||
const wchar_t JSON_KEY_AUTO_ACTIVATE[] = L"auto_activate";
|
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;
|
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||||
@@ -367,6 +368,16 @@ public:
|
|||||||
{
|
{
|
||||||
Logger::warn("Failed to initialize auto activate from settings. Will use default value");
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,3 +30,13 @@ void Trace::StartHighlightingSession() noexcept
|
|||||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
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));
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,4 +10,7 @@ public:
|
|||||||
|
|
||||||
// Log that the user activated the module by starting a highlighting session
|
// Log that the user activated the module by starting a highlighting session
|
||||||
static void StartHighlightingSession() noexcept;
|
static void StartHighlightingSession() noexcept;
|
||||||
|
|
||||||
|
// Log that spotlight mode is enabled
|
||||||
|
static void StartSpotlightSession() noexcept;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
[JsonPropertyName("auto_activate")]
|
[JsonPropertyName("auto_activate")]
|
||||||
public BoolProperty AutoActivate { get; set; }
|
public BoolProperty AutoActivate { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("spotlight_mode")]
|
||||||
|
public BoolProperty SpotlightMode { get; set; }
|
||||||
|
|
||||||
public MouseHighlighterProperties()
|
public MouseHighlighterProperties()
|
||||||
{
|
{
|
||||||
ActivationShortcut = DefaultActivationShortcut;
|
ActivationShortcut = DefaultActivationShortcut;
|
||||||
@@ -52,6 +55,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
HighlightFadeDelayMs = new IntProperty(500);
|
HighlightFadeDelayMs = new IntProperty(500);
|
||||||
HighlightFadeDurationMs = new IntProperty(250);
|
HighlightFadeDurationMs = new IntProperty(250);
|
||||||
AutoActivate = new BoolProperty(false);
|
AutoActivate = new BoolProperty(false);
|
||||||
|
SpotlightMode = new BoolProperty(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,15 +214,24 @@
|
|||||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||||
IsEnabled="{x:Bind ViewModel.IsMouseHighlighterEnabled, Mode=OneWay}">
|
IsEnabled="{x:Bind ViewModel.IsMouseHighlighterEnabled, Mode=OneWay}">
|
||||||
<tkcontrols:SettingsExpander.Items>
|
<tkcontrols:SettingsExpander.Items>
|
||||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_PrimaryButtonClickColor">
|
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_PrimaryButtonClickColor" IsEnabled="{x:Bind ViewModel.IsSpotlightModeEnabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||||
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterLeftButtonClickColor, Mode=TwoWay}" />
|
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterLeftButtonClickColor, Mode=TwoWay}" />
|
||||||
</tkcontrols:SettingsCard>
|
</tkcontrols:SettingsCard>
|
||||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_SecondaryButtonClickColor">
|
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_SecondaryButtonClickColor" IsEnabled="{x:Bind ViewModel.IsSpotlightModeEnabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||||
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterRightButtonClickColor, Mode=TwoWay}" />
|
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterRightButtonClickColor, Mode=TwoWay}" />
|
||||||
</tkcontrols:SettingsCard>
|
</tkcontrols:SettingsCard>
|
||||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_AlwaysColor">
|
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_AlwaysColor">
|
||||||
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterAlwaysColor, Mode=TwoWay}" />
|
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterAlwaysColor, Mode=TwoWay}" />
|
||||||
</tkcontrols:SettingsCard>
|
</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">
|
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_HighlightRadius">
|
||||||
<NumberBox
|
<NumberBox
|
||||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||||
|
|||||||
@@ -5068,4 +5068,16 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
|||||||
<data name="BugReportUnderConstruction" xml:space="preserve">
|
<data name="BugReportUnderConstruction" xml:space="preserve">
|
||||||
<value>Bug report package is being created</value>
|
<value>Bug report package is being created</value>
|
||||||
</data>
|
</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>
|
</root>
|
||||||
@@ -72,6 +72,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
string alwaysColor = MouseHighlighterSettingsConfig.Properties.AlwaysColor.Value;
|
string alwaysColor = MouseHighlighterSettingsConfig.Properties.AlwaysColor.Value;
|
||||||
_highlighterAlwaysColor = !string.IsNullOrEmpty(alwaysColor) ? alwaysColor : "#00FF0000";
|
_highlighterAlwaysColor = !string.IsNullOrEmpty(alwaysColor) ? alwaysColor : "#00FF0000";
|
||||||
|
_isSpotlightModeEnabled = MouseHighlighterSettingsConfig.Properties.SpotlightMode.Value;
|
||||||
|
|
||||||
_highlighterRadius = MouseHighlighterSettingsConfig.Properties.HighlightRadius.Value;
|
_highlighterRadius = MouseHighlighterSettingsConfig.Properties.HighlightRadius.Value;
|
||||||
_highlightFadeDelayMs = MouseHighlighterSettingsConfig.Properties.HighlightFadeDelayMs.Value;
|
_highlightFadeDelayMs = MouseHighlighterSettingsConfig.Properties.HighlightFadeDelayMs.Value;
|
||||||
@@ -560,6 +561,20 @@ 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
|
public int MouseHighlighterRadius
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -916,6 +931,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
private string _highlighterLeftButtonClickColor;
|
private string _highlighterLeftButtonClickColor;
|
||||||
private string _highlighterRightButtonClickColor;
|
private string _highlighterRightButtonClickColor;
|
||||||
private string _highlighterAlwaysColor;
|
private string _highlighterAlwaysColor;
|
||||||
|
private bool _isSpotlightModeEnabled;
|
||||||
private int _highlighterRadius;
|
private int _highlighterRadius;
|
||||||
private int _highlightFadeDelayMs;
|
private int _highlightFadeDelayMs;
|
||||||
private int _highlightFadeDurationMs;
|
private int _highlightFadeDurationMs;
|
||||||
|
|||||||
Reference in New Issue
Block a user