order windows

This commit is contained in:
SeraphimaZ 2021-11-17 11:46:23 +03:00
parent 0c60d64b09
commit 7704f153f4
2 changed files with 127 additions and 15 deletions

View file

@ -42,12 +42,31 @@ void AlwaysOnTop::Init()
wcex.lpszClassName = HOTKEY_WINDOW_CLASS_NAME;
RegisterClassExW(&wcex);
hotKeyHandleWindow = CreateWindowExW(WS_EX_TOOLWINDOW, HOTKEY_WINDOW_CLASS_NAME, L"", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinstance, this);
if (!hotKeyHandleWindow) {
m_hotKeyHandleWindow = CreateWindowExW(WS_EX_TOOLWINDOW, HOTKEY_WINDOW_CLASS_NAME, L"", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinstance, this);
if (!m_hotKeyHandleWindow) {
return;
}
RegisterHotKey(hotKeyHandleWindow, 1, MOD_CONTROL | MOD_NOREPEAT, 0x54 /* T */);
RegisterHotKey(m_hotKeyHandleWindow, 1, MOD_CONTROL | MOD_NOREPEAT, 0x54 /* T */);
// subscribe to windows events
std::array<DWORD, 3> events_to_subscribe = {
EVENT_SYSTEM_MOVESIZEEND,
EVENT_SYSTEM_SWITCHEND,
EVENT_OBJECT_FOCUS
};
for (const auto event : events_to_subscribe)
{
auto hook = SetWinEventHook(event, event, nullptr, WinHookProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
if (hook)
{
m_staticWinEventHooks.emplace_back(hook);
}
else
{
MessageBoxW(NULL, L"Failed to set win event hook", L"AlwaysOnTop error", MB_OK | MB_ICONERROR);
}
}
}
LRESULT AlwaysOnTop::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
@ -75,10 +94,10 @@ void AlwaysOnTop::ProcessCommand(HWND window)
{
if (ResetTopmostWindow(window))
{
auto iter = std::find(topmostWindows.begin(), topmostWindows.end(), window);
if (iter != topmostWindows.end())
auto iter = std::find(m_topmostWindows.begin(), m_topmostWindows.end(), window);
if (iter != m_topmostWindows.end())
{
topmostWindows.erase(iter);
m_topmostWindows.erase(iter);
}
}
}
@ -86,7 +105,8 @@ void AlwaysOnTop::ProcessCommand(HWND window)
{
if (SetTopmostWindow(window))
{
topmostWindows.push_back(window);
m_topmostWindows.insert(m_topmostWindows.begin(), window);
OrderWindows();
}
}
@ -124,14 +144,16 @@ void AlwaysOnTop::StartTrackingTopmostWindows()
{
if (IsTopmost(window))
{
topmostWindows.push_back(window);
m_topmostWindows.push_back(window);
}
}
OrderWindows();
}
void AlwaysOnTop::ResetAll()
{
for (HWND topWindow : topmostWindows)
for (HWND topWindow : m_topmostWindows)
{
if (!ResetTopmostWindow(topWindow))
{
@ -139,20 +161,45 @@ void AlwaysOnTop::ResetAll()
}
}
topmostWindows.clear();
m_topmostWindows.clear();
}
void AlwaysOnTop::CleanUp()
{
ResetAll();
if (hotKeyHandleWindow)
if (m_hotKeyHandleWindow)
{
DestroyWindow(hotKeyHandleWindow);
hotKeyHandleWindow = nullptr;
DestroyWindow(m_hotKeyHandleWindow);
m_hotKeyHandleWindow = nullptr;
}
UnregisterClass(HOTKEY_WINDOW_CLASS_NAME, reinterpret_cast<HINSTANCE>(&__ImageBase));
}
bool AlwaysOnTop::OrderWindows() const noexcept
{
if (m_topmostWindows.empty())
{
return true;
}
BOOL res = true;
for (int i = static_cast<int>(m_topmostWindows.size()) - 1; i >= 0; i--)
{
auto cTxtLen = GetWindowTextLength(m_topmostWindows[i]);
auto pszMem = (LPWSTR)VirtualAlloc((LPVOID)NULL, (DWORD)(cTxtLen + 1), MEM_COMMIT, PAGE_READWRITE);
GetWindowText(m_topmostWindows[i], pszMem, cTxtLen + 1);
res &= SetWindowPos(m_topmostWindows[i], nullptr, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_DRAWFRAME);
if (!res)
{
MessageBoxW(NULL, L"Failed to order windows", L"AlwaysOnTop error", MB_OK | MB_ICONERROR);
}
}
return res;
}
bool AlwaysOnTop::IsTopmost(HWND window) const noexcept
{
int exStyle = GetWindowLong(window, GWL_EXSTYLE);
@ -168,3 +215,35 @@ bool AlwaysOnTop::ResetTopmostWindow(HWND window) const noexcept
{
return SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
bool AlwaysOnTop::IsTracked(HWND window) const noexcept
{
for (HWND topmostWindow : m_topmostWindows)
{
if (window == topmostWindow)
{
return true;
}
}
return false;
}
void AlwaysOnTop::HandleWinHookEvent(WinHookEvent* data) noexcept
{
switch (data->event)
{
case EVENT_SYSTEM_MOVESIZEEND: // moved or resized
case EVENT_SYSTEM_SWITCHEND: // alt-tab
case EVENT_OBJECT_FOCUS: // focused
{
if (IsTracked(data->hwnd))
{
OrderWindows();
}
}
break;
default:
break;
}
}

View file

@ -1,5 +1,16 @@
#pragma once
// common
struct WinHookEvent
{
DWORD event;
HWND hwnd;
LONG idObject;
LONG idChild;
DWORD idEventThread;
DWORD dwmsEventTime;
};
class AlwaysOnTop
{
public:
@ -26,9 +37,11 @@ protected:
private:
static inline AlwaysOnTop* s_instance = nullptr;
std::vector<HWINEVENTHOOK> m_staticWinEventHooks;
HWND m_hotKeyHandleWindow{ nullptr };
std::vector<HWND> m_topmostWindows;
HWND hotKeyHandleWindow{ nullptr };
std::vector<HWND> topmostWindows;
bool m_activateInGameMode = false;
LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
@ -37,9 +50,29 @@ private:
void StartTrackingTopmostWindows();
void ResetAll();
void CleanUp();
bool OrderWindows() const noexcept;
bool IsTopmost(HWND window) const noexcept;
bool SetTopmostWindow(HWND window) const noexcept;
bool ResetTopmostWindow(HWND window) const noexcept;
bool IsTracked(HWND window) const noexcept;
void HandleWinHookEvent(WinHookEvent* data) noexcept;
static void CALLBACK WinHookProc(HWINEVENTHOOK winEventHook,
DWORD event,
HWND window,
LONG object,
LONG child,
DWORD eventThread,
DWORD eventTime)
{
WinHookEvent data{ event, window, object, child, eventThread, eventTime };
if (s_instance)
{
s_instance->HandleWinHookEvent(&data);
}
}
};