order windows
This commit is contained in:
parent
0c60d64b09
commit
7704f153f4
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue