diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index f202cf06c6..b273d11b1d 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -918,6 +918,7 @@ LWA lwin LZero MAGTRANSFORM +MAJORMINOR MAKEINTRESOURCE MAKEINTRESOURCEA MAKEINTRESOURCEW @@ -996,6 +997,9 @@ mousepointercrosshairs mouseutils MOVESIZEEND MOVESIZESTART +muxx +muxxc +muxxh MRM MRT mru @@ -1807,6 +1811,7 @@ ULONGLONG ums uncompilable UNCPRIORITY +undefining UNDNAME UNICODETEXT unins diff --git a/Directory.Build.props b/Directory.Build.props index 4184a8f2a3..e7b415cbca 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -30,7 +30,6 @@ <_PropertySheetDisplayName>PowerToys.Root.Props $(MsbuildThisFileDirectory)\Cpp.Build.props - all diff --git a/Directory.Build.targets b/Directory.Build.targets index cba7762d5f..6da66bc8a8 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -3,4 +3,9 @@ + + + + $(WindowsSdkDir)bin\x64\mt.exe + \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props index 23dac30258..e355bf6d7c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -37,6 +37,7 @@ + diff --git a/nuget.config b/nuget.config index 51f9b3b3f7..6b8d13a023 100644 --- a/nuget.config +++ b/nuget.config @@ -9,4 +9,4 @@ - + \ No newline at end of file diff --git a/src/modules/MouseUtils/FindMyMouse/FindMyMouse.cpp b/src/modules/MouseUtils/FindMyMouse/FindMyMouse.cpp index 3049d3740c..adf5075837 100644 --- a/src/modules/MouseUtils/FindMyMouse/FindMyMouse.cpp +++ b/src/modules/MouseUtils/FindMyMouse/FindMyMouse.cpp @@ -8,21 +8,28 @@ #include "common/utils/process_path.h" #include "common/utils/excluded_apps.h" #include "common/utils/MsWindowsSettings.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + #include -#ifdef COMPOSITION namespace winrt { using namespace winrt::Windows::System; - using namespace winrt::Windows::UI::Composition; } -namespace ABI -{ - using namespace ABI::Windows::System; - using namespace ABI::Windows::UI::Composition::Desktop; -} -#endif +namespace muxc = winrt::Microsoft::UI::Composition; +namespace muxx = winrt::Microsoft::UI::Xaml; +namespace muxxc = winrt::Microsoft::UI::Xaml::Controls; +namespace muxxh = winrt::Microsoft::UI::Xaml::Hosting; #pragma region Super_Sonar_Base_Code @@ -70,11 +77,11 @@ protected: int m_sonarRadius = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS; int m_sonarZoomFactor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM; DWORD m_fadeDuration = FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS; - int m_finalAlphaNumerator = FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY; + int m_finalAlphaNumerator = 100; // legacy (root now always animates to 1.0; kept for GDI fallback compatibility) std::vector m_excludedApps; int m_shakeMinimumDistance = FIND_MY_MOUSE_DEFAULT_SHAKE_MINIMUM_DISTANCE; static constexpr int FinalAlphaDenominator = 100; - winrt::DispatcherQueueController m_dispatcherQueueController{ nullptr }; + winrt::Microsoft::UI::Dispatching::DispatcherQueueController m_dispatcherQueueController{ nullptr }; // Don't consider movements started past these milliseconds to detect shaking. int m_shakeIntervalMs = FIND_MY_MOUSE_DEFAULT_SHAKE_INTERVAL_MS; @@ -82,7 +89,6 @@ protected: int m_shakeFactor = FIND_MY_MOUSE_DEFAULT_SHAKE_FACTOR; private: - // Save the mouse movement that occurred in any direction. struct PointerRecentMovement { @@ -159,7 +165,6 @@ bool SuperSonar::Initialize(HINSTANCE hinst) SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); WNDCLASS wc{}; - if (!GetClassInfoW(hinst, className, &wc)) { wc.lpfnWndProc = s_WndProc; @@ -171,14 +176,28 @@ bool SuperSonar::Initialize(HINSTANCE hinst) if (!RegisterClassW(&wc)) { + Logger::error("RegisterClassW failed. GetLastError={}", GetLastError()); return false; } } + // else: class already registered m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinst, nullptr); + if (!m_hwndOwner) + { + Logger::error("Failed to create owner window. GetLastError={}", GetLastError()); + return false; + } - DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW | Shim()->GetExtendedStyle(); - return CreateWindowExW(exStyle, className, windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hinst, this) != nullptr; + DWORD exStyle = WS_EX_TOOLWINDOW | Shim()->GetExtendedStyle(); + HWND created = CreateWindowExW(exStyle, className, windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hinst, this); + if (!created) + { + Logger::error("CreateWindowExW failed. GetLastError={}", GetLastError()); + return false; + } + + return true; } template @@ -226,7 +245,8 @@ LRESULT SuperSonar::BaseWndProc(UINT message, WPARAM wParam, LPARAM lParam) n switch (message) { case WM_CREATE: - if(!OnSonarCreate()) return -1; + if (!OnSonarCreate()) + return -1; UpdateMouseSnooping(); return 0; @@ -314,8 +334,7 @@ void SuperSonar::OnSonarKeyboardInput(RAWINPUT const& input) return; } - if ((m_activationMethod != FindMyMouseActivationMethod::DoubleRightControlKey && m_activationMethod != FindMyMouseActivationMethod::DoubleLeftControlKey) - || input.data.keyboard.VKey != VK_CONTROL) + if ((m_activationMethod != FindMyMouseActivationMethod::DoubleRightControlKey && m_activationMethod != FindMyMouseActivationMethod::DoubleLeftControlKey) || input.data.keyboard.VKey != VK_CONTROL) { StopSonar(); return; @@ -326,8 +345,7 @@ void SuperSonar::OnSonarKeyboardInput(RAWINPUT const& input) bool leftCtrlPressed = (input.data.keyboard.Flags & RI_KEY_E0) == 0; bool rightCtrlPressed = (input.data.keyboard.Flags & RI_KEY_E0) != 0; - if ((m_activationMethod == FindMyMouseActivationMethod::DoubleRightControlKey && !rightCtrlPressed) - || (m_activationMethod == FindMyMouseActivationMethod::DoubleLeftControlKey && !leftCtrlPressed)) + if ((m_activationMethod == FindMyMouseActivationMethod::DoubleRightControlKey && !rightCtrlPressed) || (m_activationMethod == FindMyMouseActivationMethod::DoubleLeftControlKey && !leftCtrlPressed)) { StopSonar(); return; @@ -376,7 +394,6 @@ void SuperSonar::OnSonarKeyboardInput(RAWINPUT const& input) GetCursorPos(&m_lastKeyPos); UpdateMouseSnooping(); } - Logger::info("Detecting double left control click with {} ms interval.", doubleClickInterval); m_lastKeyTime = now; m_lastKeyPos = ptCursor; } @@ -402,14 +419,13 @@ template void SuperSonar::DetectShake() { ULONGLONG shakeStartTick = GetTickCount64() - m_shakeIntervalMs; - + // Prune the story of movements for those movements that started too long ago. std::erase_if(m_movementHistory, [shakeStartTick](const PointerRecentMovement& movement) { return movement.tick < shakeStartTick; }); - - + double distanceTravelled = 0; - LONGLONG currentX=0, minX=0, maxX=0; - LONGLONG currentY=0, minY=0, maxY=0; + LONGLONG currentX = 0, minX = 0, maxX = 0; + LONGLONG currentY = 0, minY = 0, maxY = 0; for (const PointerRecentMovement& movement : m_movementHistory) { @@ -421,23 +437,22 @@ void SuperSonar::DetectShake() minY = min(currentY, minY); maxY = max(currentY, maxY); } - + if (distanceTravelled < m_shakeMinimumDistance) { return; } // Size of the rectangle that the pointer moved in. - double rectangleWidth = static_cast(maxX) - minX; - double rectangleHeight = static_cast(maxY) - minY; + double rectangleWidth = static_cast(maxX) - minX; + double rectangleHeight = static_cast(maxY) - minY; double diagonal = sqrt(rectangleWidth * rectangleWidth + rectangleHeight * rectangleHeight); - if (diagonal > 0 && distanceTravelled / diagonal > (m_shakeFactor/100.f)) + if (diagonal > 0 && distanceTravelled / diagonal > (m_shakeFactor / 100.f)) { m_movementHistory.clear(); StartSonar(); } - } template @@ -453,7 +468,7 @@ void SuperSonar::OnSonarMouseInput(RAWINPUT const& input) { LONG relativeX = 0; LONG relativeY = 0; - if ((input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) == MOUSE_MOVE_ABSOLUTE && (input.data.mouse.lLastX!=0 || input.data.mouse.lLastY!=0)) + if ((input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) == MOUSE_MOVE_ABSOLUTE && (input.data.mouse.lLastX != 0 || input.data.mouse.lLastY != 0)) { // Getting absolute mouse coordinates. Likely inside a VM / RDP session. if (m_seenAnAbsoluteMousePosition) @@ -482,7 +497,7 @@ void SuperSonar::OnSonarMouseInput(RAWINPUT const& input) } else { - m_movementHistory.push_back({ .diff = { .x=relativeX, .y=relativeY }, .tick = GetTickCount64() }); + m_movementHistory.push_back({ .diff = { .x = relativeX, .y = relativeY }, .tick = GetTickCount64() }); // Mouse movement changed directions. Take the opportunity do detect shake. DetectShake(); } @@ -491,7 +506,6 @@ void SuperSonar::OnSonarMouseInput(RAWINPUT const& input) { m_movementHistory.push_back({ .diff = { .x = relativeX, .y = relativeY }, .tick = GetTickCount64() }); } - } if (input.data.mouse.usButtonFlags) @@ -518,7 +532,6 @@ void SuperSonar::StartSonar() return; } - Logger::info("Focusing the sonar on the mouse cursor."); Trace::MousePointerFocused(); // Cover the entire virtual screen. // HACK: Draw with 1 pixel off. Otherwise, Windows glitches the task bar transparency when a transparent window fill the whole screen. @@ -633,12 +646,26 @@ struct CompositionSpotlight : SuperSonar DWORD GetExtendedStyle() { - return WS_EX_NOREDIRECTIONBITMAP; + // Remove WS_EX_NOREDIRECTIONBITMAP for Composition/XAML to allow DWM redirection. + return 0; } void AfterMoveSonar() { - m_spotlight.Offset({ static_cast(m_sonarPos.x), static_cast(m_sonarPos.y), 0.0f }); + const float scale = static_cast(m_surface.XamlRoot().RasterizationScale()); + // Move gradient center + if (m_spotlightMaskGradient) + { + m_spotlightMaskGradient.EllipseCenter({ static_cast(m_sonarPos.x) / scale, + static_cast(m_sonarPos.y) / scale }); + } + // Move spotlight visual (color fill) below masked backdrop + if (m_spotlight) + { + m_spotlight.Offset({ static_cast(m_sonarPos.x) / scale, + static_cast(m_sonarPos.y) / scale, + 0.0f }); + } } LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept @@ -646,24 +673,29 @@ struct CompositionSpotlight : SuperSonar switch (message) { case WM_CREATE: - return OnCompositionCreate() && BaseWndProc(message, wParam, lParam); + if (!OnCompositionCreate()) + return -1; + return BaseWndProc(message, wParam, lParam); case WM_OPACITY_ANIMATION_COMPLETED: OnOpacityAnimationCompleted(); break; + case WM_SIZE: + UpdateIslandSize(); + break; } return BaseWndProc(message, wParam, lParam); } void SetSonarVisibility(bool visible) { - m_batch = m_compositor.GetCommitBatch(winrt::CompositionBatchTypes::Animation); + m_batch = m_compositor.GetCommitBatch(muxc::CompositionBatchTypes::Animation); BOOL isEnabledAnimations = GetAnimationsEnabled(); m_animation.Duration(std::chrono::milliseconds{ isEnabledAnimations ? m_fadeDuration : 1 }); m_batch.Completed([hwnd = m_hwnd](auto&&, auto&&) { PostMessage(hwnd, WM_OPACITY_ANIMATION_COMPLETED, 0, 0); }); - m_root.Opacity(visible ? static_cast(m_finalAlphaNumerator) / FinalAlphaDenominator : 0.0f); + m_root.Opacity(visible ? 1.0f : 0.0f); if (visible) { ShowWindow(m_hwnd, SW_SHOWNOACTIVATE); @@ -679,54 +711,138 @@ private: bool OnCompositionCreate() try { - // We need a dispatcher queue. - DispatcherQueueOptions options = { - sizeof(options), - DQTYPE_THREAD_CURRENT, - DQTAT_COM_ASTA, - }; - ABI::IDispatcherQueueController* controller; - winrt::check_hresult(CreateDispatcherQueueController(options, &controller)); - *winrt::put_abi(m_dispatcherQueueController) = controller; + // Creating composition resources + // Ensure a DispatcherQueue bound to this thread (required by WinAppSDK composition/XAML) + if (!m_dispatcherQueueController) + { + // Ensure COM is initialized + try + { + winrt::init_apartment(winrt::apartment_type::single_threaded); + // COM STA initialized + } + catch (const winrt::hresult_error& e) + { + Logger::error("Failed to initialize COM apartment: {}", winrt::to_string(e.message())); + return false; + } - // Create the compositor for our window. - m_compositor = winrt::Compositor(); - ABI::IDesktopWindowTarget* target; - winrt::check_hresult(m_compositor.as()->CreateDesktopWindowTarget(m_hwnd, false, &target)); - *winrt::put_abi(m_target) = target; + try + { + m_dispatcherQueueController = + winrt::Microsoft::UI::Dispatching::DispatcherQueueController::CreateOnCurrentThread(); + // DispatcherQueueController created + } + catch (const winrt::hresult_error& e) + { + Logger::error("Failed to create DispatcherQueueController: {}", winrt::to_string(e.message())); + return false; + } + } - // Our composition tree: + // 1) Create a XAML island and attach it to this HWND + try + { + m_island = winrt::Microsoft::UI::Xaml::Hosting::DesktopWindowXamlSource{}; + auto windowId = winrt::Microsoft::UI::GetWindowIdFromWindow(m_hwnd); + m_island.Initialize(windowId); + // Xaml source initialized + } + catch (const winrt::hresult_error& e) + { + Logger::error("Failed to create XAML island: {}", winrt::to_string(e.message())); + return false; + } + + UpdateIslandSize(); + // Island size set + + // 2) Create a XAML container to host the Composition child visual + m_surface = winrt::Microsoft::UI::Xaml::Controls::Grid{}; + + // A transparent background keeps hit-testing consistent vs. null brush + m_surface.Background(winrt::Microsoft::UI::Xaml::Media::SolidColorBrush{ + winrt::Microsoft::UI::Colors::Transparent() }); + m_surface.HorizontalAlignment(muxx::HorizontalAlignment::Stretch); + m_surface.VerticalAlignment(muxx::VerticalAlignment::Stretch); + + m_island.Content(m_surface); + + // 3) Get the compositor from the XAML visual tree (pure MUXC path) + try + { + auto elementVisual = + winrt::Microsoft::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(m_surface); + m_compositor = elementVisual.Compositor(); + // Compositor acquired + } + catch (const winrt::hresult_error& e) + { + Logger::error("Failed to get compositor: {}", winrt::to_string(e.message())); + return false; + } + + // 4) Build the composition tree // - // [root] ContainerVisual - // \ LayerVisual - // \[gray backdrop] - // [spotlight] + // [root] ContainerVisual (fills host) + // \ LayerVisual + // \ [backdrop dim * radial gradient mask (hole)] m_root = m_compositor.CreateContainerVisual(); - m_root.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent + m_root.RelativeSizeAdjustment({ 1.0f, 1.0f }); m_root.Opacity(0.0f); - m_target.Root(m_root); + + // Insert our root as a hand-in Visual under the XAML element + winrt::Microsoft::UI::Xaml::Hosting::ElementCompositionPreview::SetElementChildVisual(m_surface, m_root); auto layer = m_compositor.CreateLayerVisual(); - layer.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent + layer.RelativeSizeAdjustment({ 1.0f, 1.0f }); m_root.Children().InsertAtTop(layer); - m_backdrop = m_compositor.CreateSpriteVisual(); - m_backdrop.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent - m_backdrop.Brush(m_compositor.CreateColorBrush(m_backgroundColor)); - layer.Children().InsertAtTop(m_backdrop); + const float scale = static_cast(m_surface.XamlRoot().RasterizationScale()); + const float rDip = m_sonarRadiusFloat / scale; + const float zoom = static_cast(m_sonarZoomFactor); - m_circleGeometry = m_compositor.CreateEllipseGeometry(); // radius set via expression animation + // Spotlight shape (below backdrop, visible through hole) + m_circleGeometry = m_compositor.CreateEllipseGeometry(); m_circleShape = m_compositor.CreateSpriteShape(m_circleGeometry); m_circleShape.FillBrush(m_compositor.CreateColorBrush(m_spotlightColor)); - m_circleShape.Offset({ m_sonarRadiusFloat * m_sonarZoomFactor, m_sonarRadiusFloat * m_sonarZoomFactor }); + m_circleShape.Offset({ rDip * zoom, rDip * zoom }); m_spotlight = m_compositor.CreateShapeVisual(); - m_spotlight.Size({ m_sonarRadiusFloat * 2 * m_sonarZoomFactor, m_sonarRadiusFloat * 2 * m_sonarZoomFactor }); + m_spotlight.Size({ rDip * 2 * zoom, rDip * 2 * zoom }); m_spotlight.AnchorPoint({ 0.5f, 0.5f }); m_spotlight.Shapes().Append(m_circleShape); - layer.Children().InsertAtTop(m_spotlight); - // Implicitly animate the alpha. + // Dim color (source) + m_dimColorBrush = m_compositor.CreateColorBrush(m_backgroundColor); + // Radial gradient mask (center transparent, outer opaque) + m_spotlightMaskGradient = m_compositor.CreateRadialGradientBrush(); + m_spotlightMaskGradient.MappingMode(muxc::CompositionMappingMode::Absolute); + m_maskStopCenter = m_compositor.CreateColorGradientStop(); + m_maskStopCenter.Offset(0.0f); + m_maskStopCenter.Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0)); + m_maskStopInner = m_compositor.CreateColorGradientStop(); + m_maskStopInner.Offset(0.995f); + m_maskStopInner.Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0)); + m_maskStopOuter = m_compositor.CreateColorGradientStop(); + m_maskStopOuter.Offset(1.0f); + m_maskStopOuter.Color(winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 255, 255)); + m_spotlightMaskGradient.ColorStops().Append(m_maskStopCenter); + m_spotlightMaskGradient.ColorStops().Append(m_maskStopInner); + m_spotlightMaskGradient.ColorStops().Append(m_maskStopOuter); + m_spotlightMaskGradient.EllipseCenter({ rDip * zoom, rDip * zoom }); + m_spotlightMaskGradient.EllipseRadius({ rDip * zoom, rDip * zoom }); + + m_maskBrush = m_compositor.CreateMaskBrush(); + m_maskBrush.Source(m_dimColorBrush); + m_maskBrush.Mask(m_spotlightMaskGradient); + + m_backdrop = m_compositor.CreateSpriteVisual(); + m_backdrop.RelativeSizeAdjustment({ 1.0f, 1.0f }); + m_backdrop.Brush(m_maskBrush); + layer.Children().InsertAtTop(m_backdrop); + + // 5) Implicit opacity animation on the root m_animation = m_compositor.CreateScalarKeyFrameAnimation(); m_animation.Target(L"Opacity"); m_animation.InsertExpressionKeyFrame(1.0f, L"this.FinalValue"); @@ -735,20 +851,31 @@ private: collection.Insert(L"Opacity", m_animation); m_root.ImplicitAnimations(collection); - // Radius of spotlight shrinks as opacity increases. - // At opacity zero, it is m_sonarRadius * SonarZoomFactor. - // At maximum opacity, it is m_sonarRadius. + // 6) Spotlight radius shrinks as opacity increases (expression animation) auto radiusExpression = m_compositor.CreateExpressionAnimation(); radiusExpression.SetReferenceParameter(L"Root", m_root); - wchar_t expressionText[256]; - winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius, FinalAlphaDenominator, m_finalAlphaNumerator)); - radiusExpression.Expression(expressionText); - m_circleGeometry.StartAnimation(L"Radius", radiusExpression); + wchar_t expressionText[256]; + winrt::check_hresult(StringCchPrintfW( + expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius)); + + radiusExpression.Expression(expressionText); + m_spotlightMaskGradient.StartAnimation(L"EllipseRadius", radiusExpression); + // Also animate spotlight geometry radius for visual consistency + if (m_circleGeometry) + { + auto radiusExpression2 = m_compositor.CreateExpressionAnimation(); + radiusExpression2.SetReferenceParameter(L"Root", m_root); + radiusExpression2.Expression(expressionText); + m_circleGeometry.StartAnimation(L"Radius", radiusExpression2); + } + + // Composition created successfully return true; } - catch (...) + catch (const winrt::hresult_error& e) { + Logger::error("Failed to create FindMyMouse visual: {}", winrt::to_string(e.message())); return false; } @@ -760,11 +887,27 @@ private: } } + void UpdateIslandSize() + { + if (!m_island) + return; + + RECT rc{}; + if (!GetClientRect(m_hwnd, &rc)) + return; + + const int width = rc.right - rc.left; + const int height = rc.bottom - rc.top; + + auto bridge = m_island.SiteBridge(); + bridge.MoveAndResize(winrt::Windows::Graphics::RectInt32{ 0, 0, width, height }); + } + public: - void ApplySettings(const FindMyMouseSettings& settings, bool applyToRuntimeObjects) { + void ApplySettings(const FindMyMouseSettings& settings, bool applyToRuntimeObjects) + { if (!applyToRuntimeObjects) { - // Runtime objects not created yet. Just update fields. m_sonarRadius = settings.spotlightRadius; m_sonarRadiusFloat = static_cast(m_sonarRadius); m_backgroundColor = settings.backgroundColor; @@ -773,7 +916,6 @@ public: m_includeWinKey = settings.includeWinKey; m_doNotActivateOnGameMode = settings.doNotActivateOnGameMode; m_fadeDuration = settings.animationDurationMs > 0 ? settings.animationDurationMs : 1; - m_finalAlphaNumerator = settings.overlayOpacity; m_sonarZoomFactor = settings.spotlightInitialZoom; m_excludedApps = settings.excludedApps; m_shakeMinimumDistance = settings.shakeMinimumDistance; @@ -782,11 +924,9 @@ public: } else { - // Runtime objects already created. Should update in the owner thread. if (m_dispatcherQueueController == nullptr) { Logger::warn("Tried accessing the dispatch queue controller before it was initialized."); - // No dispatcher Queue Controller? Means initialization still hasn't run, so settings will be applied then. return; } auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue(); @@ -794,7 +934,6 @@ public: bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() { if (!m_destroyed) { - // Runtime objects not created yet. Just update fields. m_sonarRadius = localSettings.spotlightRadius; m_sonarRadiusFloat = static_cast(m_sonarRadius); m_backgroundColor = localSettings.backgroundColor; @@ -803,7 +942,6 @@ public: m_includeWinKey = localSettings.includeWinKey; m_doNotActivateOnGameMode = localSettings.doNotActivateOnGameMode; m_fadeDuration = localSettings.animationDurationMs > 0 ? localSettings.animationDurationMs : 1; - m_finalAlphaNumerator = localSettings.overlayOpacity; m_sonarZoomFactor = localSettings.spotlightInitialZoom; m_excludedApps = localSettings.excludedApps; m_shakeMinimumDistance = localSettings.shakeMinimumDistance; @@ -812,20 +950,41 @@ public: UpdateMouseSnooping(); // For the shake mouse activation method // Apply new settings to runtime composition objects. - m_backdrop.Brush().as().Color(m_backgroundColor); - m_circleShape.FillBrush().as().Color(m_spotlightColor); - m_circleShape.Offset({ m_sonarRadiusFloat * m_sonarZoomFactor, m_sonarRadiusFloat * m_sonarZoomFactor }); - m_spotlight.Size({ m_sonarRadiusFloat * 2 * m_sonarZoomFactor, m_sonarRadiusFloat * 2 * m_sonarZoomFactor }); - m_animation.Duration(std::chrono::milliseconds{ m_fadeDuration }); - m_circleGeometry.StopAnimation(L"Radius"); - - // Update animation + if (m_dimColorBrush) + { + m_dimColorBrush.Color(m_backgroundColor); + } + if (m_circleShape) + { + if (auto brush = m_circleShape.FillBrush().try_as()) + { + brush.Color(m_spotlightColor); + } + } + const float scale = static_cast(m_surface.XamlRoot().RasterizationScale()); + const float rDip = m_sonarRadiusFloat / scale; + const float zoom = static_cast(m_sonarZoomFactor); + m_spotlightMaskGradient.StopAnimation(L"EllipseRadius"); + m_spotlightMaskGradient.EllipseCenter({ rDip * zoom, rDip * zoom }); + if (m_spotlight) + { + m_spotlight.Size({ rDip * 2 * zoom, rDip * 2 * zoom }); + m_circleShape.Offset({ rDip * zoom, rDip * zoom }); + } auto radiusExpression = m_compositor.CreateExpressionAnimation(); radiusExpression.SetReferenceParameter(L"Root", m_root); wchar_t expressionText[256]; - winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius, FinalAlphaDenominator, m_finalAlphaNumerator)); + winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius)); radiusExpression.Expression(expressionText); - m_circleGeometry.StartAnimation(L"Radius", radiusExpression); + m_spotlightMaskGradient.StartAnimation(L"EllipseRadius", radiusExpression); + if (m_circleGeometry) + { + m_circleGeometry.StopAnimation(L"Radius"); + auto radiusExpression2 = m_compositor.CreateExpressionAnimation(); + radiusExpression2.SetReferenceParameter(L"Root", m_root); + radiusExpression2.Expression(expressionText); + m_circleGeometry.StartAnimation(L"Radius", radiusExpression2); + } } }); if (!enqueueSucceeded) @@ -836,17 +995,27 @@ public: } private: - winrt::Compositor m_compositor{ nullptr }; - winrt::Desktop::DesktopWindowTarget m_target{ nullptr }; - winrt::ContainerVisual m_root{ nullptr }; - winrt::CompositionEllipseGeometry m_circleGeometry{ nullptr }; - winrt::ShapeVisual m_spotlight{ nullptr }; - winrt::CompositionCommitBatch m_batch{ nullptr }; - winrt::SpriteVisual m_backdrop{ nullptr }; - winrt::CompositionSpriteShape m_circleShape{ nullptr }; + muxc::Compositor m_compositor{ nullptr }; + muxxh::DesktopWindowXamlSource m_island{ nullptr }; + muxxc::Grid m_surface{ nullptr }; + + muxc::ContainerVisual m_root{ nullptr }; + muxc::CompositionCommitBatch m_batch{ nullptr }; + muxc::SpriteVisual m_backdrop{ nullptr }; + // Spotlight shape visuals + muxc::CompositionEllipseGeometry m_circleGeometry{ nullptr }; + muxc::ShapeVisual m_spotlight{ nullptr }; + muxc::CompositionSpriteShape m_circleShape{ nullptr }; + // Radial gradient mask components + muxc::CompositionMaskBrush m_maskBrush{ nullptr }; + muxc::CompositionColorBrush m_dimColorBrush{ nullptr }; + muxc::CompositionRadialGradientBrush m_spotlightMaskGradient{ nullptr }; + muxc::CompositionColorGradientStop m_maskStopCenter{ nullptr }; + muxc::CompositionColorGradientStop m_maskStopInner{ nullptr }; + muxc::CompositionColorGradientStop m_maskStopOuter{ nullptr }; winrt::Windows::UI::Color m_backgroundColor = FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR; winrt::Windows::UI::Color m_spotlightColor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR; - winrt::ScalarKeyFrameAnimation m_animation{ nullptr }; + muxc::ScalarKeyFrameAnimation m_animation{ nullptr }; }; template @@ -1047,7 +1216,6 @@ struct GdiCrosshairs : GdiSonar #pragma endregion Super_Sonar_Base_Code - #pragma region Super_Sonar_API CompositionSpotlight* m_sonar = nullptr; @@ -1055,7 +1223,6 @@ void FindMyMouseApplySettings(const FindMyMouseSettings& settings) { if (m_sonar != nullptr) { - Logger::info("Applying settings."); m_sonar->ApplySettings(settings, true); } } @@ -1064,7 +1231,6 @@ void FindMyMouseDisable() { if (m_sonar != nullptr) { - Logger::info("Terminating a sonar instance."); m_sonar->Terminate(); } } @@ -1077,7 +1243,6 @@ bool FindMyMouseIsEnabled() // Based on SuperSonar's original wWinMain. int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings) { - Logger::info("Starting a sonar instance."); if (m_sonar != nullptr) { Logger::error("A sonar instance was still working when trying to start a new one."); @@ -1092,7 +1257,6 @@ int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings) return 0; } m_sonar = &sonar; - Logger::info("Initialized the sonar instance."); InitializeWinhookEventIds(); @@ -1105,7 +1269,6 @@ int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings) DispatchMessage(&msg); } - Logger::info("Sonar message loop ended."); m_sonar = nullptr; return (int)msg.wParam; diff --git a/src/modules/MouseUtils/FindMyMouse/FindMyMouse.h b/src/modules/MouseUtils/FindMyMouse/FindMyMouse.h index fb52bf11e5..857ec8b84f 100644 --- a/src/modules/MouseUtils/FindMyMouse/FindMyMouse.h +++ b/src/modules/MouseUtils/FindMyMouse/FindMyMouse.h @@ -11,9 +11,9 @@ enum struct FindMyMouseActivationMethod : int }; constexpr bool FIND_MY_MOUSE_DEFAULT_DO_NOT_ACTIVATE_ON_GAME_MODE = true; +// Default colors now include full alpha. Opacity is encoded directly in color alpha (legacy overlay_opacity migrated into A channel) const winrt::Windows::UI::Color FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 0, 0, 0); const winrt::Windows::UI::Color FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 255, 255); -constexpr int FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY = 50; constexpr int FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS = 100; constexpr int FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS = 500; constexpr int FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM = 9; @@ -30,7 +30,6 @@ struct FindMyMouseSettings bool doNotActivateOnGameMode = FIND_MY_MOUSE_DEFAULT_DO_NOT_ACTIVATE_ON_GAME_MODE; winrt::Windows::UI::Color backgroundColor = FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR; winrt::Windows::UI::Color spotlightColor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR; - int overlayOpacity = FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY; int spotlightRadius = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS; int animationDurationMs = FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS; int spotlightInitialZoom = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM; diff --git a/src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj b/src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj index 9d4dbd2b28..d127de245e 100644 --- a/src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj +++ b/src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj @@ -1,5 +1,12 @@ + + + + + + + 15.0 @@ -7,6 +14,14 @@ Win32Proj FindMyMouse FindMyMouse + true + false + false + false + true + false + + packages.config @@ -30,6 +45,7 @@ + ..\..\..\..\$(Platform)\$(Configuration)\ @@ -79,7 +95,8 @@ - $(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories) + + $(GeneratedFilesDir);$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;$(MSBuildThisFileDirectory)..\..\..\..\src\;$(MSBuildThisFileDirectory)..\..\..\..\src\modules;$(MSBuildThisFileDirectory)..\..\..\..\src\common\Telemetry;%(AdditionalIncludeDirectories) @@ -98,6 +115,7 @@ + {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd} @@ -112,16 +130,56 @@ + + + + + + + NotUsing + + + + + <_ToDelete Include="$(OutDir)Microsoft.Web.WebView2.Core.dll" /> + + + + - - - + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/modules/MouseUtils/FindMyMouse/dllmain.cpp b/src/modules/MouseUtils/FindMyMouse/dllmain.cpp index 0518f468c2..b7ffb6177a 100644 --- a/src/modules/MouseUtils/FindMyMouse/dllmain.cpp +++ b/src/modules/MouseUtils/FindMyMouse/dllmain.cpp @@ -18,7 +18,7 @@ namespace const wchar_t JSON_KEY_DO_NOT_ACTIVATE_ON_GAME_MODE[] = L"do_not_activate_on_game_mode"; const wchar_t JSON_KEY_BACKGROUND_COLOR[] = L"background_color"; const wchar_t JSON_KEY_SPOTLIGHT_COLOR[] = L"spotlight_color"; - const wchar_t JSON_KEY_OVERLAY_OPACITY[] = L"overlay_opacity"; + const wchar_t JSON_KEY_OVERLAY_OPACITY[] = L"overlay_opacity"; // legacy only (migrated into color alpha) const wchar_t JSON_KEY_SPOTLIGHT_RADIUS[] = L"spotlight_radius"; const wchar_t JSON_KEY_ANIMATION_DURATION_MS[] = L"animation_duration_ms"; const wchar_t JSON_KEY_SPOTLIGHT_INITIAL_ZOOM[] = L"spotlight_initial_zoom"; @@ -204,6 +204,22 @@ void FindMyMouse::init_settings() } } +inline static uint8_t LegacyOpacityToAlpha(int overlayOpacityPercent) +{ + if (overlayOpacityPercent < 0) + { + return 255; // fallback: fully opaque + } + + if (overlayOpacityPercent > 100) + { + overlayOpacityPercent = 100; + } + + // Round to nearest integer (0–255) + return static_cast((overlayOpacityPercent * 255 + 50) / 100); +} + void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings) { auto settingsObject = settings.get_raw_json(); @@ -224,14 +240,13 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings) } else { - findMyMouseSettings.activationMethod = static_cast(value); - } + findMyMouseSettings.activationMethod = static_cast(value); + } } else { throw std::runtime_error("Invalid Activation Method value"); } - } catch (...) { @@ -255,19 +270,49 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings) { Logger::warn("Failed to get 'do not activate on game mode' setting"); } + // Colors + legacy overlay opacity migration + // Desired behavior: + // - Old schema: colors stored as RGB (no alpha) + separate overlay_opacity (0-100). We should migrate by applying that opacity as alpha. + // - New schema: colors stored as ARGB (alpha embedded). Ignore overlay_opacity even if still present. + int legacyOverlayOpacity = -1; + bool backgroundColorHadExplicitAlpha = false; + bool spotlightColorHadExplicitAlpha = false; try { - // Parse background color - auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_BACKGROUND_COLOR); - auto backgroundColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE); - uint8_t r, g, b; - if (!checkValidRGB(backgroundColor, &r, &g, &b)) + auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_OVERLAY_OPACITY); + int value = static_cast(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE)); + if (value >= 0 && value <= 100) { - Logger::error("Background color RGB value is invalid. Will use default value"); + legacyOverlayOpacity = value; + } + } + catch (...) + { + // overlay_opacity may not exist anymore + } + try + { + auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_BACKGROUND_COLOR); + auto backgroundColorStr = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE); + uint8_t a = 255, r, g, b; + bool parsed = false; + if (checkValidARGB(backgroundColorStr, &a, &r, &g, &b)) + { + parsed = true; + backgroundColorHadExplicitAlpha = true; // New schema with alpha present + } + else if (checkValidRGB(backgroundColorStr, &r, &g, &b)) + { + a = LegacyOpacityToAlpha(legacyOverlayOpacity); + parsed = true; // Old schema (no alpha component) + } + if (parsed) + { + findMyMouseSettings.backgroundColor = winrt::Windows::UI::ColorHelper::FromArgb(a, r, g, b); } else { - findMyMouseSettings.backgroundColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b); + Logger::error("Background color value is invalid. Will use default"); } } catch (...) @@ -276,17 +321,27 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings) } try { - // Parse spotlight color auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_COLOR); - auto spotlightColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE); - uint8_t r, g, b; - if (!checkValidRGB(spotlightColor, &r, &g, &b)) + auto spotlightColorStr = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE); + uint8_t a = 255, r, g, b; + bool parsed = false; + if (checkValidARGB(spotlightColorStr, &a, &r, &g, &b)) { - Logger::error("Spotlight color RGB value is invalid. Will use default value"); + parsed = true; + spotlightColorHadExplicitAlpha = true; + } + else if (checkValidRGB(spotlightColorStr, &r, &g, &b)) + { + a = LegacyOpacityToAlpha(legacyOverlayOpacity); + parsed = true; + } + if (parsed) + { + findMyMouseSettings.spotlightColor = winrt::Windows::UI::ColorHelper::FromArgb(a, r, g, b); } else { - findMyMouseSettings.spotlightColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b); + Logger::error("Spotlight color value is invalid. Will use default"); } } catch (...) @@ -294,24 +349,6 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings) Logger::warn("Failed to initialize spotlight color from settings. Will use default value"); } try - { - // Parse Overlay Opacity - auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_OVERLAY_OPACITY); - int value = static_cast(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE)); - if (value >= 0) - { - findMyMouseSettings.overlayOpacity = value; - } - else - { - throw std::runtime_error("Invalid Overlay Opacity value"); - } - } - catch (...) - { - Logger::warn("Failed to initialize Overlay Opacity from settings. Will use default value"); - } - try { // Parse Spotlight Radius auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_RADIUS); @@ -492,7 +529,6 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings) m_findMyMouseSettings = findMyMouseSettings; } - extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create() { return new FindMyMouse(); diff --git a/src/modules/MouseUtils/FindMyMouse/packages.config b/src/modules/MouseUtils/FindMyMouse/packages.config index 09bfc449e2..cff3aa8705 100644 --- a/src/modules/MouseUtils/FindMyMouse/packages.config +++ b/src/modules/MouseUtils/FindMyMouse/packages.config @@ -1,4 +1,12 @@ - + - \ No newline at end of file + + + + + + + + + diff --git a/src/modules/MouseUtils/FindMyMouse/pch.h b/src/modules/MouseUtils/FindMyMouse/pch.h index 26da2455f2..a0a8f1819c 100644 --- a/src/modules/MouseUtils/FindMyMouse/pch.h +++ b/src/modules/MouseUtils/FindMyMouse/pch.h @@ -5,15 +5,22 @@ #include #include #include +// Required for IUnknown and DECLARE_INTERFACE_* used by interop headers +#include #ifdef COMPOSITION -#include #include #include #include -#include +#include +#include +#include #endif #include #include #include + +#ifdef GetCurrentTime +#undef GetCurrentTime +#endif \ No newline at end of file diff --git a/src/runner/main.cpp b/src/runner/main.cpp index 31afbd0378..cc8e6ca2b0 100644 --- a/src/runner/main.cpp +++ b/src/runner/main.cpp @@ -335,6 +335,7 @@ int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR l GdiplusStartup(&gpToken, &gpStartupInput, NULL); winrt::init_apartment(); + const wchar_t* securityDescriptor = L"O:BA" // Owner: Builtin (local) administrator L"G:BA" // Group: Builtin (local) administrator @@ -526,5 +527,6 @@ int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR l } } stop_tray_icon(); + return result; } diff --git a/src/runner/packages.config b/src/runner/packages.config index ff4b059648..74d5ef5747 100644 --- a/src/runner/packages.config +++ b/src/runner/packages.config @@ -2,4 +2,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/runner/runner.vcxproj b/src/runner/runner.vcxproj index 90dafb5e45..afff599d8e 100644 --- a/src/runner/runner.vcxproj +++ b/src/runner/runner.vcxproj @@ -1,8 +1,7 @@  - - + 81010002 @@ -15,10 +14,20 @@ + + + + + + + + Application v143 + None + true @@ -131,15 +140,38 @@ - - + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/settings-ui/Settings.UI.Library/FindMyMouseProperties.cs b/src/settings-ui/Settings.UI.Library/FindMyMouseProperties.cs index a028eb9e43..f1fe32e1ca 100644 --- a/src/settings-ui/Settings.UI.Library/FindMyMouseProperties.cs +++ b/src/settings-ui/Settings.UI.Library/FindMyMouseProperties.cs @@ -31,9 +31,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library [JsonPropertyName("spotlight_color")] public StringProperty SpotlightColor { get; set; } - [JsonPropertyName("overlay_opacity")] - public IntProperty OverlayOpacity { get; set; } - [JsonPropertyName("spotlight_radius")] public IntProperty SpotlightRadius { get; set; } @@ -61,9 +58,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library IncludeWinKey = new BoolProperty(false); ActivationShortcut = DefaultActivationShortcut; DoNotActivateOnGameMode = new BoolProperty(true); - BackgroundColor = new StringProperty("#000000"); - SpotlightColor = new StringProperty("#FFFFFF"); - OverlayOpacity = new IntProperty(50); + BackgroundColor = new StringProperty("#FF000000"); // ARGB (#AARRGGBB) + SpotlightColor = new StringProperty("#FFFFFFFF"); SpotlightRadius = new IntProperty(100); AnimationDurationMs = new IntProperty(500); SpotlightInitialZoom = new IntProperty(9); diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml deleted file mode 100644 index c077042d96..0000000000 --- a/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml.cs deleted file mode 100644 index 24a0d0e448..0000000000 --- a/src/settings-ui/Settings.UI/SettingsXAML/Controls/AlphaColorPickerButton.xaml.cs +++ /dev/null @@ -1,59 +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 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/Controls/ColorPickerButton.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Controls/ColorPickerButton.xaml index 10a1e01236..4a46b7dc29 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Controls/ColorPickerButton.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Controls/ColorPickerButton.xaml @@ -27,9 +27,9 @@ (bool)GetValue(IsAlphaEnabledProperty); + set => SetValue(IsAlphaEnabledProperty, value); + } public ColorPickerButton() { diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml index 537d5a1071..514e959629 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml @@ -117,19 +117,12 @@ IsEnabled="{x:Bind ViewModel.IsFindMyMouseEnabled, Mode=OneWay}" IsExpanded="False"> - - - + - + - + - + - + - +