diff --git a/src/modules/MouseUtils/MousePointerCrosshairs/InclusiveCrosshairs.cpp b/src/modules/MouseUtils/MousePointerCrosshairs/InclusiveCrosshairs.cpp index a6fca80090..66b273e48c 100644 --- a/src/modules/MouseUtils/MousePointerCrosshairs/InclusiveCrosshairs.cpp +++ b/src/modules/MouseUtils/MousePointerCrosshairs/InclusiveCrosshairs.cpp @@ -77,6 +77,8 @@ private: int m_crosshairs_radius = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_RADIUS; int m_crosshairs_thickness = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_THICKNESS; int m_crosshairs_border_size = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE; + bool m_crosshairs_is_fixed_length_enabled = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED; + int m_crosshairs_fixed_length = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_FIXED_LENGTH; float m_crosshairs_opacity = max(0.f, min(1.f, (float)INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_OPACITY / 100.0f)); bool m_crosshairs_auto_hide = INCLUSIVE_MOUSE_DEFAULT_AUTO_HIDE; }; @@ -214,27 +216,47 @@ void InclusiveCrosshairs::UpdateCrosshairsPosition() // Crosshair position should receive a minor adjustment for odd values to prevent anti-aliasing due to half pixels, while still looking like it's centered around the mouse pointer. float halfPixelAdjustment = m_crosshairs_thickness % 2 == 1 ? 0.5f : 0.0f; + float borderSizePadding = m_crosshairs_border_size * 2.f; - // Position crosshairs components around the mouse pointer. - m_left_crosshairs_border.Offset({ ptCursor.x - m_crosshairs_radius + m_crosshairs_border_size + halfPixelAdjustment * 2, ptCursor.y + halfPixelAdjustment, .0f }); - m_left_crosshairs_border.Size({ ptCursor.x - ptMonitorUpperLeft.x - m_crosshairs_radius + m_crosshairs_border_size + halfPixelAdjustment * 2, m_crosshairs_thickness + m_crosshairs_border_size * 2.f }); - m_left_crosshairs.Offset({ ptCursor.x - m_crosshairs_radius + halfPixelAdjustment * 2.f, ptCursor.y + halfPixelAdjustment, .0f }); - m_left_crosshairs.Size({ ptCursor.x - ptMonitorUpperLeft.x - m_crosshairs_radius + halfPixelAdjustment * 2, static_cast(m_crosshairs_thickness) }); + { + float leftCrosshairsFullScreenLength = ptCursor.x - ptMonitorUpperLeft.x - m_crosshairs_radius + halfPixelAdjustment * 2.f; + float leftCrosshairsLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length : leftCrosshairsFullScreenLength; + float leftCrosshairsBorderLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length + borderSizePadding : leftCrosshairsFullScreenLength + m_crosshairs_border_size; + m_left_crosshairs_border.Offset({ ptCursor.x - m_crosshairs_radius + m_crosshairs_border_size + halfPixelAdjustment * 2.f, ptCursor.y + halfPixelAdjustment, .0f }); + m_left_crosshairs_border.Size({ leftCrosshairsBorderLength, m_crosshairs_thickness + borderSizePadding }); + m_left_crosshairs.Offset({ ptCursor.x - m_crosshairs_radius + halfPixelAdjustment * 2.f, ptCursor.y + halfPixelAdjustment, .0f }); + m_left_crosshairs.Size({ leftCrosshairsLength, static_cast(m_crosshairs_thickness) }); + } - m_right_crosshairs_border.Offset({ static_cast(ptCursor.x) + m_crosshairs_radius - m_crosshairs_border_size, ptCursor.y + halfPixelAdjustment, .0f }); - m_right_crosshairs_border.Size({ static_cast(ptMonitorBottomRight.x) - ptCursor.x - m_crosshairs_radius + m_crosshairs_border_size, m_crosshairs_thickness + m_crosshairs_border_size * 2.f }); - m_right_crosshairs.Offset({ static_cast(ptCursor.x) + m_crosshairs_radius, ptCursor.y + halfPixelAdjustment, .0f }); - m_right_crosshairs.Size({ static_cast(ptMonitorBottomRight.x) - ptCursor.x - m_crosshairs_radius, static_cast(m_crosshairs_thickness) }); + { + float rightCrosshairsFullScreenLength = static_cast(ptMonitorBottomRight.x) - ptCursor.x - m_crosshairs_radius; + float rightCrosshairsLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length : rightCrosshairsFullScreenLength; + float rightCrosshairsBorderLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length + borderSizePadding : rightCrosshairsFullScreenLength + m_crosshairs_border_size; + m_right_crosshairs_border.Offset({ static_cast(ptCursor.x) + m_crosshairs_radius - m_crosshairs_border_size, ptCursor.y + halfPixelAdjustment, .0f }); + m_right_crosshairs_border.Size({ rightCrosshairsBorderLength, m_crosshairs_thickness + borderSizePadding }); + m_right_crosshairs.Offset({ static_cast(ptCursor.x) + m_crosshairs_radius, ptCursor.y + halfPixelAdjustment, .0f }); + m_right_crosshairs.Size({ rightCrosshairsLength, static_cast(m_crosshairs_thickness) }); + } - m_top_crosshairs_border.Offset({ ptCursor.x + halfPixelAdjustment, ptCursor.y - m_crosshairs_radius + m_crosshairs_border_size + halfPixelAdjustment * 2, .0f }); - m_top_crosshairs_border.Size({ m_crosshairs_thickness + m_crosshairs_border_size * 2.f, ptCursor.y - ptMonitorUpperLeft.y - m_crosshairs_radius + m_crosshairs_border_size + halfPixelAdjustment * 2 }); - m_top_crosshairs.Offset({ ptCursor.x + halfPixelAdjustment, ptCursor.y - m_crosshairs_radius + halfPixelAdjustment * 2, .0f }); - m_top_crosshairs.Size({ static_cast(m_crosshairs_thickness), ptCursor.y - ptMonitorUpperLeft.y - m_crosshairs_radius + halfPixelAdjustment * 2 }); + { + float topCrosshairsFullScreenLength = ptCursor.y - ptMonitorUpperLeft.y - m_crosshairs_radius + halfPixelAdjustment * 2.f; + float topCrosshairsLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length : topCrosshairsFullScreenLength; + float topCrosshairsBorderLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length + borderSizePadding : topCrosshairsFullScreenLength + m_crosshairs_border_size; + m_top_crosshairs_border.Offset({ ptCursor.x + halfPixelAdjustment, ptCursor.y - m_crosshairs_radius + m_crosshairs_border_size + halfPixelAdjustment * 2.f, .0f }); + m_top_crosshairs_border.Size({ m_crosshairs_thickness + borderSizePadding, topCrosshairsBorderLength }); + m_top_crosshairs.Offset({ ptCursor.x + halfPixelAdjustment, ptCursor.y - m_crosshairs_radius + halfPixelAdjustment * 2.f, .0f }); + m_top_crosshairs.Size({ static_cast(m_crosshairs_thickness), topCrosshairsLength }); + } - m_bottom_crosshairs_border.Offset({ ptCursor.x + halfPixelAdjustment, static_cast(ptCursor.y) + m_crosshairs_radius - m_crosshairs_border_size, .0f }); - m_bottom_crosshairs_border.Size({ m_crosshairs_thickness + m_crosshairs_border_size * 2.f, static_cast(ptMonitorBottomRight.y) - ptCursor.y - m_crosshairs_radius + m_crosshairs_border_size }); - m_bottom_crosshairs.Offset({ ptCursor.x + halfPixelAdjustment, static_cast(ptCursor.y) + m_crosshairs_radius, .0f }); - m_bottom_crosshairs.Size({ static_cast(m_crosshairs_thickness), static_cast(ptMonitorBottomRight.y) - ptCursor.y - m_crosshairs_radius }); + { + float bottomCrosshairsFullScreenLength = static_cast(ptMonitorBottomRight.y) - ptCursor.y - m_crosshairs_radius; + float bottomCrosshairsLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length : bottomCrosshairsFullScreenLength; + float bottomCrosshairsBorderLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length + borderSizePadding : bottomCrosshairsFullScreenLength + m_crosshairs_border_size; + m_bottom_crosshairs_border.Offset({ ptCursor.x + halfPixelAdjustment, static_cast(ptCursor.y) + m_crosshairs_radius - m_crosshairs_border_size, .0f }); + m_bottom_crosshairs_border.Size({ m_crosshairs_thickness + borderSizePadding, bottomCrosshairsBorderLength }); + m_bottom_crosshairs.Offset({ ptCursor.x + halfPixelAdjustment, static_cast(ptCursor.y) + m_crosshairs_radius, .0f }); + m_bottom_crosshairs.Size({ static_cast(m_crosshairs_thickness), bottomCrosshairsLength }); + } } LRESULT CALLBACK InclusiveCrosshairs::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept @@ -303,6 +325,8 @@ void InclusiveCrosshairs::ApplySettings(InclusiveCrosshairsSettings& settings, b m_crosshairs_border_size = settings.crosshairsBorderSize; bool autoHideChanged = m_crosshairs_auto_hide != settings.crosshairsAutoHide; m_crosshairs_auto_hide = settings.crosshairsAutoHide; + m_crosshairs_is_fixed_length_enabled = settings.crosshairsIsFixedLengthEnabled; + m_crosshairs_fixed_length = settings.crosshairsFixedLength; if (applyToRunTimeObjects) { diff --git a/src/modules/MouseUtils/MousePointerCrosshairs/InclusiveCrosshairs.h b/src/modules/MouseUtils/MousePointerCrosshairs/InclusiveCrosshairs.h index 28844e9380..bf760dd5c0 100644 --- a/src/modules/MouseUtils/MousePointerCrosshairs/InclusiveCrosshairs.h +++ b/src/modules/MouseUtils/MousePointerCrosshairs/InclusiveCrosshairs.h @@ -8,6 +8,8 @@ constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_RADIUS = 20; constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_THICKNESS = 5; constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE = 1; constexpr bool INCLUSIVE_MOUSE_DEFAULT_AUTO_HIDE = false; +constexpr bool INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED = false; +constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_FIXED_LENGTH = 1; struct InclusiveCrosshairsSettings { @@ -18,6 +20,8 @@ struct InclusiveCrosshairsSettings int crosshairsOpacity = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_OPACITY; int crosshairsBorderSize = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE; bool crosshairsAutoHide = INCLUSIVE_MOUSE_DEFAULT_AUTO_HIDE; + bool crosshairsIsFixedLengthEnabled = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED; + int crosshairsFixedLength = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_FIXED_LENGTH; }; int InclusiveCrosshairsMain(HINSTANCE hinst, InclusiveCrosshairsSettings& settings); diff --git a/src/modules/MouseUtils/MousePointerCrosshairs/dllmain.cpp b/src/modules/MouseUtils/MousePointerCrosshairs/dllmain.cpp index cf611b55cc..60aa9c3bc4 100644 --- a/src/modules/MouseUtils/MousePointerCrosshairs/dllmain.cpp +++ b/src/modules/MouseUtils/MousePointerCrosshairs/dllmain.cpp @@ -18,6 +18,8 @@ namespace const wchar_t JSON_KEY_CROSSHAIRS_BORDER_COLOR[] = L"crosshairs_border_color"; const wchar_t JSON_KEY_CROSSHAIRS_BORDER_SIZE[] = L"crosshairs_border_size"; const wchar_t JSON_KEY_CROSSHAIRS_AUTO_HIDE[] = L"crosshairs_auto_hide"; + const wchar_t JSON_KEY_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED[] = L"crosshairs_is_fixed_length_enabled"; + const wchar_t JSON_KEY_CROSSHAIRS_FIXED_LENGTH[] = L"crosshairs_fixed_length"; } extern "C" IMAGE_DOS_HEADER __ImageBase; @@ -341,6 +343,35 @@ public: { Logger::warn("Failed to initialize auto hide from settings. Will use default value"); } + try + { + // Parse whether the fixed length is enabled + auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED); + bool value = jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE); + inclusiveCrosshairsSettings.crosshairsIsFixedLengthEnabled = value; + } + catch (...) + { + Logger::warn("Failed to initialize fixed length enabled from settings. Will use default value"); + } + try + { + // Parse fixed length + auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_FIXED_LENGTH); + int value = static_cast(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE)); + if (value >= 0) + { + inclusiveCrosshairsSettings.crosshairsFixedLength = value; + } + else + { + throw; + } + } + catch (...) + { + Logger::warn("Failed to initialize fixed length from settings. Will use default value"); + } } else { diff --git a/src/settings-ui/Settings.UI.Library/MousePointerCrosshairsProperties.cs b/src/settings-ui/Settings.UI.Library/MousePointerCrosshairsProperties.cs index 1354088163..f543a34bdd 100644 --- a/src/settings-ui/Settings.UI.Library/MousePointerCrosshairsProperties.cs +++ b/src/settings-ui/Settings.UI.Library/MousePointerCrosshairsProperties.cs @@ -34,6 +34,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library [JsonPropertyName("crosshairs_auto_hide")] public BoolProperty CrosshairsAutoHide { get; set; } + [JsonPropertyName("crosshairs_is_fixed_length_enabled")] + public BoolProperty CrosshairsIsFixedLengthEnabled { get; set; } + + [JsonPropertyName("crosshairs_fixed_length")] + public IntProperty CrosshairsFixedLength { get; set; } + public MousePointerCrosshairsProperties() { ActivationShortcut = DefaultActivationShortcut; @@ -44,6 +50,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library CrosshairsBorderColor = new StringProperty("#FFFFFF"); CrosshairsBorderSize = new IntProperty(1); CrosshairsAutoHide = new BoolProperty(false); + CrosshairsIsFixedLengthEnabled = new BoolProperty(false); + CrosshairsFixedLength = new IntProperty(1); } } } diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index 22ec1f4a49..3599138382 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -2662,6 +2662,13 @@ From there, simply click on one of the supported files in the File Explorer and Crosshairs border size (px) px = pixels + + Fix crosshairs length + + + Crosshairs fixed length (px) + px = pixels + Custom colors diff --git a/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs index db14dff27f..2b4b4abe25 100644 --- a/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs @@ -107,6 +107,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _mousePointerCrosshairsThickness = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsThickness.Value; _mousePointerCrosshairsBorderSize = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsBorderSize.Value; _mousePointerCrosshairsAutoHide = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsAutoHide.Value; + _mousePointerCrosshairsIsFixedLengthEnabled = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsIsFixedLengthEnabled.Value; + _mousePointerCrosshairsFixedLength = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsFixedLength.Value; // set the callback functions value to handle outgoing IPC message. SendConfigMSG = ipcMSGCallBackFunc; @@ -811,6 +813,42 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } } + public bool MousePointerCrosshairsIsFixedLengthEnabled + { + get + { + return _mousePointerCrosshairsIsFixedLengthEnabled; + } + + set + { + if (value != _mousePointerCrosshairsIsFixedLengthEnabled) + { + _mousePointerCrosshairsIsFixedLengthEnabled = value; + MousePointerCrosshairsSettingsConfig.Properties.CrosshairsIsFixedLengthEnabled.Value = value; + NotifyMousePointerCrosshairsPropertyChanged(); + } + } + } + + public int MousePointerCrosshairsFixedLength + { + get + { + return _mousePointerCrosshairsFixedLength; + } + + set + { + if (value != _mousePointerCrosshairsFixedLength) + { + _mousePointerCrosshairsFixedLength = value; + MousePointerCrosshairsSettingsConfig.Properties.CrosshairsFixedLength.Value = value; + NotifyMousePointerCrosshairsPropertyChanged(); + } + } + } + public void NotifyMousePointerCrosshairsPropertyChanged([CallerMemberName] string propertyName = null) { OnPropertyChanged(propertyName); @@ -870,5 +908,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels private string _mousePointerCrosshairsBorderColor; private int _mousePointerCrosshairsBorderSize; private bool _mousePointerCrosshairsAutoHide; + private bool _mousePointerCrosshairsIsFixedLengthEnabled; + private int _mousePointerCrosshairsFixedLength; } } diff --git a/src/settings-ui/Settings.UI/Views/MouseUtilsPage.xaml b/src/settings-ui/Settings.UI/Views/MouseUtilsPage.xaml index 9fc657f415..85ffea3b6c 100644 --- a/src/settings-ui/Settings.UI/Views/MouseUtilsPage.xaml +++ b/src/settings-ui/Settings.UI/Views/MouseUtilsPage.xaml @@ -388,6 +388,24 @@ x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsAutoHide" IsChecked="{x:Bind ViewModel.MousePointerCrosshairsAutoHide, Mode=TwoWay}" /> + + + + + + + +