[MouseHighlighter]Bringing to front to be on top of other topmost windows (#27062)

* [MouseHighlighter] modifying window to be 'topmost' to be visible when clicking on 'pinned to top' windows.

* Fixing window hidden when clicking on a pinned to top window.

* Moving the code which starts the bring-to-front-timer to the mouse click events.
Also adding modifications to await 5 times 10 ms after the event to have surely the desired effect as in some cases the window repositioning takes longer than 10 ms.

* Minor changes

* Add safety code to ensure timer is never started paralely. Also minor format changes.

* Add comments

* spell checker corrections
This commit is contained in:
Laszlo Nemeth
2023-08-06 17:16:56 +02:00
committed by GitHub
parent c95508c8a5
commit 6948ffca53

View File

@@ -45,6 +45,7 @@ private:
void StartDrawingPointFading(MouseButton button); void StartDrawingPointFading(MouseButton button);
void ClearDrawingPoint(MouseButton button); void ClearDrawingPoint(MouseButton button);
void ClearDrawing(); void ClearDrawing();
void BringToFront();
HHOOK m_mouseHook = NULL; HHOOK m_mouseHook = NULL;
static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept; static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept;
@@ -72,6 +73,7 @@ private:
bool m_leftButtonPressed = false; bool m_leftButtonPressed = false;
bool m_rightButtonPressed = false; bool m_rightButtonPressed = false;
UINT_PTR m_timer_id = 0;
bool m_visible = false; bool m_visible = false;
@@ -85,7 +87,7 @@ private:
winrt::Windows::UI::Color m_rightClickColor = MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR; winrt::Windows::UI::Color m_rightClickColor = MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR;
winrt::Windows::UI::Color m_alwaysColor = MOUSE_HIGHLIGHTER_DEFAULT_ALWAYS_COLOR; winrt::Windows::UI::Color m_alwaysColor = MOUSE_HIGHLIGHTER_DEFAULT_ALWAYS_COLOR;
}; };
static const uint32_t BRING_TO_FRONT_TIMER_ID = 123;
Highlighter* Highlighter::instance = nullptr; Highlighter* Highlighter::instance = nullptr;
bool Highlighter::CreateHighlighter() bool Highlighter::CreateHighlighter()
@@ -126,11 +128,10 @@ bool Highlighter::CreateHighlighter()
} }
} }
void Highlighter::AddDrawingPoint(MouseButton button) void Highlighter::AddDrawingPoint(MouseButton button)
{ {
POINT pt; POINT pt;
// Applies DPIs. // Applies DPIs.
GetCursorPos(&pt); GetCursorPos(&pt);
@@ -257,6 +258,13 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa
} }
instance->AddDrawingPoint(MouseButton::Left); instance->AddDrawingPoint(MouseButton::Left);
instance->m_leftButtonPressed = true; instance->m_leftButtonPressed = true;
// start a timer for the scenario, when the user clicks a pinned window which has no focus.
// after we drow the highlighting circle the pinned window will jump in front of us,
// we have to bring our window back to topmost position
if (instance->m_timer_id == 0)
{
instance->m_timer_id = SetTimer(instance->m_hwnd, BRING_TO_FRONT_TIMER_ID, 10, nullptr);
}
} }
break; break;
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
@@ -269,6 +277,11 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa
} }
instance->AddDrawingPoint(MouseButton::Right); instance->AddDrawingPoint(MouseButton::Right);
instance->m_rightButtonPressed = true; instance->m_rightButtonPressed = true;
// same as for the left button, start a timer for reposition ourselves to topmost position
if (instance->m_timer_id == 0)
{
instance->m_timer_id = SetTimer(instance->m_hwnd, BRING_TO_FRONT_TIMER_ID, 10, nullptr);
}
} }
break; break;
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
@@ -316,7 +329,6 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa
return CallNextHookEx(0, nCode, wParam, lParam); return CallNextHookEx(0, nCode, wParam, lParam);
} }
void Highlighter::StartDrawing() void Highlighter::StartDrawing()
{ {
Logger::info("Starting draw mode."); Logger::info("Starting draw mode.");
@@ -363,6 +375,11 @@ void Highlighter::ApplySettings(MouseHighlighterSettings settings) {
m_alwaysPointerEnabled = settings.alwaysColor.A != 0; m_alwaysPointerEnabled = settings.alwaysColor.A != 0;
} }
void Highlighter::BringToFront() {
// HACK: Draw with 1 pixel off. Otherwise Windows glitches the task bar transparency when a transparent window fill the whole screen.
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN) + 1, GetSystemMetrics(SM_YVIRTUALSCREEN) + 1, GetSystemMetrics(SM_CXVIRTUALSCREEN) - 2, GetSystemMetrics(SM_CYVIRTUALSCREEN) - 2, 0);
}
void Highlighter::DestroyHighlighter() void Highlighter::DestroyHighlighter()
{ {
StopDrawing(); StopDrawing();
@@ -393,6 +410,28 @@ LRESULT CALLBACK Highlighter::WndProc(HWND hWnd, UINT message, WPARAM wParam, LP
case WM_DESTROY: case WM_DESTROY:
instance->DestroyHighlighter(); instance->DestroyHighlighter();
break; break;
case WM_TIMER:
{
switch (wParam)
{
// when the bring-to-front-timer expires (every 10 ms), we are repositioning our window to topmost Z order position
// As we experience that it takes 0-30 ms that the pinned window hides our window,
// we await 5 timer ticks (50 ms together) and then we stop the timer.
// If we would use a timer with a 50 ms period, there would be a flickering on the UI, as in most of the cases
// the pinned window hides our window in a few milliseconds.
case BRING_TO_FRONT_TIMER_ID:
static int fireCount = 0;
if (fireCount++ >= 4)
{
KillTimer(instance->m_hwnd, instance->m_timer_id);
instance->m_timer_id = 0;
fireCount = 0;
}
instance->BringToFront();
break;
}
break;
}
default: default:
return DefWindowProc(hWnd, message, wParam, lParam); return DefWindowProc(hWnd, message, wParam, lParam);
} }