Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
328ddde
[MouseJump] - port latest fancymouse code to mousejump (microsoft#48290)
mikeclayton Jun 8, 2026
4fa6832
[MouseJump] - adding WinUI MouseJump version (microsoft#48290)
mikeclayton Jun 9, 2026
8cff457
[MouseJump] - adding WinUI MouseJump version (microsoft#48290)
mikeclayton Jun 9, 2026
04ca66d
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
bcfd326
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
c2d058b
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
739f0e3
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
145afdc
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
5721cd6
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
e0bdb31
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
63a4fe4
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
27ed704
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
53fd7a2
[MouseJump] - fixing spellcheck issues (microsoft#48290)
mikeclayton Jun 9, 2026
dfadb9b
Merge branch 'main' into dev/mikeclayton/mousejump-winui-port
mikeclayton Jun 24, 2026
37c1082
[MouseJump] - bumped MouseJump module dependencies (microsoft#48290)
mikeclayton Jun 24, 2026
447f4af
[MouseJump] - fixing settings ui (microsoft#48290)
mikeclayton Jun 24, 2026
4dba1db
[MouseJump] - fixed regression - Mouse crosshair moves when Mouse Jum…
mikeclayton Jun 24, 2026
194e0c8
[MouseJump] - fixing mouse jump exe paths for runner (microsoft#48290)
mikeclayton Jun 24, 2026
659b542
Merge branch 'main' into dev/mikeclayton/mousejump-winui-port
mikeclayton Jun 24, 2026
938f8f2
[MouseJump] - restoring "powertoys runner" watcher to quit Mouse Jump…
mikeclayton Jun 25, 2026
14da12c
[MouseJump] - remove unused trayicon (microsoft#48290)
mikeclayton Jun 25, 2026
e1dfa71
[MouseJump] - deleting Mouse Jump (WinForms) to avoid confusion (micr…
mikeclayton Jun 25, 2026
25df81c
[MouseJump] - fixing preview dismissal when clicking another applicat…
mikeclayton Jul 2, 2026
8e0844a
[MouseJump] - removing some test code (microsoft#48290)
mikeclayton Jul 3, 2026
7c750d6
Apply suggestions from code review
mikeclayton Jul 4, 2026
5e23105
[MouseJump] - fixing vcxproj module imports (microsoft#48290)
mikeclayton Jul 5, 2026
486522a
[MouseJump] - moved MouseJump.Kicker to \tools (microsoft#48290)
mikeclayton Jul 9, 2026
1aeefa8
[MouseJump] - fixing copilot feedback for MouseJump.Kicker (microsoft…
mikeclayton Jul 9, 2026
69179db
[MouseJump] - fixing copilot feedback for MouseJump (microsoft#48290)
mikeclayton Jul 9, 2026
dd06250
[MouseJump] - misc MouseJump fixes suggested by Claude (microsoft#48290)
mikeclayton Jul 9, 2026
a9c01af
Merge branch 'main' into dev/mikeclayton/mousejump-winui-port
mikeclayton Jul 9, 2026
2477195
[MouseJump] - fixing path to MouseJump.Kicker resx in spelling exclus…
mikeclayton Jul 9, 2026
cdd0e78
[MouseJump] - fixing path to MouseJump.Kicker resx in spelling exclus…
mikeclayton Jul 9, 2026
2a92884
Merge main into mousejump-winui-port to resolve spell-check conflict
LegendaryBlair Jul 23, 2026
925b70d
Merge branch 'main' into dev/mikeclayton/mousejump-winui-port
moooyo Aug 5, 2026
1ff8a1c
[MouseJump] Fix XAML formatting
Aug 5, 2026
b9586d4
[MouseJump] Fix ARM64 solution configurations
moooyo Aug 6, 2026
acc53fe
[MouseJump] Move XAML assets into module directory
Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions PowerToys.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/Common.UI/Common.UI.csproj">
<Project Path="src/common/Common.UI.Controls/Common.UI.Controls.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/Common.UI.Controls/Common.UI.Controls.csproj">
<Project Path="src/common/Common.UI/Common.UI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
Expand Down Expand Up @@ -56,8 +56,8 @@
</Project>
<Project Path="src/common/UnitTests-CommonLib/UnitTests-CommonLib.vcxproj" Id="1a066c63-64b3-45f8-92fe-664e1cce8077" />
<Project Path="src/common/UnitTests-CommonUtils/UnitTests-CommonUtils.vcxproj" Id="8b5cfb38-ccba-40a8-ad7a-89c57b070884" />
<Project Path="src/common/updating/updating.vcxproj" Id="17da04df-e393-4397-9cf0-84dabe11032e" />
<Project Path="src/common/updating/UnitTests/UpdatingUnitTests.vcxproj" Id="a1b2c3d4-e5f6-7890-abcd-ef1234567890" />
<Project Path="src/common/updating/updating.vcxproj" Id="17da04df-e393-4397-9cf0-84dabe11032e" />
<Project Path="src/common/version/version.vcxproj" Id="cc6e41ac-8174-4e8a-8d22-85dd7f4851df" />
</Folder>
<Folder Name="/common/interop/">
Expand Down Expand Up @@ -200,11 +200,11 @@
</Project>
</Folder>
<Folder Name="/modules/CommandPalette/Built-in Extensions/">
<Project Path="src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Microsoft.CmdPal.Ext.Apps.csproj">
<Project Path="src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Actions/Microsoft.CmdPal.Ext.Actions.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Actions/Microsoft.CmdPal.Ext.Actions.csproj">
<Project Path="src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Microsoft.CmdPal.Ext.Apps.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
Expand Down Expand Up @@ -511,6 +511,20 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseJump.HotKeys/MouseJump.HotKeys.csproj">
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseJump.Kicker/MouseJump.Kicker.csproj" Id="fbcafd0a-9262-4257-adb5-5b61a7c81a89">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseJump.Models/MouseJump.Models.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseJump.Settings/MouseJump.Settings.csproj">
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseJump/MouseJump.vcxproj" Id="8a08d663-4995-40e3-b42c-3f910625f284" />
<Project Path="src/modules/MouseUtils/MouseJumpUI/MouseJumpUI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
Expand All @@ -523,6 +537,15 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseJump.HotKeys.UnitTests/MouseJump.HotKeys.UnitTests.csproj">
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseJump.Models.UnitTests/MouseJump.Models.UnitTests.csproj">
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseJump.Settings.UnitTests/MouseJump.Settings.UnitTests.csproj">
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseUtils.UITests/MouseUtils.UITests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
Expand Down Expand Up @@ -715,11 +738,11 @@
</Project>
</Folder>
<Folder Name="/modules/PowerDisplay/">
<Project Path="src/modules/powerdisplay/PowerDisplay.Models/PowerDisplay.Models.csproj">
<Project Path="src/modules/powerdisplay/PowerDisplay.Lib/PowerDisplay.Lib.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/powerdisplay/PowerDisplay.Lib/PowerDisplay.Lib.csproj">
<Project Path="src/modules/powerdisplay/PowerDisplay.Models/PowerDisplay.Models.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
Expand Down Expand Up @@ -1119,14 +1142,14 @@
<BuildDependency Project="src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj" />
<BuildDependency Project="src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj" />
<BuildDependency Project="src/modules/fancyzones/FancyZonesModuleInterface/FancyZonesModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMove/GrabAndMove.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMoveModuleInterface/GrabAndMoveModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/imageresizer/dll/ImageResizerExt.vcxproj" />
<BuildDependency Project="src/modules/imageresizer/ui/ImageResizerUI.csproj" />
<BuildDependency Project="src/modules/keyboardmanager/dll/KeyboardManager.vcxproj" />
<BuildDependency Project="src/modules/launcher/Microsoft.Launcher/Microsoft.Launcher.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMoveModuleInterface/GrabAndMoveModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMove/GrabAndMove.vcxproj" />
<BuildDependency Project="src/modules/powerrename/dll/PowerRenameExt.vcxproj" />
<BuildDependency Project="src/modules/powerrename/lib/PowerRenameLib.vcxproj" />
<BuildDependency Project="src/modules/previewpane/Common/PreviewHandlerCommon.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,42 @@
// 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.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.Text;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using MouseJump.Common.Helpers;
using MouseJump.Common.Imaging;
using MouseJump.Common.Models.Drawing;
using MouseJump.Common.Models.Styles;
using MouseJump.Models.Display;
using MouseJump.Models.Drawing;
using MouseJump.Models.Styles;

namespace MouseJump.Common.UnitTests.Helpers;

[TestClass]
public static class DrawingHelperTests
{
[TestClass]
public sealed class RenderPreviewTests
public sealed class GetPreviewLayoutTests
{
public sealed class TestCase
{
public TestCase(PreviewStyle previewStyle, List<RectangleInfo> screens, PointInfo activatedLocation, string desktopImageFilename, string expectedImageFilename)
public TestCase(PreviewStyle previewStyle, DisplayInfo displayInfo, ScreenInfo activatedScreen, PointInfo activatedLocation, string desktopImageFilename, string expectedImageFilename)
{
this.PreviewStyle = previewStyle;
this.Screens = screens;
this.DisplayInfo = displayInfo;
this.ActivatedScreen = activatedScreen;
this.ActivatedLocation = activatedLocation;
this.DesktopImageFilename = desktopImageFilename;
this.ExpectedImageFilename = expectedImageFilename;
}

public PreviewStyle PreviewStyle { get; }

public List<RectangleInfo> Screens { get; }
public DisplayInfo DisplayInfo { get; }

public ScreenInfo ActivatedScreen { get; }

public PointInfo ActivatedLocation { get; }

Expand All @@ -43,80 +48,158 @@ public TestCase(PreviewStyle previewStyle, List<RectangleInfo> screens, PointInf

public static IEnumerable<object[]> GetTestCases()
{
/* 4-grid */
// colors like "SystemColors.Highlight" can change between versions of windows,
// so we'll use hard-coded colors instead to reduce false test failures
var systemHighlight = Color.FromArgb(0, 120, 215);
var previewStyle = StyleHelper.BezelledPreviewStyle;
previewStyle = new(
canvasSize: previewStyle.CanvasSize,
canvasStyle: new(
marginStyle: previewStyle.CanvasStyle.MarginStyle,
borderStyle: previewStyle.CanvasStyle.BorderStyle.WithColor(systemHighlight),
paddingStyle: previewStyle.CanvasStyle.PaddingStyle,
backgroundStyle: previewStyle.CanvasStyle.BackgroundStyle
),
screenStyle: previewStyle.ScreenStyle,
extraColors: previewStyle.ExtraColors
);

// 4-grid
var displayInfo = new DisplayInfo(
devices: new DeviceInfo[]
{
new(
hostname: "localhost",
localhost: true,
screens: new List<ScreenInfo>
{
new(
handle: 0,
primary: true,
displayArea: new(0, 0, 500, 500),
workingArea: new(0, 0, 500, 500)),
new(
handle: 0,
primary: false,
displayArea: new(500, 0, 500, 500),
workingArea: new(500, 0, 500, 500)),
new(
handle: 0,
primary: false,
displayArea: new(500, 500, 500, 500),
workingArea: new(500, 500, 500, 500)),
new(
handle: 0,
primary: false,
displayArea: new(0, 500, 500, 500),
workingArea: new(0, 500, 500, 500)),
}
),
});
yield return new object[]
{
new TestCase(
previewStyle: StyleHelper.BezelledPreviewStyle,
screens: new List<RectangleInfo>()
{
new(0, 0, 500, 500),
new(500, 0, 500, 500),
new(500, 500, 500, 500),
new(0, 500, 500, 500),
},
previewStyle: previewStyle,
displayInfo: displayInfo,
activatedScreen: displayInfo.Devices[0].Screens[0],
activatedLocation: new(x: 50, y: 50),
desktopImageFilename: "_test-4grid-desktop.png",
expectedImageFilename: "_test-4grid-expected.png"),
};
/* win 11 */

// win 11
displayInfo = new(
devices: new DeviceInfo[]
{
new(
hostname: "localhost",
localhost: true,
screens: new List<ScreenInfo>
{
new(
handle: 0,
primary: true,
displayArea: new(5120, 349, 1920, 1080),
workingArea: new(5120, 349, 1920, 1080)),
new(
handle: 0,
primary: false,
displayArea: new(0, 0, 5120, 1440),
workingArea: new(0, 0, 5120, 1440)),
}
),
}
);
yield return new object[]
{
new TestCase(
previewStyle: StyleHelper.BezelledPreviewStyle,
screens: new List<RectangleInfo>()
{
new(5120, 349, 1920, 1080),
new(0, 0, 5120, 1440),
},
previewStyle: previewStyle,
displayInfo: displayInfo,
activatedScreen: displayInfo.Devices[0].Screens[0],
activatedLocation: new(x: 50, y: 50),
desktopImageFilename: "_test-win11-desktop.png",
expectedImageFilename: "_test-win11-expected.png"),
};
}

[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
[DynamicData(nameof(GetTestCases))]
public async Task RunTestCases(TestCase data)
{
// load the fake desktop image
using var desktopImage = RenderPreviewTests.LoadImageResource(data.DesktopImageFilename);
using var desktopImage = GetPreviewLayoutTests.LoadImageResource(data.DesktopImageFilename);

// draw the preview image
var previewLayout = LayoutHelper.GetPreviewLayout(
var formLayout = LayoutHelper.GetFormLayout(
previewStyle: data.PreviewStyle,
screens: data.Screens,
displayInfo: data.DisplayInfo,
activatedScreen: data.ActivatedScreen,
activatedLocation: data.ActivatedLocation);
var imageCopyService = new StaticImageRegionCopyService(desktopImage);
using var actual = DrawingHelper.RenderPreview(previewLayout, imageCopyService);

var imageCopyServices = formLayout.CanvasLayout.DeviceLayouts
.Select(
deviceLayout => (IImageRegionCopyService)new StaticImageRegionCopyService(desktopImage))
.ToList();

// draw the preview image
using var actual = await DrawingHelper.RenderPreviewAsync(formLayout.CanvasLayout, data.ActivatedScreen, imageCopyServices);

// save the actual image so we can pick it up as a build artifact
var actualFilename = Path.GetFileNameWithoutExtension(data.ExpectedImageFilename) + "_actual" + Path.GetExtension(data.ExpectedImageFilename);
actual.Save(actualFilename, ImageFormat.Png);

// load the expected image
var expected = RenderPreviewTests.LoadImageResource(data.ExpectedImageFilename);
var expected = GetPreviewLayoutTests.LoadImageResource(data.ExpectedImageFilename);

// save the actual image so we can pick it up as a build artifact
var expectedFilename = Path.GetFileNameWithoutExtension(data.ExpectedImageFilename) + "_expected" + Path.GetExtension(data.ExpectedImageFilename);
expected.Save(expectedFilename, ImageFormat.Png);

// compare the images
AssertImagesEqual(expected, actual);
}

private static Bitmap LoadImageResource(string filename)
{
var assembly = Assembly.GetExecutingAssembly();
var assemblyName = new AssemblyName(assembly.FullName ?? throw new InvalidOperationException());
var resourceName = $"{typeof(DrawingHelperTests).Namespace}.{filename.Replace("/", ".")}";
var resourceNames = assembly.GetManifestResourceNames();
var referenceType = typeof(DrawingHelperTests);
var resourceAssembly = referenceType.Assembly;

var resourcePrefix = referenceType.Namespace;
var resourceName = $"{resourcePrefix}.{filename.Replace("/", ".")}";
var resourceNames = resourceAssembly.GetManifestResourceNames();
if (!resourceNames.Contains(resourceName))
{
var message = new StringBuilder();
message.AppendLine(CultureInfo.InvariantCulture, $"Embedded resource '{resourceName}' does not exist.");
message.AppendLine($"Known resources:");
foreach (var name in resourceNames)
{
message.AppendLine(name);
}

throw new InvalidOperationException(message.ToString());
var message = string.Join(
Environment.NewLine,
new List<string>([
$"Embedded resource '{resourceName}' does not exist.",
string.Empty,
"Valid resource names are:",
string.Empty])
.Concat(resourceNames));
throw new InvalidOperationException(message);
}

var stream = assembly.GetManifestResourceStream(resourceName)
var stream = resourceAssembly.GetManifestResourceStream(resourceName)
?? throw new InvalidOperationException();
var image = (Bitmap)Image.FromStream(stream);
return image;
Expand All @@ -143,12 +226,11 @@ private static void AssertImagesEqual(Bitmap expected, Bitmap actual)
var actualPixel = actual.GetPixel(x, y);

// allow a small tolerance for rounding differences in gdi
// using a tolerance of 3 for support of minor differences in Windows Server 2025 CI
Assert.IsTrue(
(Math.Abs(expectedPixel.A - actualPixel.A) <= 3) &&
(Math.Abs(expectedPixel.R - actualPixel.R) <= 3) &&
(Math.Abs(expectedPixel.G - actualPixel.G) <= 3) &&
(Math.Abs(expectedPixel.B - actualPixel.B) <= 3),
(Math.Abs(expectedPixel.A - actualPixel.A) <= 1) &&
(Math.Abs(expectedPixel.R - actualPixel.R) <= 1) &&
(Math.Abs(expectedPixel.G - actualPixel.G) <= 1) &&
(Math.Abs(expectedPixel.B - actualPixel.B) <= 1),
$"images differ at pixel ({x}, {y}) - expected: {expectedPixel}, actual: {actualPixel}");
}
}
Expand Down
Loading