mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
Add Cursor Wrap functionality to Powertoys Mouse Utils (#41826)
## Summary of the Pull Request Cursor Wrap makes it simple to move the mouse from one edge of a display (or set of displays) to the opposite edge of the display stack - on a single display Cursor Wrap will wrap top/bottom and left/right edges. https://github.com/user-attachments/assets/3feb606c-142b-4dab-9824-7597833d3ba4 ## PR Checklist - [x] Closes: CursorWrap #41759 - [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 - [x] **New binaries:** Added on the required places - [x] [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 ## Detailed Description of the Pull Request / Additional comments PR adds a new mouse utils module, this is 'Cursor Wrap' - Cursor Wrap works with 1-9 monitors based on the logical monitor layout of the PC - for a single monitor device the cursor is wrapped for the top/bottom and left/right edges of the display - for a multi-monitor setup the cursor is wrapped on the top/bottom left/right of the displays in the logical display layout. ## Validation Steps Performed Validation has been performed on a Surface Laptop 7 Pro (Intel) with a single display and with an HDMI USB-C second display configured to be a second monitor in top/left/right/bottom configuration - there are also tests that run as part of the build to validate logical monitor layout and cursor positioning. --------- Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: Kai Tao (from Dev Box) <kaitao@microsoft.com> Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
This commit is contained in:
3
.github/actions/spell-check/expect.txt
vendored
3
.github/actions/spell-check/expect.txt
vendored
@@ -22,6 +22,7 @@ ADate
|
|||||||
ADDSTRING
|
ADDSTRING
|
||||||
ADDUNDORECORD
|
ADDUNDORECORD
|
||||||
ADifferent
|
ADifferent
|
||||||
|
adjacents
|
||||||
ADMINS
|
ADMINS
|
||||||
adml
|
adml
|
||||||
admx
|
admx
|
||||||
@@ -313,6 +314,8 @@ CURRENTDIR
|
|||||||
CURSORINFO
|
CURSORINFO
|
||||||
cursorpos
|
cursorpos
|
||||||
CURSORSHOWING
|
CURSORSHOWING
|
||||||
|
CURSORWRAP
|
||||||
|
CursorWrap
|
||||||
customaction
|
customaction
|
||||||
CUSTOMACTIONTEST
|
CUSTOMACTIONTEST
|
||||||
CUSTOMFORMATPLACEHOLDER
|
CUSTOMFORMATPLACEHOLDER
|
||||||
|
|||||||
@@ -181,6 +181,7 @@
|
|||||||
"PowerToys.MousePointerCrosshairs.dll",
|
"PowerToys.MousePointerCrosshairs.dll",
|
||||||
"PowerToys.MouseJumpUI.dll",
|
"PowerToys.MouseJumpUI.dll",
|
||||||
"PowerToys.MouseJumpUI.exe",
|
"PowerToys.MouseJumpUI.exe",
|
||||||
|
"PowerToys.CursorWrap.dll",
|
||||||
|
|
||||||
"PowerToys.MouseWithoutBorders.dll",
|
"PowerToys.MouseWithoutBorders.dll",
|
||||||
"PowerToys.MouseWithoutBorders.exe",
|
"PowerToys.MouseWithoutBorders.exe",
|
||||||
|
|||||||
@@ -822,6 +822,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSea
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Shell.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Shell.UnitTests\Microsoft.CmdPal.Ext.Shell.UnitTests.csproj", "{E816D7B4-4688-4ECB-97CC-3D8E798F3833}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Shell.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Shell.UnitTests\Microsoft.CmdPal.Ext.Shell.UnitTests.csproj", "{E816D7B4-4688-4ECB-97CC-3D8E798F3833}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CursorWrap", "src\modules\MouseUtils\CursorWrap\CursorWrap.vcxproj", "{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}"
|
||||||
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3DCCD936-D085-4869-A1DE-CA6A64152C94}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3DCCD936-D085-4869-A1DE-CA6A64152C94}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightSwitch.UITests", "src\modules\LightSwitch\Tests\LightSwitch.UITests\LightSwitch.UITests.csproj", "{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightSwitch.UITests", "src\modules\LightSwitch\Tests\LightSwitch.UITests\LightSwitch.UITests.csproj", "{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}"
|
||||||
@@ -2990,6 +2992,14 @@ Global
|
|||||||
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|ARM64.Build.0 = Release|ARM64
|
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|ARM64.Build.0 = Release|ARM64
|
||||||
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.ActiveCfg = Release|x64
|
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.ActiveCfg = Release|x64
|
||||||
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.Build.0 = Release|x64
|
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.Build.0 = Release|x64
|
||||||
|
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||||
|
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||||
|
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||||
|
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.Build.0 = Release|ARM64
|
||||||
|
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.Build.0 = Release|x64
|
||||||
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||||
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Build.0 = Debug|ARM64
|
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||||
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||||
@@ -3351,6 +3361,7 @@ Global
|
|||||||
{E816D7B3-4688-4ECB-97CC-3D8E798F3832} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
{E816D7B3-4688-4ECB-97CC-3D8E798F3832} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||||
{E816D7B2-4688-4ECB-97CC-3D8E798F3831} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
{E816D7B2-4688-4ECB-97CC-3D8E798F3831} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||||
{E816D7B4-4688-4ECB-97CC-3D8E798F3833} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
{E816D7B4-4688-4ECB-97CC-3D8E798F3833} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||||
|
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||||
{3DCCD936-D085-4869-A1DE-CA6A64152C94} = {5B201255-53C8-490B-A34F-01F05D48A477}
|
{3DCCD936-D085-4869-A1DE-CA6A64152C94} = {5B201255-53C8-490B-A34F-01F05D48A477}
|
||||||
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F} = {3DCCD936-D085-4869-A1DE-CA6A64152C94}
|
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F} = {3DCCD936-D085-4869-A1DE-CA6A64152C94}
|
||||||
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||||
|
|||||||
@@ -112,6 +112,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
|||||||
{
|
{
|
||||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredMousePointerCrosshairsEnabledValue());
|
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredMousePointerCrosshairsEnabledValue());
|
||||||
}
|
}
|
||||||
|
GpoRuleConfigured GPOWrapper::GetConfiguredCursorWrapEnabledValue()
|
||||||
|
{
|
||||||
|
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCursorWrapEnabledValue());
|
||||||
|
}
|
||||||
GpoRuleConfigured GPOWrapper::GetConfiguredPowerRenameEnabledValue()
|
GpoRuleConfigured GPOWrapper::GetConfiguredPowerRenameEnabledValue()
|
||||||
{
|
{
|
||||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredPowerRenameEnabledValue());
|
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredPowerRenameEnabledValue());
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
|||||||
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
|
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
|
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
|
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
|
||||||
|
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
|
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
|
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredQuickAccentEnabledValue();
|
static GpoRuleConfigured GetConfiguredQuickAccentEnabledValue();
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace PowerToys
|
|||||||
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
|
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
|
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
|
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
|
||||||
|
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredMouseWithoutBordersEnabledValue();
|
static GpoRuleConfigured GetConfiguredMouseWithoutBordersEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
|
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
|
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace ManagedCommon
|
|||||||
ColorPicker,
|
ColorPicker,
|
||||||
CmdPal,
|
CmdPal,
|
||||||
CropAndLock,
|
CropAndLock,
|
||||||
|
CursorWrap,
|
||||||
EnvironmentVariables,
|
EnvironmentVariables,
|
||||||
FancyZones,
|
FancyZones,
|
||||||
FileLocksmith,
|
FileLocksmith,
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ struct LogSettings
|
|||||||
inline const static std::string mouseHighlighterLoggerName = "mouse-highlighter";
|
inline const static std::string mouseHighlighterLoggerName = "mouse-highlighter";
|
||||||
inline const static std::string mouseJumpLoggerName = "mouse-jump";
|
inline const static std::string mouseJumpLoggerName = "mouse-jump";
|
||||||
inline const static std::string mousePointerCrosshairsLoggerName = "mouse-pointer-crosshairs";
|
inline const static std::string mousePointerCrosshairsLoggerName = "mouse-pointer-crosshairs";
|
||||||
|
inline const static std::string cursorWrapLoggerName = "cursor-wrap";
|
||||||
inline const static std::string imageResizerLoggerName = "imageresizer";
|
inline const static std::string imageResizerLoggerName = "imageresizer";
|
||||||
inline const static std::string powerRenameLoggerName = "powerrename";
|
inline const static std::string powerRenameLoggerName = "powerrename";
|
||||||
inline const static std::string alwaysOnTopLoggerName = "always-on-top";
|
inline const static std::string alwaysOnTopLoggerName = "always-on-top";
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace powertoys_gpo
|
namespace powertoys_gpo
|
||||||
{
|
{
|
||||||
@@ -51,6 +52,7 @@ namespace powertoys_gpo
|
|||||||
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_HIGHLIGHTER = L"ConfigureEnabledUtilityMouseHighlighter";
|
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_HIGHLIGHTER = L"ConfigureEnabledUtilityMouseHighlighter";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_JUMP = L"ConfigureEnabledUtilityMouseJump";
|
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_JUMP = L"ConfigureEnabledUtilityMouseJump";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS = L"ConfigureEnabledUtilityMousePointerCrosshairs";
|
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS = L"ConfigureEnabledUtilityMousePointerCrosshairs";
|
||||||
|
const std::wstring POLICY_CONFIGURE_ENABLED_CURSOR_WRAP = L"ConfigureEnabledUtilityCursorWrap";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_RENAME = L"ConfigureEnabledUtilityPowerRename";
|
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_RENAME = L"ConfigureEnabledUtilityPowerRename";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER = L"ConfigureEnabledUtilityPowerLauncher";
|
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER = L"ConfigureEnabledUtilityPowerLauncher";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_QUICK_ACCENT = L"ConfigureEnabledUtilityQuickAccent";
|
const std::wstring POLICY_CONFIGURE_ENABLED_QUICK_ACCENT = L"ConfigureEnabledUtilityQuickAccent";
|
||||||
@@ -409,6 +411,11 @@ namespace powertoys_gpo
|
|||||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS);
|
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline gpo_rule_configured_t getConfiguredCursorWrapEnabledValue()
|
||||||
|
{
|
||||||
|
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CURSOR_WRAP);
|
||||||
|
}
|
||||||
|
|
||||||
inline gpo_rule_configured_t getConfiguredPowerRenameEnabledValue()
|
inline gpo_rule_configured_t getConfiguredPowerRenameEnabledValue()
|
||||||
{
|
{
|
||||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_POWER_RENAME);
|
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_POWER_RENAME);
|
||||||
|
|||||||
46
src/modules/MouseUtils/CursorWrap/CursorWrap.rc
Normal file
46
src/modules/MouseUtils/CursorWrap/CursorWrap.rc
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include "resource.h"
|
||||||
|
#include "../../../../common/version/version.h"
|
||||||
|
|
||||||
|
#define APSTUDIO_READONLY_SYMBOLS
|
||||||
|
#include "winres.h"
|
||||||
|
#undef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
|
||||||
|
1 VERSIONINFO
|
||||||
|
FILEVERSION FILE_VERSION
|
||||||
|
PRODUCTVERSION PRODUCT_VERSION
|
||||||
|
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS VS_FF_DEBUG
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS VOS_NT_WINDOWS32
|
||||||
|
FILETYPE VFT_DLL
|
||||||
|
FILESUBTYPE VFT2_UNKNOWN
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", COMPANY_NAME
|
||||||
|
VALUE "FileDescription", "PowerToys CursorWrap"
|
||||||
|
VALUE "FileVersion", FILE_VERSION_STRING
|
||||||
|
VALUE "InternalName", "CursorWrap"
|
||||||
|
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||||
|
VALUE "OriginalFilename", "PowerToys.CursorWrap.dll"
|
||||||
|
VALUE "ProductName", PRODUCT_NAME
|
||||||
|
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
||||||
|
STRINGTABLE
|
||||||
|
BEGIN
|
||||||
|
IDS_CURSORWRAP_NAME L"CursorWrap"
|
||||||
|
IDS_CURSORWRAP_DISABLE_WRAP_DURING_DRAG L"Disable wrapping during drag"
|
||||||
|
END
|
||||||
130
src/modules/MouseUtils/CursorWrap/CursorWrap.vcxproj
Normal file
130
src/modules/MouseUtils/CursorWrap/CursorWrap.vcxproj
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{48a1db8c-5df8-4fb3-9e14-2b67f3f2d8b5}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>CursorWrap</RootNamespace>
|
||||||
|
<ProjectName>CursorWrap</ProjectName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<TargetName>PowerToys.CursorWrap</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="CursorWrapTests.h" />
|
||||||
|
<ClInclude Include="pch.h" />
|
||||||
|
<ClInclude Include="trace.h" />
|
||||||
|
<ClInclude Include="resource.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dllmain.cpp" />
|
||||||
|
|
||||||
|
<ClCompile Include="pch.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="trace.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="CursorWrap.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||||
|
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||||
|
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="COMPLETE_REWRITE_SUMMARY.md" />
|
||||||
|
<None Include="CRITICAL_BUG_ANALYSIS.md" />
|
||||||
|
<None Include="CURSOR_WRAP_FIX_ANALYSIS.md" />
|
||||||
|
<None Include="DEBUG_GUIDE.md" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
<None Include="VERTICAL_WRAP_BUG_FIX.md" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||||
|
</ImportGroup>
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>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}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||||
|
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
213
src/modules/MouseUtils/CursorWrap/CursorWrapTests.h
Normal file
213
src/modules/MouseUtils/CursorWrap/CursorWrapTests.h
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// Test case structure for comprehensive monitor layout testing
|
||||||
|
struct MonitorTestCase
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::string description;
|
||||||
|
int grid[3][3]; // 3x3 grid representing monitor layout (0 = no monitor, 1-9 = monitor ID)
|
||||||
|
|
||||||
|
// Test scenarios to validate
|
||||||
|
struct TestScenario
|
||||||
|
{
|
||||||
|
int sourceMonitor; // Which monitor to start cursor on (1-based)
|
||||||
|
int edgeDirection; // 0=top, 1=right, 2=bottom, 3=left
|
||||||
|
int expectedTargetMonitor; // Expected destination monitor (1-based, -1 = wrap within same monitor)
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<TestScenario> scenarios;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Comprehensive test cases for all possible 3x3 monitor grid configurations
|
||||||
|
class CursorWrapTestSuite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::vector<MonitorTestCase> GetAllTestCases()
|
||||||
|
{
|
||||||
|
std::vector<MonitorTestCase> testCases;
|
||||||
|
|
||||||
|
// Test Case 1: Single monitor (center)
|
||||||
|
testCases.push_back({
|
||||||
|
"Single_Center",
|
||||||
|
"Single monitor in center position",
|
||||||
|
{
|
||||||
|
{0, 0, 0},
|
||||||
|
{0, 1, 0},
|
||||||
|
{0, 0, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{1, 0, -1, "Top edge wraps to bottom of same monitor"},
|
||||||
|
{1, 1, -1, "Right edge wraps to left of same monitor"},
|
||||||
|
{1, 2, -1, "Bottom edge wraps to top of same monitor"},
|
||||||
|
{1, 3, -1, "Left edge wraps to right of same monitor"}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test Case 2: Two monitors horizontal (left + right)
|
||||||
|
testCases.push_back({
|
||||||
|
"Dual_Horizontal_Left_Right",
|
||||||
|
"Two monitors: left + right",
|
||||||
|
{
|
||||||
|
{0, 0, 0},
|
||||||
|
{1, 0, 2},
|
||||||
|
{0, 0, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{1, 0, -1, "Monitor 1 top wraps to bottom of monitor 1"},
|
||||||
|
{1, 1, 2, "Monitor 1 right edge moves to monitor 2 left"},
|
||||||
|
{1, 2, -1, "Monitor 1 bottom wraps to top of monitor 1"},
|
||||||
|
{1, 3, -1, "Monitor 1 left edge wraps to right of monitor 1"},
|
||||||
|
{2, 0, -1, "Monitor 2 top wraps to bottom of monitor 2"},
|
||||||
|
{2, 1, -1, "Monitor 2 right edge wraps to left of monitor 2"},
|
||||||
|
{2, 2, -1, "Monitor 2 bottom wraps to top of monitor 2"},
|
||||||
|
{2, 3, 1, "Monitor 2 left edge moves to monitor 1 right"}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test Case 3: Two monitors vertical (Monitor 2 above Monitor 1) - CORRECTED FOR USER'S SETUP
|
||||||
|
testCases.push_back({
|
||||||
|
"Dual_Vertical_2_Above_1",
|
||||||
|
"Two monitors: Monitor 2 (top) above Monitor 1 (bottom/main)",
|
||||||
|
{
|
||||||
|
{0, 2, 0}, // Row 0: Monitor 2 (physically top monitor)
|
||||||
|
{0, 0, 0}, // Row 1: Empty
|
||||||
|
{0, 1, 0} // Row 2: Monitor 1 (physically bottom/main monitor)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Monitor 1 (bottom/main monitor) tests
|
||||||
|
{1, 0, 2, "Monitor 1 (bottom) top edge should move to Monitor 2 (top) bottom"},
|
||||||
|
{1, 1, -1, "Monitor 1 right wraps to left of monitor 1"},
|
||||||
|
{1, 2, -1, "Monitor 1 bottom wraps to top of monitor 1"},
|
||||||
|
{1, 3, -1, "Monitor 1 left wraps to right of monitor 1"},
|
||||||
|
|
||||||
|
// Monitor 2 (top monitor) tests
|
||||||
|
{2, 0, -1, "Monitor 2 (top) top wraps to bottom of monitor 2"},
|
||||||
|
{2, 1, -1, "Monitor 2 right wraps to left of monitor 2"},
|
||||||
|
{2, 2, 1, "Monitor 2 (top) bottom edge should move to Monitor 1 (bottom) top"},
|
||||||
|
{2, 3, -1, "Monitor 2 left wraps to right of monitor 2"}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test Case 4: Three monitors L-shape (center + left + top)
|
||||||
|
testCases.push_back({
|
||||||
|
"Triple_L_Shape",
|
||||||
|
"Three monitors in L-shape: center + left + top",
|
||||||
|
{
|
||||||
|
{0, 3, 0},
|
||||||
|
{2, 1, 0},
|
||||||
|
{0, 0, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{1, 0, 3, "Monitor 1 top moves to monitor 3 bottom"},
|
||||||
|
{1, 1, -1, "Monitor 1 right wraps to left of monitor 1"},
|
||||||
|
{1, 2, -1, "Monitor 1 bottom wraps to top of monitor 1"},
|
||||||
|
{1, 3, 2, "Monitor 1 left moves to monitor 2 right"},
|
||||||
|
{2, 0, -1, "Monitor 2 top wraps to bottom of monitor 2"},
|
||||||
|
{2, 1, 1, "Monitor 2 right moves to monitor 1 left"},
|
||||||
|
{2, 2, -1, "Monitor 2 bottom wraps to top of monitor 2"},
|
||||||
|
{2, 3, -1, "Monitor 2 left wraps to right of monitor 2"},
|
||||||
|
{3, 0, -1, "Monitor 3 top wraps to bottom of monitor 3"},
|
||||||
|
{3, 1, -1, "Monitor 3 right wraps to left of monitor 3"},
|
||||||
|
{3, 2, 1, "Monitor 3 bottom moves to monitor 1 top"},
|
||||||
|
{3, 3, -1, "Monitor 3 left wraps to right of monitor 3"}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test Case 5: Three monitors horizontal (left + center + right)
|
||||||
|
testCases.push_back({
|
||||||
|
"Triple_Horizontal",
|
||||||
|
"Three monitors horizontal: left + center + right",
|
||||||
|
{
|
||||||
|
{0, 0, 0},
|
||||||
|
{1, 2, 3},
|
||||||
|
{0, 0, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{1, 0, -1, "Monitor 1 top wraps to bottom"},
|
||||||
|
{1, 1, 2, "Monitor 1 right moves to monitor 2"},
|
||||||
|
{1, 2, -1, "Monitor 1 bottom wraps to top"},
|
||||||
|
{1, 3, -1, "Monitor 1 left wraps to right"},
|
||||||
|
{2, 0, -1, "Monitor 2 top wraps to bottom"},
|
||||||
|
{2, 1, 3, "Monitor 2 right moves to monitor 3"},
|
||||||
|
{2, 2, -1, "Monitor 2 bottom wraps to top"},
|
||||||
|
{2, 3, 1, "Monitor 2 left moves to monitor 1"},
|
||||||
|
{3, 0, -1, "Monitor 3 top wraps to bottom"},
|
||||||
|
{3, 1, -1, "Monitor 3 right wraps to left"},
|
||||||
|
{3, 2, -1, "Monitor 3 bottom wraps to top"},
|
||||||
|
{3, 3, 2, "Monitor 3 left moves to monitor 2"}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test Case 6: Three monitors vertical (top + center + bottom)
|
||||||
|
testCases.push_back({
|
||||||
|
"Triple_Vertical",
|
||||||
|
"Three monitors vertical: top + center + bottom",
|
||||||
|
{
|
||||||
|
{0, 1, 0},
|
||||||
|
{0, 2, 0},
|
||||||
|
{0, 3, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{1, 0, -1, "Monitor 1 top wraps to bottom"},
|
||||||
|
{1, 1, -1, "Monitor 1 right wraps to left"},
|
||||||
|
{1, 2, 2, "Monitor 1 bottom moves to monitor 2"},
|
||||||
|
{1, 3, -1, "Monitor 1 left wraps to right"},
|
||||||
|
{2, 0, 1, "Monitor 2 top moves to monitor 1"},
|
||||||
|
{2, 1, -1, "Monitor 2 right wraps to left"},
|
||||||
|
{2, 2, 3, "Monitor 2 bottom moves to monitor 3"},
|
||||||
|
{2, 3, -1, "Monitor 2 left wraps to right"},
|
||||||
|
{3, 0, 2, "Monitor 3 top moves to monitor 2"},
|
||||||
|
{3, 1, -1, "Monitor 3 right wraps to left"},
|
||||||
|
{3, 2, -1, "Monitor 3 bottom wraps to top"},
|
||||||
|
{3, 3, -1, "Monitor 3 left wraps to right"}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return testCases;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to print test case in a readable format
|
||||||
|
static std::string FormatTestCase(const MonitorTestCase& testCase)
|
||||||
|
{
|
||||||
|
std::string result = "Test Case: " + testCase.name + "\n";
|
||||||
|
result += "Description: " + testCase.description + "\n";
|
||||||
|
result += "Layout:\n";
|
||||||
|
|
||||||
|
for (int row = 0; row < 3; row++)
|
||||||
|
{
|
||||||
|
result += " ";
|
||||||
|
for (int col = 0; col < 3; col++)
|
||||||
|
{
|
||||||
|
if (testCase.grid[row][col] == 0)
|
||||||
|
{
|
||||||
|
result += ". ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result += std::to_string(testCase.grid[row][col]) + " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
result += "Test Scenarios:\n";
|
||||||
|
for (const auto& scenario : testCase.scenarios)
|
||||||
|
{
|
||||||
|
result += " - " + scenario.description + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to validate a specific test case against actual behavior
|
||||||
|
static bool ValidateTestCase(const MonitorTestCase& testCase)
|
||||||
|
{
|
||||||
|
// This would be called with actual CursorWrap instance to validate behavior
|
||||||
|
// For now, just return true - this would need actual implementation
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
1045
src/modules/MouseUtils/CursorWrap/dllmain.cpp
Normal file
1045
src/modules/MouseUtils/CursorWrap/dllmain.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4
src/modules/MouseUtils/CursorWrap/packages.config
Normal file
4
src/modules/MouseUtils/CursorWrap/packages.config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||||
|
</packages>
|
||||||
1
src/modules/MouseUtils/CursorWrap/pch.cpp
Normal file
1
src/modules/MouseUtils/CursorWrap/pch.cpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "pch.h"
|
||||||
13
src/modules/MouseUtils/CursorWrap/pch.h
Normal file
13
src/modules/MouseUtils/CursorWrap/pch.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Note: Common includes moved to individual source files due to include path issues
|
||||||
|
// #include <common/SettingsAPI/settings_helpers.h>
|
||||||
|
// #include <common/logger/logger.h>
|
||||||
|
// #include <common/utils/logger_helper.h>
|
||||||
4
src/modules/MouseUtils/CursorWrap/resource.h
Normal file
4
src/modules/MouseUtils/CursorWrap/resource.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define IDS_CURSORWRAP_NAME 101
|
||||||
|
#define IDS_CURSORWRAP_DISABLE_WRAP_DURING_DRAG 102
|
||||||
31
src/modules/MouseUtils/CursorWrap/trace.cpp
Normal file
31
src/modules/MouseUtils/CursorWrap/trace.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
#include "../../../../common/Telemetry/TraceBase.h"
|
||||||
|
|
||||||
|
TRACELOGGING_DEFINE_PROVIDER(
|
||||||
|
g_hProvider,
|
||||||
|
"Microsoft.PowerToys",
|
||||||
|
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||||
|
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||||
|
TraceLoggingOptionProjectTelemetry());
|
||||||
|
|
||||||
|
void Trace::RegisterProvider()
|
||||||
|
{
|
||||||
|
TraceLoggingRegister(g_hProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::UnregisterProvider()
|
||||||
|
{
|
||||||
|
TraceLoggingUnregister(g_hProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::EnableCursorWrap(const bool enabled) noexcept
|
||||||
|
{
|
||||||
|
TraceLoggingWriteWrapper(
|
||||||
|
g_hProvider,
|
||||||
|
"CursorWrap_EnableCursorWrap",
|
||||||
|
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||||
|
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||||
|
TraceLoggingBoolean(enabled, "Enabled"));
|
||||||
|
}
|
||||||
11
src/modules/MouseUtils/CursorWrap/trace.h
Normal file
11
src/modules/MouseUtils/CursorWrap/trace.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common/Telemetry/TraceBase.h>
|
||||||
|
|
||||||
|
class Trace : public telemetry::TraceBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void RegisterProvider();
|
||||||
|
static void UnregisterProvider();
|
||||||
|
static void EnableCursorWrap(const bool enabled) noexcept;
|
||||||
|
};
|
||||||
@@ -62,10 +62,18 @@
|
|||||||
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
|
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<!-- Only enable Native AOT for Release builds to avoid System.Private.CoreLib.dll version conflicts during development -->
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
<PublishTrimmed>true</PublishTrimmed>
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
<PublishAot>true</PublishAot>
|
<PublishAot>true</PublishAot>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- For Debug builds, use standard JIT compilation -->
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
||||||
|
<PublishTrimmed>false</PublishTrimmed>
|
||||||
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
<PublishAot>false</PublishAot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
|||||||
L"PowerToys.MouseJump.dll",
|
L"PowerToys.MouseJump.dll",
|
||||||
L"PowerToys.AlwaysOnTopModuleInterface.dll",
|
L"PowerToys.AlwaysOnTopModuleInterface.dll",
|
||||||
L"PowerToys.MousePointerCrosshairs.dll",
|
L"PowerToys.MousePointerCrosshairs.dll",
|
||||||
|
L"PowerToys.CursorWrap.dll",
|
||||||
L"PowerToys.PowerAccentModuleInterface.dll",
|
L"PowerToys.PowerAccentModuleInterface.dll",
|
||||||
L"PowerToys.PowerOCRModuleInterface.dll",
|
L"PowerToys.PowerOCRModuleInterface.dll",
|
||||||
L"PowerToys.AdvancedPasteModuleInterface.dll",
|
L"PowerToys.AdvancedPasteModuleInterface.dll",
|
||||||
|
|||||||
32
src/settings-ui/Settings.UI.Library/CursorWrapProperties.cs
Normal file
32
src/settings-ui/Settings.UI.Library/CursorWrapProperties.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// 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 System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
using Settings.UI.Library.Attributes;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||||
|
{
|
||||||
|
public class CursorWrapProperties
|
||||||
|
{
|
||||||
|
[CmdConfigureIgnore]
|
||||||
|
public HotkeySettings DefaultActivationShortcut => new HotkeySettings(true, false, true, false, 0x55); // Win + Alt + U
|
||||||
|
|
||||||
|
[JsonPropertyName("activation_shortcut")]
|
||||||
|
public HotkeySettings ActivationShortcut { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("auto_activate")]
|
||||||
|
public BoolProperty AutoActivate { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("disable_wrap_during_drag")]
|
||||||
|
public BoolProperty DisableWrapDuringDrag { get; set; }
|
||||||
|
|
||||||
|
public CursorWrapProperties()
|
||||||
|
{
|
||||||
|
ActivationShortcut = DefaultActivationShortcut;
|
||||||
|
AutoActivate = new BoolProperty(false);
|
||||||
|
DisableWrapDuringDrag = new BoolProperty(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/settings-ui/Settings.UI.Library/CursorWrapSettings.cs
Normal file
53
src/settings-ui/Settings.UI.Library/CursorWrapSettings.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// 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 System.Collections.Generic;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||||
|
{
|
||||||
|
public class CursorWrapSettings : BasePTModuleSettings, ISettingsConfig, IHotkeyConfig
|
||||||
|
{
|
||||||
|
public const string ModuleName = "CursorWrap";
|
||||||
|
|
||||||
|
[JsonPropertyName("properties")]
|
||||||
|
public CursorWrapProperties Properties { get; set; }
|
||||||
|
|
||||||
|
public CursorWrapSettings()
|
||||||
|
{
|
||||||
|
Name = ModuleName;
|
||||||
|
Properties = new CursorWrapProperties();
|
||||||
|
Version = "1.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetModuleName()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModuleType GetModuleType() => ModuleType.CursorWrap;
|
||||||
|
|
||||||
|
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||||
|
{
|
||||||
|
var hotkeyAccessors = new List<HotkeyAccessor>
|
||||||
|
{
|
||||||
|
new HotkeyAccessor(
|
||||||
|
() => Properties.ActivationShortcut,
|
||||||
|
value => Properties.ActivationShortcut = value ?? Properties.DefaultActivationShortcut,
|
||||||
|
"MouseUtils_CursorWrap_ActivationShortcut"),
|
||||||
|
};
|
||||||
|
|
||||||
|
return hotkeyAccessors.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This can be utilized in the future if the settings.json file is to be modified/deleted.
|
||||||
|
public bool UpgradeSettingsConfiguration()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -513,6 +513,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool cursorWrap; // defaulting to off
|
||||||
|
|
||||||
|
[JsonPropertyName("CursorWrap")]
|
||||||
|
public bool CursorWrap
|
||||||
|
{
|
||||||
|
get => cursorWrap;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (cursorWrap != value)
|
||||||
|
{
|
||||||
|
LogTelemetryEvent(value);
|
||||||
|
cursorWrap = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool lightSwitch;
|
private bool lightSwitch;
|
||||||
|
|
||||||
[JsonPropertyName("LightSwitch")]
|
[JsonPropertyName("LightSwitch")]
|
||||||
|
|||||||
29
src/settings-ui/Settings.UI.Library/SndCursorWrapSettings.cs
Normal file
29
src/settings-ui/Settings.UI.Library/SndCursorWrapSettings.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// 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 System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||||
|
{
|
||||||
|
public class SndCursorWrapSettings
|
||||||
|
{
|
||||||
|
[JsonPropertyName("CursorWrap")]
|
||||||
|
public CursorWrapSettings CursorWrap { get; set; }
|
||||||
|
|
||||||
|
public SndCursorWrapSettings()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SndCursorWrapSettings(CursorWrapSettings settings)
|
||||||
|
{
|
||||||
|
CursorWrap = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToJsonString()
|
||||||
|
{
|
||||||
|
return JsonSerializer.Serialize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/settings-ui/Settings.UI/Assets/Settings/Icons/CursorWrap.png
Normal file
BIN
src/settings-ui/Settings.UI/Assets/Settings/Icons/CursorWrap.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -22,7 +22,8 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
|||||||
case ModuleType.FindMyMouse:
|
case ModuleType.FindMyMouse:
|
||||||
case ModuleType.MouseHighlighter:
|
case ModuleType.MouseHighlighter:
|
||||||
case ModuleType.MouseJump:
|
case ModuleType.MouseJump:
|
||||||
case ModuleType.MousePointerCrosshairs: return $"MouseUtils_{moduleType}/Header";
|
case ModuleType.MousePointerCrosshairs:
|
||||||
|
case ModuleType.CursorWrap: return $"MouseUtils_{moduleType}/Header";
|
||||||
default: return $"{moduleType}/ModuleTitle";
|
default: return $"{moduleType}/ModuleTitle";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,6 +53,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
|||||||
case ModuleType.CmdPal: return generalSettingsConfig.Enabled.CmdPal;
|
case ModuleType.CmdPal: return generalSettingsConfig.Enabled.CmdPal;
|
||||||
case ModuleType.ColorPicker: return generalSettingsConfig.Enabled.ColorPicker;
|
case ModuleType.ColorPicker: return generalSettingsConfig.Enabled.ColorPicker;
|
||||||
case ModuleType.CropAndLock: return generalSettingsConfig.Enabled.CropAndLock;
|
case ModuleType.CropAndLock: return generalSettingsConfig.Enabled.CropAndLock;
|
||||||
|
case ModuleType.CursorWrap: return generalSettingsConfig.Enabled.CursorWrap;
|
||||||
case ModuleType.LightSwitch: return generalSettingsConfig.Enabled.LightSwitch;
|
case ModuleType.LightSwitch: return generalSettingsConfig.Enabled.LightSwitch;
|
||||||
case ModuleType.EnvironmentVariables: return generalSettingsConfig.Enabled.EnvironmentVariables;
|
case ModuleType.EnvironmentVariables: return generalSettingsConfig.Enabled.EnvironmentVariables;
|
||||||
case ModuleType.FancyZones: return generalSettingsConfig.Enabled.FancyZones;
|
case ModuleType.FancyZones: return generalSettingsConfig.Enabled.FancyZones;
|
||||||
@@ -89,6 +91,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
|||||||
case ModuleType.CmdPal: generalSettingsConfig.Enabled.CmdPal = isEnabled; break;
|
case ModuleType.CmdPal: generalSettingsConfig.Enabled.CmdPal = isEnabled; break;
|
||||||
case ModuleType.ColorPicker: generalSettingsConfig.Enabled.ColorPicker = isEnabled; break;
|
case ModuleType.ColorPicker: generalSettingsConfig.Enabled.ColorPicker = isEnabled; break;
|
||||||
case ModuleType.CropAndLock: generalSettingsConfig.Enabled.CropAndLock = isEnabled; break;
|
case ModuleType.CropAndLock: generalSettingsConfig.Enabled.CropAndLock = isEnabled; break;
|
||||||
|
case ModuleType.CursorWrap: generalSettingsConfig.Enabled.CursorWrap = isEnabled; break;
|
||||||
case ModuleType.LightSwitch: generalSettingsConfig.Enabled.LightSwitch = isEnabled; break;
|
case ModuleType.LightSwitch: generalSettingsConfig.Enabled.LightSwitch = isEnabled; break;
|
||||||
case ModuleType.EnvironmentVariables: generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break;
|
case ModuleType.EnvironmentVariables: generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break;
|
||||||
case ModuleType.FancyZones: generalSettingsConfig.Enabled.FancyZones = isEnabled; break;
|
case ModuleType.FancyZones: generalSettingsConfig.Enabled.FancyZones = isEnabled; break;
|
||||||
@@ -125,6 +128,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
|||||||
case ModuleType.CmdPal: return GPOWrapper.GetConfiguredCmdPalEnabledValue();
|
case ModuleType.CmdPal: return GPOWrapper.GetConfiguredCmdPalEnabledValue();
|
||||||
case ModuleType.ColorPicker: return GPOWrapper.GetConfiguredColorPickerEnabledValue();
|
case ModuleType.ColorPicker: return GPOWrapper.GetConfiguredColorPickerEnabledValue();
|
||||||
case ModuleType.CropAndLock: return GPOWrapper.GetConfiguredCropAndLockEnabledValue();
|
case ModuleType.CropAndLock: return GPOWrapper.GetConfiguredCropAndLockEnabledValue();
|
||||||
|
case ModuleType.CursorWrap: return GPOWrapper.GetConfiguredCursorWrapEnabledValue();
|
||||||
case ModuleType.EnvironmentVariables: return GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue();
|
case ModuleType.EnvironmentVariables: return GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue();
|
||||||
case ModuleType.FancyZones: return GPOWrapper.GetConfiguredFancyZonesEnabledValue();
|
case ModuleType.FancyZones: return GPOWrapper.GetConfiguredFancyZonesEnabledValue();
|
||||||
case ModuleType.FileLocksmith: return GPOWrapper.GetConfiguredFileLocksmithEnabledValue();
|
case ModuleType.FileLocksmith: return GPOWrapper.GetConfiguredFileLocksmithEnabledValue();
|
||||||
@@ -161,6 +165,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
|||||||
ModuleType.CmdPal => typeof(CmdPalPage),
|
ModuleType.CmdPal => typeof(CmdPalPage),
|
||||||
ModuleType.ColorPicker => typeof(ColorPickerPage),
|
ModuleType.ColorPicker => typeof(ColorPickerPage),
|
||||||
ModuleType.CropAndLock => typeof(CropAndLockPage),
|
ModuleType.CropAndLock => typeof(CropAndLockPage),
|
||||||
|
ModuleType.CursorWrap => typeof(MouseUtilsPage),
|
||||||
ModuleType.LightSwitch => typeof(LightSwitchPage),
|
ModuleType.LightSwitch => typeof(LightSwitchPage),
|
||||||
ModuleType.EnvironmentVariables => typeof(EnvironmentVariablesPage),
|
ModuleType.EnvironmentVariables => typeof(EnvironmentVariablesPage),
|
||||||
ModuleType.FancyZones => typeof(FancyZonesPage),
|
ModuleType.FancyZones => typeof(FancyZonesPage),
|
||||||
|
|||||||
@@ -273,6 +273,44 @@
|
|||||||
|
|
||||||
<panels:MouseJumpPanel x:Name="MouseUtils_MouseJump_Panel" x:Uid="MouseUtils_MouseJump_Panel" />
|
<panels:MouseJumpPanel x:Name="MouseUtils_MouseJump_Panel" x:Uid="MouseUtils_MouseJump_Panel" />
|
||||||
|
|
||||||
|
<controls:SettingsGroup x:Uid="MouseUtils_CursorWrap" AutomationProperties.AutomationId="MouseUtils_CursorWrapTestId">
|
||||||
|
<controls:GPOInfoControl ShowWarning="{x:Bind ViewModel.IsCursorWrapEnabledGpoConfigured, Mode=OneWay}">
|
||||||
|
<tkcontrols:SettingsCard
|
||||||
|
Name="MouseUtilsEnableCursorWrap"
|
||||||
|
x:Uid="MouseUtils_Enable_CursorWrap"
|
||||||
|
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/CursorWrap.png}"
|
||||||
|
IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||||
|
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
</controls:GPOInfoControl>
|
||||||
|
<tkcontrols:SettingsExpander
|
||||||
|
Name="MouseUtilsCursorWrapSettingsExpander"
|
||||||
|
x:Uid="MouseUtils_CursorWrap_ActivationShortcut"
|
||||||
|
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||||
|
IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=OneWay}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.CursorWrapActivationShortcut, Mode=TwoWay}" />
|
||||||
|
<tkcontrols:SettingsExpander.Items>
|
||||||
|
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||||
|
<CheckBox x:Uid="MouseUtils_AutoActivate" IsChecked="{x:Bind ViewModel.CursorWrapAutoActivate, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
</tkcontrols:SettingsExpander.Items>
|
||||||
|
</tkcontrols:SettingsExpander>
|
||||||
|
|
||||||
|
<tkcontrols:SettingsExpander
|
||||||
|
Name="CursorWrapAppearanceBehavior"
|
||||||
|
x:Uid="Appearance_Behavior"
|
||||||
|
AutomationProperties.AutomationId="MouseUtils_CursorWrapAppearanceBehaviorId"
|
||||||
|
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||||
|
IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=OneWay}"
|
||||||
|
IsExpanded="False">
|
||||||
|
<tkcontrols:SettingsExpander.Items>
|
||||||
|
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||||
|
<CheckBox x:Uid="MouseUtils_CursorWrap_DisableWrapDuringDrag" IsChecked="{x:Bind ViewModel.CursorWrapDisableWrapDuringDrag, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
</tkcontrols:SettingsExpander.Items>
|
||||||
|
</tkcontrols:SettingsExpander>
|
||||||
|
</controls:SettingsGroup>
|
||||||
<controls:SettingsGroup x:Uid="MouseUtils_MousePointerCrosshairs" AutomationProperties.AutomationId="MouseUtils_MousePointerCrosshairsTestId">
|
<controls:SettingsGroup x:Uid="MouseUtils_MousePointerCrosshairs" AutomationProperties.AutomationId="MouseUtils_MousePointerCrosshairsTestId">
|
||||||
<controls:GPOInfoControl ShowWarning="{x:Bind ViewModel.IsMousePointerCrosshairsEnabledGpoConfigured, Mode=OneWay}">
|
<controls:GPOInfoControl ShowWarning="{x:Bind ViewModel.IsMousePointerCrosshairsEnabledGpoConfigured, Mode=OneWay}">
|
||||||
<tkcontrols:SettingsCard
|
<tkcontrols:SettingsCard
|
||||||
@@ -285,7 +323,6 @@
|
|||||||
IsOn="{x:Bind ViewModel.IsMousePointerCrosshairsEnabled, Mode=TwoWay}" />
|
IsOn="{x:Bind ViewModel.IsMousePointerCrosshairsEnabled, Mode=TwoWay}" />
|
||||||
</tkcontrols:SettingsCard>
|
</tkcontrols:SettingsCard>
|
||||||
</controls:GPOInfoControl>
|
</controls:GPOInfoControl>
|
||||||
|
|
||||||
<tkcontrols:SettingsExpander
|
<tkcontrols:SettingsExpander
|
||||||
Name="MouseUtilsMousePointerCrosshairsActivationShortcut"
|
Name="MouseUtilsMousePointerCrosshairsActivationShortcut"
|
||||||
x:Uid="MouseUtils_MousePointerCrosshairs_ActivationShortcut"
|
x:Uid="MouseUtils_MousePointerCrosshairs_ActivationShortcut"
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
SettingsRepository<MouseHighlighterSettings>.GetInstance(settingsUtils),
|
SettingsRepository<MouseHighlighterSettings>.GetInstance(settingsUtils),
|
||||||
SettingsRepository<MouseJumpSettings>.GetInstance(settingsUtils),
|
SettingsRepository<MouseJumpSettings>.GetInstance(settingsUtils),
|
||||||
SettingsRepository<MousePointerCrosshairsSettings>.GetInstance(settingsUtils),
|
SettingsRepository<MousePointerCrosshairsSettings>.GetInstance(settingsUtils),
|
||||||
|
SettingsRepository<CursorWrapSettings>.GetInstance(settingsUtils),
|
||||||
ShellPage.SendDefaultIPCMessage);
|
ShellPage.SendDefaultIPCMessage);
|
||||||
|
|
||||||
DataContext = ViewModel;
|
DataContext = ViewModel;
|
||||||
|
|||||||
@@ -2696,11 +2696,46 @@ From there, simply click on one of the supported files in the File Explorer and
|
|||||||
<value>Use a keyboard shortcut to highlight left and right mouse clicks.</value>
|
<value>Use a keyboard shortcut to highlight left and right mouse clicks.</value>
|
||||||
<comment>Mouse as in the hardware peripheral.</comment>
|
<comment>Mouse as in the hardware peripheral.</comment>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<!-- CursorWrap Module -->
|
||||||
|
<data name="MouseUtils_Enable_CursorWrap.Header" xml:space="preserve">
|
||||||
|
<value>Enable CursorWrap</value>
|
||||||
|
</data>
|
||||||
|
<data name="MouseUtils_CursorWrap.Header" xml:space="preserve">
|
||||||
|
<value>CursorWrap</value>
|
||||||
|
</data>
|
||||||
|
<data name="MouseUtils_CursorWrap.Description" xml:space="preserve">
|
||||||
|
<value>Wrap the mouse cursor between monitor edges</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<!-- Activation Shortcut -->
|
||||||
|
<data name="MouseUtils_CursorWrap_ActivationShortcut.Header" xml:space="preserve">
|
||||||
|
<value>Activation shortcut</value>
|
||||||
|
</data>
|
||||||
|
<data name="MouseUtils_CursorWrap_ActivationShortcut_Description.Text" xml:space="preserve">
|
||||||
|
<value>Hotkey to toggle cursor wrapping on/off</value>
|
||||||
|
</data>
|
||||||
|
<data name="MouseUtils_CursorWrap_ActivationShortcut_Button.Content" xml:space="preserve">
|
||||||
|
<value>Set shortcut</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<data name="MouseUtils_CursorWrap_DisableWrapDuringDrag.Content" xml:space="preserve">
|
||||||
|
<value>Disable wrapping while dragging</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<!-- Auto-activate -->
|
||||||
|
<data name="MouseUtils_CursorWrap_AutoActivate.Header" xml:space="preserve">
|
||||||
|
<value>Auto-activate on startup</value>
|
||||||
|
</data>
|
||||||
|
<data name="MouseUtils_CursorWrap_AutoActivate.Content" xml:space="preserve">
|
||||||
|
<value>Automatically activate on utility startup</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<data name="Oobe_MouseUtils_MousePointerCrosshairs.Text" xml:space="preserve">
|
<data name="Oobe_MouseUtils_MousePointerCrosshairs.Text" xml:space="preserve">
|
||||||
<value>Mouse Pointer Crosshairs</value>
|
<value>Mouse Pointer Crosshairs</value>
|
||||||
<comment>Mouse as in the hardware peripheral.</comment>
|
<comment>Mouse as in the hardware peripheral.</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="Oobe_MouseUtils_MousePointerCrosshairs_Description.Text" xml:space="preserve">
|
<data name="Oobe_MouseUtils_MousePointerCrosshairs.Description" xml:space="preserve">
|
||||||
<value>Draw crosshairs centered around the mouse pointer.</value>
|
<value>Draw crosshairs centered around the mouse pointer.</value>
|
||||||
<comment>Mouse as in the hardware peripheral.</comment>
|
<comment>Mouse as in the hardware peripheral.</comment>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
private MousePointerCrosshairsSettings MousePointerCrosshairsSettingsConfig { get; set; }
|
private MousePointerCrosshairsSettings MousePointerCrosshairsSettingsConfig { get; set; }
|
||||||
|
|
||||||
public MouseUtilsViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<FindMyMouseSettings> findMyMouseSettingsRepository, ISettingsRepository<MouseHighlighterSettings> mouseHighlighterSettingsRepository, ISettingsRepository<MouseJumpSettings> mouseJumpSettingsRepository, ISettingsRepository<MousePointerCrosshairsSettings> mousePointerCrosshairsSettingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
private CursorWrapSettings CursorWrapSettingsConfig { get; set; }
|
||||||
|
|
||||||
|
public MouseUtilsViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<FindMyMouseSettings> findMyMouseSettingsRepository, ISettingsRepository<MouseHighlighterSettings> mouseHighlighterSettingsRepository, ISettingsRepository<MouseJumpSettings> mouseJumpSettingsRepository, ISettingsRepository<MousePointerCrosshairsSettings> mousePointerCrosshairsSettingsRepository, ISettingsRepository<CursorWrapSettings> cursorWrapSettingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
||||||
{
|
{
|
||||||
SettingsUtils = settingsUtils;
|
SettingsUtils = settingsUtils;
|
||||||
|
|
||||||
@@ -103,6 +105,14 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
_mousePointerCrosshairsOrientation = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsOrientation.Value;
|
_mousePointerCrosshairsOrientation = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsOrientation.Value;
|
||||||
_mousePointerCrosshairsAutoActivate = MousePointerCrosshairsSettingsConfig.Properties.AutoActivate.Value;
|
_mousePointerCrosshairsAutoActivate = MousePointerCrosshairsSettingsConfig.Properties.AutoActivate.Value;
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(cursorWrapSettingsRepository);
|
||||||
|
|
||||||
|
CursorWrapSettingsConfig = cursorWrapSettingsRepository.SettingsConfig;
|
||||||
|
_cursorWrapAutoActivate = CursorWrapSettingsConfig.Properties.AutoActivate.Value;
|
||||||
|
|
||||||
|
// Null-safe access in case property wasn't upgraded yet - default to TRUE
|
||||||
|
_cursorWrapDisableWrapDuringDrag = CursorWrapSettingsConfig.Properties.DisableWrapDuringDrag?.Value ?? true;
|
||||||
|
|
||||||
int isEnabled = 0;
|
int isEnabled = 0;
|
||||||
|
|
||||||
Utilities.NativeMethods.SystemParametersInfo(Utilities.NativeMethods.SPI_GETCLIENTAREAANIMATION, 0, ref isEnabled, 0);
|
Utilities.NativeMethods.SystemParametersInfo(Utilities.NativeMethods.SPI_GETCLIENTAREAANIMATION, 0, ref isEnabled, 0);
|
||||||
@@ -144,13 +154,25 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
if (_mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
if (_mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
||||||
{
|
{
|
||||||
// Get the enabled state from GPO.
|
// Get the enabled state from GPO.
|
||||||
_mousePointerCrosshairsEnabledStateIsGPOConfigured = true;
|
_mousePointerCrosshairsEnabledStateGPOConfigured = true;
|
||||||
_isMousePointerCrosshairsEnabled = _mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
_isMousePointerCrosshairsEnabled = _mousePointerCrosshairsEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_isMousePointerCrosshairsEnabled = GeneralSettingsConfig.Enabled.MousePointerCrosshairs;
|
_isMousePointerCrosshairsEnabled = GeneralSettingsConfig.Enabled.MousePointerCrosshairs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cursorWrapEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredCursorWrapEnabledValue();
|
||||||
|
if (_cursorWrapEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _cursorWrapEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
||||||
|
{
|
||||||
|
// Get the enabled state from GPO.
|
||||||
|
_cursorWrapEnabledStateIsGPOConfigured = true;
|
||||||
|
_isCursorWrapEnabled = _cursorWrapEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_isCursorWrapEnabled = GeneralSettingsConfig.Enabled.CursorWrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Dictionary<string, HotkeySettings[]> GetAllHotkeySettings()
|
public override Dictionary<string, HotkeySettings[]> GetAllHotkeySettings()
|
||||||
@@ -163,6 +185,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
MousePointerCrosshairsActivationShortcut,
|
MousePointerCrosshairsActivationShortcut,
|
||||||
GlidingCursorActivationShortcut],
|
GlidingCursorActivationShortcut],
|
||||||
[MouseJumpSettings.ModuleName] = [MouseJumpActivationShortcut],
|
[MouseJumpSettings.ModuleName] = [MouseJumpActivationShortcut],
|
||||||
|
[CursorWrapSettings.ModuleName] = [CursorWrapActivationShortcut],
|
||||||
};
|
};
|
||||||
|
|
||||||
return hotkeysDict;
|
return hotkeysDict;
|
||||||
@@ -663,7 +686,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
get => _isMousePointerCrosshairsEnabled;
|
get => _isMousePointerCrosshairsEnabled;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_mousePointerCrosshairsEnabledStateIsGPOConfigured)
|
if (_mousePointerCrosshairsEnabledStateGPOConfigured)
|
||||||
{
|
{
|
||||||
// If it's GPO configured, shouldn't be able to change this state.
|
// If it's GPO configured, shouldn't be able to change this state.
|
||||||
return;
|
return;
|
||||||
@@ -686,7 +709,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
public bool IsMousePointerCrosshairsEnabledGpoConfigured
|
public bool IsMousePointerCrosshairsEnabledGpoConfigured
|
||||||
{
|
{
|
||||||
get => _mousePointerCrosshairsEnabledStateIsGPOConfigured;
|
get => _mousePointerCrosshairsEnabledStateGPOConfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HotkeySettings MousePointerCrosshairsActivationShortcut
|
public HotkeySettings MousePointerCrosshairsActivationShortcut
|
||||||
@@ -959,6 +982,110 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
SettingsUtils.SaveSettings(MousePointerCrosshairsSettingsConfig.ToJsonString(), MousePointerCrosshairsSettings.ModuleName);
|
SettingsUtils.SaveSettings(MousePointerCrosshairsSettingsConfig.ToJsonString(), MousePointerCrosshairsSettings.ModuleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsCursorWrapEnabled
|
||||||
|
{
|
||||||
|
get => _isCursorWrapEnabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_cursorWrapEnabledStateIsGPOConfigured)
|
||||||
|
{
|
||||||
|
// If it's GPO configured, shouldn't be able to change this state.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isCursorWrapEnabled != value)
|
||||||
|
{
|
||||||
|
_isCursorWrapEnabled = value;
|
||||||
|
|
||||||
|
GeneralSettingsConfig.Enabled.CursorWrap = value;
|
||||||
|
OnPropertyChanged(nameof(IsCursorWrapEnabled));
|
||||||
|
|
||||||
|
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||||
|
SendConfigMSG(outgoing.ToString());
|
||||||
|
|
||||||
|
NotifyCursorWrapPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCursorWrapEnabledGpoConfigured
|
||||||
|
{
|
||||||
|
get => _cursorWrapEnabledStateIsGPOConfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotkeySettings CursorWrapActivationShortcut
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return CursorWrapSettingsConfig.Properties.ActivationShortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (CursorWrapSettingsConfig.Properties.ActivationShortcut != value)
|
||||||
|
{
|
||||||
|
CursorWrapSettingsConfig.Properties.ActivationShortcut = value ?? CursorWrapSettingsConfig.Properties.DefaultActivationShortcut;
|
||||||
|
NotifyCursorWrapPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CursorWrapAutoActivate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _cursorWrapAutoActivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _cursorWrapAutoActivate)
|
||||||
|
{
|
||||||
|
_cursorWrapAutoActivate = value;
|
||||||
|
CursorWrapSettingsConfig.Properties.AutoActivate.Value = value;
|
||||||
|
NotifyCursorWrapPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CursorWrapDisableWrapDuringDrag
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _cursorWrapDisableWrapDuringDrag;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _cursorWrapDisableWrapDuringDrag)
|
||||||
|
{
|
||||||
|
_cursorWrapDisableWrapDuringDrag = value;
|
||||||
|
|
||||||
|
// Ensure the property exists before setting value
|
||||||
|
if (CursorWrapSettingsConfig.Properties.DisableWrapDuringDrag == null)
|
||||||
|
{
|
||||||
|
CursorWrapSettingsConfig.Properties.DisableWrapDuringDrag = new BoolProperty(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CursorWrapSettingsConfig.Properties.DisableWrapDuringDrag.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
NotifyCursorWrapPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifyCursorWrapPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(propertyName);
|
||||||
|
|
||||||
|
SndCursorWrapSettings outsettings = new SndCursorWrapSettings(CursorWrapSettingsConfig);
|
||||||
|
SndModuleSettings<SndCursorWrapSettings> ipcMessage = new SndModuleSettings<SndCursorWrapSettings>(outsettings);
|
||||||
|
SendConfigMSG(ipcMessage.ToJsonString());
|
||||||
|
SettingsUtils.SaveSettings(CursorWrapSettingsConfig.ToJsonString(), CursorWrapSettings.ModuleName);
|
||||||
|
}
|
||||||
|
|
||||||
public void RefreshEnabledState()
|
public void RefreshEnabledState()
|
||||||
{
|
{
|
||||||
InitializeEnabledValues();
|
InitializeEnabledValues();
|
||||||
@@ -966,6 +1093,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
OnPropertyChanged(nameof(IsMouseHighlighterEnabled));
|
OnPropertyChanged(nameof(IsMouseHighlighterEnabled));
|
||||||
OnPropertyChanged(nameof(IsMouseJumpEnabled));
|
OnPropertyChanged(nameof(IsMouseJumpEnabled));
|
||||||
OnPropertyChanged(nameof(IsMousePointerCrosshairsEnabled));
|
OnPropertyChanged(nameof(IsMousePointerCrosshairsEnabled));
|
||||||
|
OnPropertyChanged(nameof(IsCursorWrapEnabled));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Func<string, int> SendConfigMSG { get; }
|
private Func<string, int> SendConfigMSG { get; }
|
||||||
@@ -999,7 +1127,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
private bool _highlighterAutoActivate;
|
private bool _highlighterAutoActivate;
|
||||||
|
|
||||||
private GpoRuleConfigured _mousePointerCrosshairsEnabledGpoRuleConfiguration;
|
private GpoRuleConfigured _mousePointerCrosshairsEnabledGpoRuleConfiguration;
|
||||||
private bool _mousePointerCrosshairsEnabledStateIsGPOConfigured;
|
private bool _mousePointerCrosshairsEnabledStateGPOConfigured;
|
||||||
private bool _isMousePointerCrosshairsEnabled;
|
private bool _isMousePointerCrosshairsEnabled;
|
||||||
private string _mousePointerCrosshairsColor;
|
private string _mousePointerCrosshairsColor;
|
||||||
private int _mousePointerCrosshairsOpacity;
|
private int _mousePointerCrosshairsOpacity;
|
||||||
@@ -1013,5 +1141,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
private int _mousePointerCrosshairsOrientation;
|
private int _mousePointerCrosshairsOrientation;
|
||||||
private bool _mousePointerCrosshairsAutoActivate;
|
private bool _mousePointerCrosshairsAutoActivate;
|
||||||
private bool _isAnimationEnabledBySystem;
|
private bool _isAnimationEnabledBySystem;
|
||||||
|
|
||||||
|
private GpoRuleConfigured _cursorWrapEnabledGpoRuleConfiguration;
|
||||||
|
private bool _cursorWrapEnabledStateIsGPOConfigured;
|
||||||
|
private bool _isCursorWrapEnabled;
|
||||||
|
private bool _cursorWrapAutoActivate;
|
||||||
|
private bool _cursorWrapDisableWrapDuringDrag; // Will be initialized in constructor from settings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user