mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-01-19 15:03:36 +08:00
[Mouse Crosshairs] Hide crosshairs when cursor hides (#27381)
* hide crosshairs when cursor hides * fix formatting
This commit is contained in:
parent
ed44db25e3
commit
7e4e8f59bb
@ -45,6 +45,7 @@ private:
|
||||
|
||||
static constexpr auto m_className = L"MousePointerCrosshairs";
|
||||
static constexpr auto m_windowTitle = L"PowerToys Mouse Pointer Crosshairs";
|
||||
static constexpr DWORD AUTO_HIDE_TIMER_ID = 101;
|
||||
HWND m_hwndOwner = NULL;
|
||||
HWND m_hwnd = NULL;
|
||||
HINSTANCE m_hinstance = NULL;
|
||||
@ -65,8 +66,10 @@ private:
|
||||
winrt::SpriteVisual m_bottom_crosshairs_border{ nullptr };
|
||||
winrt::SpriteVisual m_bottom_crosshairs{ nullptr };
|
||||
|
||||
bool m_visible = false;
|
||||
bool m_drawing = false;
|
||||
bool m_destroyed = false;
|
||||
bool m_hiddenCursor = false;
|
||||
void SetAutoHideTimer() noexcept;
|
||||
|
||||
// Configurable Settings
|
||||
winrt::Windows::UI::Color m_crosshairs_border_color = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_COLOR;
|
||||
@ -75,6 +78,7 @@ private:
|
||||
int m_crosshairs_thickness = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_THICKNESS;
|
||||
int m_crosshairs_border_size = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE;
|
||||
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;
|
||||
};
|
||||
|
||||
InclusiveCrosshairs* InclusiveCrosshairs::instance = nullptr;
|
||||
@ -217,7 +221,7 @@ void InclusiveCrosshairs::UpdateCrosshairsPosition()
|
||||
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<float>(m_crosshairs_thickness) });
|
||||
|
||||
m_right_crosshairs_border.Offset({static_cast<float>(ptCursor.x) + m_crosshairs_radius - m_crosshairs_border_size, ptCursor.y + halfPixelAdjustment, .0f });
|
||||
m_right_crosshairs_border.Offset({ static_cast<float>(ptCursor.x) + m_crosshairs_radius - m_crosshairs_border_size, ptCursor.y + halfPixelAdjustment, .0f });
|
||||
m_right_crosshairs_border.Size({ static_cast<float>(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<float>(ptCursor.x) + m_crosshairs_radius, ptCursor.y + halfPixelAdjustment, .0f });
|
||||
m_right_crosshairs.Size({ static_cast<float>(ptMonitorBottomRight.x) - ptCursor.x - m_crosshairs_radius, static_cast<float>(m_crosshairs_thickness) });
|
||||
@ -227,11 +231,10 @@ void InclusiveCrosshairs::UpdateCrosshairsPosition()
|
||||
m_top_crosshairs.Offset({ ptCursor.x + halfPixelAdjustment, ptCursor.y - m_crosshairs_radius + halfPixelAdjustment * 2, .0f });
|
||||
m_top_crosshairs.Size({ static_cast<float>(m_crosshairs_thickness), ptCursor.y - ptMonitorUpperLeft.y - m_crosshairs_radius + halfPixelAdjustment * 2 });
|
||||
|
||||
m_bottom_crosshairs_border.Offset({ ptCursor.x + halfPixelAdjustment, static_cast<float>(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<float>(ptMonitorBottomRight.y) - ptCursor.y - m_crosshairs_radius + m_crosshairs_border_size });
|
||||
m_bottom_crosshairs.Offset({ ptCursor.x + halfPixelAdjustment, static_cast<float>(ptCursor.y) + m_crosshairs_radius, .0f });
|
||||
m_bottom_crosshairs.Size({ static_cast<float>(m_crosshairs_thickness), static_cast<float>(ptMonitorBottomRight.y) - ptCursor.y - m_crosshairs_radius });
|
||||
|
||||
m_bottom_crosshairs_border.Offset({ ptCursor.x + halfPixelAdjustment, static_cast<float>(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<float>(ptMonitorBottomRight.y) - ptCursor.y - m_crosshairs_radius + m_crosshairs_border_size });
|
||||
m_bottom_crosshairs.Offset({ ptCursor.x + halfPixelAdjustment, static_cast<float>(ptCursor.y) + m_crosshairs_radius, .0f });
|
||||
m_bottom_crosshairs.Size({ static_cast<float>(m_crosshairs_thickness), static_cast<float>(ptMonitorBottomRight.y) - ptCursor.y - m_crosshairs_radius });
|
||||
}
|
||||
|
||||
LRESULT CALLBACK InclusiveCrosshairs::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept
|
||||
@ -239,7 +242,8 @@ LRESULT CALLBACK InclusiveCrosshairs::MouseHookProc(int nCode, WPARAM wParam, LP
|
||||
if (nCode >= 0)
|
||||
{
|
||||
MSLLHOOKSTRUCT* hookData = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
|
||||
if (wParam == WM_MOUSEMOVE) {
|
||||
if (wParam == WM_MOUSEMOVE)
|
||||
{
|
||||
instance->UpdateCrosshairsPosition();
|
||||
}
|
||||
}
|
||||
@ -251,18 +255,37 @@ void InclusiveCrosshairs::StartDrawing()
|
||||
Logger::info("Start drawing crosshairs.");
|
||||
Trace::StartDrawingCrosshairs();
|
||||
UpdateCrosshairsPosition();
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
m_visible = true;
|
||||
|
||||
m_hiddenCursor = false;
|
||||
if (m_crosshairs_auto_hide)
|
||||
{
|
||||
CURSORINFO cursorInfo{};
|
||||
cursorInfo.cbSize = sizeof(cursorInfo);
|
||||
if (GetCursorInfo(&cursorInfo))
|
||||
{
|
||||
m_hiddenCursor = !(cursorInfo.flags & CURSOR_SHOWING);
|
||||
}
|
||||
|
||||
SetAutoHideTimer();
|
||||
}
|
||||
|
||||
if (!m_hiddenCursor)
|
||||
{
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
}
|
||||
|
||||
m_drawing = true;
|
||||
m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0);
|
||||
}
|
||||
|
||||
void InclusiveCrosshairs::StopDrawing()
|
||||
{
|
||||
Logger::info("Stop drawing crosshairs.");
|
||||
m_visible = false;
|
||||
m_drawing = false;
|
||||
ShowWindow(m_hwnd, SW_HIDE);
|
||||
UnhookWindowsHookEx(m_mouseHook);
|
||||
m_mouseHook = NULL;
|
||||
KillTimer(m_hwnd, AUTO_HIDE_TIMER_ID);
|
||||
}
|
||||
|
||||
void InclusiveCrosshairs::SwitchActivationMode()
|
||||
@ -278,9 +301,30 @@ void InclusiveCrosshairs::ApplySettings(InclusiveCrosshairsSettings& settings, b
|
||||
m_crosshairs_opacity = max(0.f, min(1.f, (float)settings.crosshairsOpacity / 100.0f));
|
||||
m_crosshairs_border_color = settings.crosshairsBorderColor;
|
||||
m_crosshairs_border_size = settings.crosshairsBorderSize;
|
||||
bool autoHideChanged = m_crosshairs_auto_hide != settings.crosshairsAutoHide;
|
||||
m_crosshairs_auto_hide = settings.crosshairsAutoHide;
|
||||
|
||||
if (applyToRunTimeObjects)
|
||||
{
|
||||
if (autoHideChanged)
|
||||
{
|
||||
if (m_crosshairs_auto_hide)
|
||||
{
|
||||
SetAutoHideTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
KillTimer(m_hwnd, AUTO_HIDE_TIMER_ID);
|
||||
|
||||
// Edge case of settings being changed with hidden crosshairs: timer time-out is 1 seconds
|
||||
if (m_drawing && m_hiddenCursor)
|
||||
{
|
||||
instance->m_hiddenCursor = false;
|
||||
ShowWindow(instance->m_hwnd, SW_SHOWNOACTIVATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime objects already created. Should update in the owner thread.
|
||||
if (m_dispatcherQueueController == nullptr)
|
||||
{
|
||||
@ -331,7 +375,7 @@ LRESULT CALLBACK InclusiveCrosshairs::WndProc(HWND hWnd, UINT message, WPARAM wP
|
||||
case WM_NCHITTEST:
|
||||
return HTTRANSPARENT;
|
||||
case WM_SWITCH_ACTIVATION_MODE:
|
||||
if (instance->m_visible)
|
||||
if (instance->m_drawing)
|
||||
{
|
||||
instance->StopDrawing();
|
||||
}
|
||||
@ -343,6 +387,32 @@ LRESULT CALLBACK InclusiveCrosshairs::WndProc(HWND hWnd, UINT message, WPARAM wP
|
||||
case WM_DESTROY:
|
||||
instance->DestroyInclusiveCrosshairs();
|
||||
break;
|
||||
case WM_TIMER:
|
||||
if (wParam == AUTO_HIDE_TIMER_ID && instance->m_drawing)
|
||||
{
|
||||
CURSORINFO cursorInfo{};
|
||||
cursorInfo.cbSize = sizeof(cursorInfo);
|
||||
if (GetCursorInfo(&cursorInfo))
|
||||
{
|
||||
if (cursorInfo.flags & CURSOR_SHOWING)
|
||||
{
|
||||
if (instance->m_hiddenCursor)
|
||||
{
|
||||
instance->m_hiddenCursor = false;
|
||||
ShowWindow(instance->m_hwnd, SW_SHOWNOACTIVATE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!instance->m_hiddenCursor)
|
||||
{
|
||||
instance->m_hiddenCursor = true;
|
||||
ShowWindow(instance->m_hwnd, SW_HIDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
@ -390,6 +460,15 @@ void InclusiveCrosshairs::Terminate()
|
||||
}
|
||||
}
|
||||
|
||||
void InclusiveCrosshairs::SetAutoHideTimer() noexcept
|
||||
{
|
||||
if (SetTimer(m_hwnd, AUTO_HIDE_TIMER_ID, 1000, NULL) == 0)
|
||||
{
|
||||
int error = GetLastError();
|
||||
Logger::trace("Failed to create auto hide timer. Last error: {}", error);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region InclusiveCrosshairs_API
|
||||
|
||||
void InclusiveCrosshairsApplySettings(InclusiveCrosshairsSettings& settings)
|
||||
|
@ -7,6 +7,7 @@ const winrt::Windows::UI::Color INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_COLOR
|
||||
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;
|
||||
|
||||
struct InclusiveCrosshairsSettings
|
||||
{
|
||||
@ -16,6 +17,7 @@ struct InclusiveCrosshairsSettings
|
||||
int crosshairsThickness = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_THICKNESS;
|
||||
int crosshairsOpacity = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_OPACITY;
|
||||
int crosshairsBorderSize = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE;
|
||||
bool crosshairsAutoHide = INCLUSIVE_MOUSE_DEFAULT_AUTO_HIDE;
|
||||
};
|
||||
|
||||
int InclusiveCrosshairsMain(HINSTANCE hinst, InclusiveCrosshairsSettings& settings);
|
||||
|
@ -17,6 +17,7 @@ namespace
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_THICKNESS[] = L"crosshairs_thickness";
|
||||
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";
|
||||
}
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
@ -330,6 +331,16 @@ public:
|
||||
{
|
||||
Logger::warn("Failed to initialize border color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse auto hide
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_AUTO_HIDE);
|
||||
inclusiveCrosshairsSettings.crosshairsAutoHide = static_cast<bool>(jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize auto hide from settings. Will use default value");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -31,6 +31,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("crosshairs_border_size")]
|
||||
public IntProperty CrosshairsBorderSize { get; set; }
|
||||
|
||||
[JsonPropertyName("crosshairs_auto_hide")]
|
||||
public BoolProperty CrosshairsAutoHide { get; set; }
|
||||
|
||||
public MousePointerCrosshairsProperties()
|
||||
{
|
||||
ActivationShortcut = DefaultActivationShortcut;
|
||||
@ -40,6 +43,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
CrosshairsThickness = new IntProperty(5);
|
||||
CrosshairsBorderColor = new StringProperty("#FFFFFF");
|
||||
CrosshairsBorderSize = new IntProperty(1);
|
||||
CrosshairsAutoHide = new BoolProperty(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2150,7 +2150,7 @@ From there, simply click on one of the supported files in the File Explorer and
|
||||
<data name="OobeWindow_Title" xml:space="preserve">
|
||||
<value>Welcome to PowerToys</value>
|
||||
</data>
|
||||
<data name="OobeWindow_TitleTxt.Text" xml:space="preserve">
|
||||
<data name="OobeWindow_TitleTxt.Text" xml:space="preserve">
|
||||
<value>Welcome to PowerToys</value>
|
||||
</data>
|
||||
<data name="SettingsWindow_Title" xml:space="preserve">
|
||||
@ -2469,10 +2469,10 @@ From there, simply click on one of the supported files in the File Explorer and
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="Activation_Shortcut_Description.Text" xml:space="preserve">
|
||||
<value>Press a combination of keys to change this shortcut</value>
|
||||
<value>Press a combination of keys to change this shortcut</value>
|
||||
</data>
|
||||
<data name="Activation_Shortcut_Reset" xml:space="preserve">
|
||||
<value>Reset</value>
|
||||
<value>Reset</value>
|
||||
</data>
|
||||
<data name="Activation_Shortcut_Save" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
@ -3318,7 +3318,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="FileLocksmith_Toggle_StandardContextMenu.Content" xml:space="preserve">
|
||||
<value>Default and extended context menu</value>
|
||||
</data>
|
||||
<data name="FileLocksmith_Toggle_ExtendedContextMenu.Content" xml:space="preserve">
|
||||
<data name="FileLocksmith_Toggle_ExtendedContextMenu.Content" xml:space="preserve">
|
||||
<value>Extended context menu only</value>
|
||||
</data>
|
||||
<data name="FileLocksmith_Toggle_ContextMenu.Header" xml:space="preserve">
|
||||
@ -3551,9 +3551,9 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Maximum width (px)</value>
|
||||
<comment>px = pixels</comment>
|
||||
</data>
|
||||
<data name="SettingsWindow_TitleTxt.Text" xml:space="preserve">
|
||||
<data name="SettingsWindow_TitleTxt.Text" xml:space="preserve">
|
||||
<value>PowerToys Settings</value>
|
||||
</data>
|
||||
</data>
|
||||
<data name="Oobe_Peek.Description" xml:space="preserve">
|
||||
<value>A lightning fast file preview feature for Windows.</value>
|
||||
</data>
|
||||
@ -3582,4 +3582,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="Hosts_Encoding_Utf8Bom.Content" xml:space="preserve">
|
||||
<value>UTF-8 with BOM</value>
|
||||
</data>
|
||||
<data name="MouseUtils_MousePointerCrosshairs_CrosshairsAutoHide.Content" xml:space="preserve">
|
||||
<value>Automatically hide crosshairs when the mouse pointer is hidden</value>
|
||||
</data>
|
||||
</root>
|
||||
|
@ -106,6 +106,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
_mousePointerCrosshairsRadius = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsRadius.Value;
|
||||
_mousePointerCrosshairsThickness = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsThickness.Value;
|
||||
_mousePointerCrosshairsBorderSize = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsBorderSize.Value;
|
||||
_mousePointerCrosshairsAutoHide = MousePointerCrosshairsSettingsConfig.Properties.CrosshairsAutoHide.Value;
|
||||
|
||||
// set the callback functions value to handle outgoing IPC message.
|
||||
SendConfigMSG = ipcMSGCallBackFunc;
|
||||
@ -792,6 +793,24 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool MousePointerCrosshairsAutoHide
|
||||
{
|
||||
get
|
||||
{
|
||||
return _mousePointerCrosshairsAutoHide;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _mousePointerCrosshairsAutoHide)
|
||||
{
|
||||
_mousePointerCrosshairsAutoHide = value;
|
||||
MousePointerCrosshairsSettingsConfig.Properties.CrosshairsAutoHide.Value = value;
|
||||
NotifyMousePointerCrosshairsPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void NotifyMousePointerCrosshairsPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
OnPropertyChanged(propertyName);
|
||||
@ -850,5 +869,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private int _mousePointerCrosshairsThickness;
|
||||
private string _mousePointerCrosshairsBorderColor;
|
||||
private int _mousePointerCrosshairsBorderSize;
|
||||
private bool _mousePointerCrosshairsAutoHide;
|
||||
}
|
||||
}
|
||||
|
@ -382,6 +382,12 @@
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{x:Bind Mode=TwoWay, Path=ViewModel.MousePointerCrosshairsBorderSize}" />
|
||||
</labs:SettingsCard>
|
||||
|
||||
<labs:SettingsCard ContentAlignment="Left">
|
||||
<CheckBox
|
||||
x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsAutoHide"
|
||||
IsChecked="{x:Bind ViewModel.MousePointerCrosshairsAutoHide, Mode=TwoWay}" />
|
||||
</labs:SettingsCard>
|
||||
</labs:SettingsExpander.Items>
|
||||
</labs:SettingsExpander>
|
||||
</controls:SettingsGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user