order windows
This commit is contained in:
parent
0c60d64b09
commit
7704f153f4
|
@ -42,12 +42,31 @@ void AlwaysOnTop::Init()
|
||||||
wcex.lpszClassName = HOTKEY_WINDOW_CLASS_NAME;
|
wcex.lpszClassName = HOTKEY_WINDOW_CLASS_NAME;
|
||||||
RegisterClassExW(&wcex);
|
RegisterClassExW(&wcex);
|
||||||
|
|
||||||
hotKeyHandleWindow = CreateWindowExW(WS_EX_TOOLWINDOW, HOTKEY_WINDOW_CLASS_NAME, L"", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinstance, this);
|
m_hotKeyHandleWindow = CreateWindowExW(WS_EX_TOOLWINDOW, HOTKEY_WINDOW_CLASS_NAME, L"", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinstance, this);
|
||||||
if (!hotKeyHandleWindow) {
|
if (!m_hotKeyHandleWindow) {
|
||||||
return;
|
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
|
LRESULT AlwaysOnTop::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||||
|
@ -75,10 +94,10 @@ void AlwaysOnTop::ProcessCommand(HWND window)
|
||||||
{
|
{
|
||||||
if (ResetTopmostWindow(window))
|
if (ResetTopmostWindow(window))
|
||||||
{
|
{
|
||||||
auto iter = std::find(topmostWindows.begin(), topmostWindows.end(), window);
|
auto iter = std::find(m_topmostWindows.begin(), m_topmostWindows.end(), window);
|
||||||
if (iter != topmostWindows.end())
|
if (iter != m_topmostWindows.end())
|
||||||
{
|
{
|
||||||
topmostWindows.erase(iter);
|
m_topmostWindows.erase(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +105,8 @@ void AlwaysOnTop::ProcessCommand(HWND window)
|
||||||
{
|
{
|
||||||
if (SetTopmostWindow(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))
|
if (IsTopmost(window))
|
||||||
{
|
{
|
||||||
topmostWindows.push_back(window);
|
m_topmostWindows.push_back(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OrderWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlwaysOnTop::ResetAll()
|
void AlwaysOnTop::ResetAll()
|
||||||
{
|
{
|
||||||
for (HWND topWindow : topmostWindows)
|
for (HWND topWindow : m_topmostWindows)
|
||||||
{
|
{
|
||||||
if (!ResetTopmostWindow(topWindow))
|
if (!ResetTopmostWindow(topWindow))
|
||||||
{
|
{
|
||||||
|
@ -139,20 +161,45 @@ void AlwaysOnTop::ResetAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
topmostWindows.clear();
|
m_topmostWindows.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlwaysOnTop::CleanUp()
|
void AlwaysOnTop::CleanUp()
|
||||||
{
|
{
|
||||||
ResetAll();
|
ResetAll();
|
||||||
if (hotKeyHandleWindow)
|
if (m_hotKeyHandleWindow)
|
||||||
{
|
{
|
||||||
DestroyWindow(hotKeyHandleWindow);
|
DestroyWindow(m_hotKeyHandleWindow);
|
||||||
hotKeyHandleWindow = nullptr;
|
m_hotKeyHandleWindow = nullptr;
|
||||||
}
|
}
|
||||||
UnregisterClass(HOTKEY_WINDOW_CLASS_NAME, reinterpret_cast<HINSTANCE>(&__ImageBase));
|
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
|
bool AlwaysOnTop::IsTopmost(HWND window) const noexcept
|
||||||
{
|
{
|
||||||
int exStyle = GetWindowLong(window, GWL_EXSTYLE);
|
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);
|
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
|
#pragma once
|
||||||
|
|
||||||
|
// common
|
||||||
|
struct WinHookEvent
|
||||||
|
{
|
||||||
|
DWORD event;
|
||||||
|
HWND hwnd;
|
||||||
|
LONG idObject;
|
||||||
|
LONG idChild;
|
||||||
|
DWORD idEventThread;
|
||||||
|
DWORD dwmsEventTime;
|
||||||
|
};
|
||||||
|
|
||||||
class AlwaysOnTop
|
class AlwaysOnTop
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -26,9 +37,11 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static inline AlwaysOnTop* s_instance = nullptr;
|
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;
|
bool m_activateInGameMode = false;
|
||||||
|
|
||||||
LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
|
LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
|
||||||
|
@ -37,9 +50,29 @@ private:
|
||||||
void StartTrackingTopmostWindows();
|
void StartTrackingTopmostWindows();
|
||||||
void ResetAll();
|
void ResetAll();
|
||||||
void CleanUp();
|
void CleanUp();
|
||||||
|
bool OrderWindows() const noexcept;
|
||||||
|
|
||||||
bool IsTopmost(HWND window) const noexcept;
|
bool IsTopmost(HWND window) const noexcept;
|
||||||
bool SetTopmostWindow(HWND window) const noexcept;
|
bool SetTopmostWindow(HWND window) const noexcept;
|
||||||
bool ResetTopmostWindow(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