mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
[Cursor Wrap] Update edge wrap model, update simulator, add cursor logging, add settings support to ModuleLoader (#45915)
This PR adds new options for disabling wrap, updates the wrapping model, extends the simulator and cursor logging. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #45116 - [ ] Closes: #44955 - [ ] Closes: #44827 - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [x] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx The PR adds a new option for disabling cursor wrapping, exposing three options: None - wrapping is not disabled, Ctrl key - if this is pressed then wrapping is disabled, Shift key - if this is pressed then wrapping is disabled, this would enable a user to temporarily disable wrapping if they wanted to get close to a monitor edge without wrapping (auto-hide status bar for example). The cursor wrap edge model has been updated to mirror Windows monitor-to-monitor cursor movement, this should ensure there aren't any non-wrappable edges. A new test tool has been added 'CursorLog' this is a monitor aware, dpi/scaling aware Win32 application that captures mouse movement across monitors to a log file, the log contains one line per mouse movement which includes: Monitor, x, y, scale, dpi. The wrapping simulator has been updated to include the new wrapping model and support mouse cursor log playback. ## Validation Steps Performed The updated CursorWrap has been tested on a single monitor (laptop) and multi-monitor desktop PC with monitors being offset to test edge/wrapping behavior. --------- Co-authored-by: Mike Hall <mikehall@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: vanzue <vanzue@outlook.com>
This commit is contained in:
@@ -25,6 +25,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("wrap_mode")]
|
||||
public IntProperty WrapMode { get; set; }
|
||||
|
||||
[JsonPropertyName("activation_mode")]
|
||||
public IntProperty ActivationMode { get; set; }
|
||||
|
||||
[JsonPropertyName("disable_cursor_wrap_on_single_monitor")]
|
||||
public BoolProperty DisableCursorWrapOnSingleMonitor { get; set; }
|
||||
|
||||
@@ -34,6 +37,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
AutoActivate = new BoolProperty(false);
|
||||
DisableWrapDuringDrag = new BoolProperty(true);
|
||||
WrapMode = new IntProperty(0); // 0=Both (default), 1=VerticalOnly, 2=HorizontalOnly
|
||||
ActivationMode = new IntProperty(0); // 0=Always (default), 1=HoldingCtrl, 2=HoldingShift
|
||||
DisableCursorWrapOnSingleMonitor = new BoolProperty(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,13 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
settingsUpgraded = true;
|
||||
}
|
||||
|
||||
// Add ActivationMode property if it doesn't exist (for users upgrading from older versions)
|
||||
if (Properties.ActivationMode == null)
|
||||
{
|
||||
Properties.ActivationMode = new IntProperty(0); // Default to Always (0=Always, 1=HoldingCtrl, 2=HoldingShift)
|
||||
settingsUpgraded = true;
|
||||
}
|
||||
|
||||
// Add DisableCursorWrapOnSingleMonitor property if it doesn't exist (for users upgrading from older versions)
|
||||
if (Properties.DisableCursorWrapOnSingleMonitor == null)
|
||||
{
|
||||
|
||||
@@ -54,6 +54,13 @@
|
||||
<ComboBoxItem x:Uid="MouseUtils_CursorWrap_WrapMode_HorizontalOnly" />
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsCursorWrapActivationMode" x:Uid="MouseUtils_CursorWrap_ActivationMode">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.CursorWrapActivationMode, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="MouseUtils_CursorWrap_ActivationMode_Always" />
|
||||
<ComboBoxItem x:Uid="MouseUtils_CursorWrap_ActivationMode_HoldingCtrl" />
|
||||
<ComboBoxItem x:Uid="MouseUtils_CursorWrap_ActivationMode_HoldingShift" />
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=OneWay}">
|
||||
<CheckBox x:Uid="MouseUtils_CursorWrap_DisableOnSingleMonitor" IsChecked="{x:Bind ViewModel.CursorWrapDisableOnSingleMonitor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
@@ -2504,6 +2504,26 @@ From there, simply click on one of the supported files in the File Explorer and
|
||||
<data name="MouseUtils_CursorWrap_WrapMode_Both.Content" xml:space="preserve">
|
||||
<value>Vertical and horizontal</value>
|
||||
</data>
|
||||
<data name="MouseUtils_CursorWrap_ActivationMode.Header" xml:space="preserve">
|
||||
<value>Wrapping activation</value>
|
||||
<comment>CursorWrap: Label for activation mode dropdown</comment>
|
||||
</data>
|
||||
<data name="MouseUtils_CursorWrap_ActivationMode.Description" xml:space="preserve">
|
||||
<value>Control when cursor wrapping occurs as the pointer reaches the screen edge.</value>
|
||||
<comment>CursorWrap: Description for activation mode dropdown</comment>
|
||||
</data>
|
||||
<data name="MouseUtils_CursorWrap_ActivationMode_Always.Content" xml:space="preserve">
|
||||
<value>Always</value>
|
||||
<comment>CursorWrap: Activation mode - always wrap</comment>
|
||||
</data>
|
||||
<data name="MouseUtils_CursorWrap_ActivationMode_HoldingCtrl.Content" xml:space="preserve">
|
||||
<value>Holding Ctrl</value>
|
||||
<comment>CursorWrap: Activation mode - disable wrap when Ctrl held</comment>
|
||||
</data>
|
||||
<data name="MouseUtils_CursorWrap_ActivationMode_HoldingShift.Content" xml:space="preserve">
|
||||
<value>Holding Shift</value>
|
||||
<comment>CursorWrap: Activation mode - disable wrap when Shift held</comment>
|
||||
</data>
|
||||
<data name="Oobe_MouseUtils_MousePointerCrosshairs.Text" xml:space="preserve">
|
||||
<value>Mouse Pointer Crosshairs</value>
|
||||
<comment>Mouse as in the hardware peripheral.</comment>
|
||||
|
||||
@@ -116,6 +116,9 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
// Null-safe access in case property wasn't upgraded yet - default to 0 (Both)
|
||||
_cursorWrapWrapMode = CursorWrapSettingsConfig.Properties.WrapMode?.Value ?? 0;
|
||||
|
||||
// Null-safe access in case property wasn't upgraded yet - default to 0 (Always)
|
||||
_cursorWrapActivationMode = CursorWrapSettingsConfig.Properties.ActivationMode?.Value ?? 0;
|
||||
|
||||
// Null-safe access in case property wasn't upgraded yet - default to false
|
||||
_cursorWrapDisableOnSingleMonitor = CursorWrapSettingsConfig.Properties.DisableCursorWrapOnSingleMonitor?.Value ?? false;
|
||||
|
||||
@@ -1110,6 +1113,34 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public int CursorWrapActivationMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cursorWrapActivationMode;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _cursorWrapActivationMode)
|
||||
{
|
||||
_cursorWrapActivationMode = value;
|
||||
|
||||
// Ensure the property exists before setting value
|
||||
if (CursorWrapSettingsConfig.Properties.ActivationMode == null)
|
||||
{
|
||||
CursorWrapSettingsConfig.Properties.ActivationMode = new IntProperty(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
CursorWrapSettingsConfig.Properties.ActivationMode.Value = value;
|
||||
}
|
||||
|
||||
NotifyCursorWrapPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool CursorWrapDisableOnSingleMonitor
|
||||
{
|
||||
get
|
||||
@@ -1210,6 +1241,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private bool _cursorWrapAutoActivate;
|
||||
private bool _cursorWrapDisableWrapDuringDrag; // Will be initialized in constructor from settings
|
||||
private int _cursorWrapWrapMode; // 0=Both, 1=VerticalOnly, 2=HorizontalOnly
|
||||
private int _cursorWrapActivationMode; // 0=Always, 1=HoldingCtrl (disables wrap), 2=HoldingShift (disables wrap)
|
||||
private bool _cursorWrapDisableOnSingleMonitor; // Disable cursor wrap when only one monitor is connected
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user