Skip to content

Commit

Permalink
deploy: 1b53ec6
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Oct 28, 2024
1 parent dd3cee5 commit dd2283b
Show file tree
Hide file tree
Showing 4 changed files with 300 additions and 15 deletions.
24 changes: 24 additions & 0 deletions catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,30 @@
"version": "1.0.2"
}
},
"alt-tab-per-monitor": {
"details": {
"defaultSorting": 0,
"published": 1730148779000,
"rating": 0,
"ratingUsers": 0,
"updated": 1730148779000,
"users": 0
},
"metadata": {
"architecture": [
"x86-64"
],
"author": "L3r0y",
"compilerOptions": "-lole32 -loleaut32",
"description": "Pressing Alt+Tab shows all open windows on the primary display. This mod shows only the windows on the monitor where the cursor is.",
"github": "https://github.com/L3r0yThingz",
"include": [
"explorer.exe"
],
"name": "Alt+Tab per monitor",
"version": "1.0.0"
}
},
"basic-themer": {
"details": {
"defaultSorting": 2295,
Expand Down
3 changes: 3 additions & 0 deletions changelogs/alt-tab-per-monitor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0 ([Oct 28, 2024](https://github.com/ramensoftware/windhawk-mods/blob/1b53ec6de6072aae622f18e895fedd349521136c/mods/alt-tab-per-monitor.wh.cpp))

Initial release.
257 changes: 257 additions & 0 deletions mods/alt-tab-per-monitor.wh.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
// ==WindhawkMod==
// @id alt-tab-per-monitor
// @name Alt+Tab per monitor
// @description Pressing Alt+Tab shows all open windows on the primary display. This mod shows only the windows on the monitor where the cursor is.
// @version 1.0.0
// @author L3r0y
// @github https://github.com/L3r0yThingz
// @include explorer.exe
// @architecture x86-64
// @compilerOptions -lole32 -loleaut32
// ==/WindhawkMod==

// ==WindhawkModReadme==
/*
# Alt+Tab per monitor
When you press the Alt+Tab combination, the window switcher will appear on the
primary display, showing all open windows across all monitors. This mod
customizes the behavior to display the switcher on the monitor where the cursor
is currently located, showing only the windows present on that specific monitor.
*/
// ==/WindhawkModReadme==

#include <windhawk_utils.h>

#include <winrt/windows.foundation.collections.h>

std::atomic<DWORD> g_threadIdForAltTabShowWindow;
std::atomic<DWORD> g_lastThreadIdForXamlAltTabViewHost_CreateInstance;
std::atomic<DWORD> g_threadIdForXamlAltTabViewHost_CreateInstance;
ULONGLONG g_CreateInstance_TickCount;
constexpr ULONGLONG kDeltaThreshold = 200;

bool HandleAltTabWindow(winrt::Windows::Foundation::Rect* rect) {
POINT pt;
if (!GetCursorPos(&pt)) {
return false;
}

auto hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);

MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
if (!GetMonitorInfo(hMon, &monInfo)) {
return false;
}

rect->Height = monInfo.rcWork.bottom - monInfo.rcWork.top;
rect->Width = monInfo.rcWork.right - monInfo.rcWork.left;
rect->X = monInfo.rcWork.left;
rect->Y = monInfo.rcWork.top;

return true;
}

void* CWin32ApplicationView_vtable;
void* CWinRTApplicationView_vtable;

using CWin32ApplicationView_v_GetNativeWindow_t =
HRESULT(WINAPI*)(void* pThis, HWND* windowHandle);
CWin32ApplicationView_v_GetNativeWindow_t
CWin32ApplicationView_v_GetNativeWindow;

using CWinRTApplicationView_v_GetNativeWindow_t =
HRESULT(WINAPI*)(void* pThis, HWND* windowHandle);
CWinRTApplicationView_v_GetNativeWindow_t
CWinRTApplicationView_v_GetNativeWindow;

HRESULT GetWindowHandleFromApplicationView(void* applicationView,
HWND* windowHandle) {
*windowHandle = nullptr;
void* vtable = *(void**)applicationView;
HRESULT hr = E_FAIL;

if (vtable == CWin32ApplicationView_vtable) {
hr = CWin32ApplicationView_v_GetNativeWindow(applicationView,
windowHandle);
} else if (vtable == CWinRTApplicationView_vtable) {
hr = CWinRTApplicationView_v_GetNativeWindow(applicationView,
windowHandle);
}

return hr;
}

bool IsWindowOnCursorMonitor(HWND windowHandle) {
POINT pt;
if (!GetCursorPos(&pt)) {
return false;
}

auto hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
auto hMonFromWindow =
MonitorFromWindow(windowHandle, MONITOR_DEFAULTTONEAREST);

return hMon == hMonFromWindow;
}

using CVirtualDesktop_IsViewVisible_t = HRESULT(WINAPI*)(void* pThis,
void* applicationView,
BOOL* isVisible);
CVirtualDesktop_IsViewVisible_t CVirtualDesktop_IsViewVisible_Original;
HRESULT WINAPI CVirtualDesktop_IsViewVisible_Hook(void* pThis,
void* applicationView,
BOOL* isVisible) {
Wh_Log(L">");
auto ret = CVirtualDesktop_IsViewVisible_Original(pThis, applicationView,
isVisible);
if (FAILED(ret)) {
return ret;
}

if (g_threadIdForXamlAltTabViewHost_CreateInstance !=
GetCurrentThreadId()) {
// A focused window might be added after a short period. Filter windows
// using our monitor rules if the alt tab window was just opened.
// Otherwise, don't play with the filter anymore, as it's also used by
// other components such as Win+Tab and the taskbar.
if ((GetTickCount64() - g_CreateInstance_TickCount) > kDeltaThreshold ||
g_lastThreadIdForXamlAltTabViewHost_CreateInstance !=
GetCurrentThreadId()) {
return ret;
}
}

if (!*isVisible) {
return ret;
}

HWND windowHandle;
HRESULT hr =
GetWindowHandleFromApplicationView(applicationView, &windowHandle);

if (FAILED(hr) || !windowHandle) {
return ret;
}

if (!IsWindowOnCursorMonitor(windowHandle)) {
*isVisible = FALSE;
}

return ret;
}

using XamlAltTabViewHost_Show_t = HRESULT(WINAPI*)(void* pThis,
void* param1,
int param2,
void* param3);
XamlAltTabViewHost_Show_t XamlAltTabViewHost_Show_Original;
HRESULT XamlAltTabViewHost_Show_Hook(void* pThis,
void* param1,
int param2,
void* param3) {
g_threadIdForAltTabShowWindow = GetCurrentThreadId();
HRESULT ret =
XamlAltTabViewHost_Show_Original(pThis, param1, param2, param3);
g_threadIdForAltTabShowWindow = 0;
return ret;
}

using ITaskGroupWindowInformation_Position_t =
HRESULT(WINAPI*)(void* pThis, winrt::Windows::Foundation::Rect* rect);
ITaskGroupWindowInformation_Position_t
ITaskGroupWindowInformation_Position_Original;
HRESULT ITaskGroupWindowInformation_Position_Hook(
void* pThis,
winrt::Windows::Foundation::Rect* rect) {
if (g_threadIdForAltTabShowWindow != GetCurrentThreadId()) {
return ITaskGroupWindowInformation_Position_Original(pThis, rect);
}
g_threadIdForAltTabShowWindow = 0;

winrt::Windows::Foundation::Rect newRect;
if (!HandleAltTabWindow(&newRect)) {
return ITaskGroupWindowInformation_Position_Original(pThis, rect);
}

HRESULT ret =
ITaskGroupWindowInformation_Position_Original(pThis, &newRect);

return ret;
}

using XamlAltTabViewHost_CreateInstance_t = HRESULT(WINAPI*)(void* pThis,
void* param1,
void* param2,
void* param3);
XamlAltTabViewHost_CreateInstance_t XamlAltTabViewHost_CreateInstance_Original;
HRESULT XamlAltTabViewHost_CreateInstance_Hook(void* pThis,
void* param1,
void* param2,
void* param3) {
g_threadIdForXamlAltTabViewHost_CreateInstance = GetCurrentThreadId();
g_lastThreadIdForXamlAltTabViewHost_CreateInstance = GetCurrentThreadId();
g_CreateInstance_TickCount = GetTickCount64();
HRESULT ret = XamlAltTabViewHost_CreateInstance_Original(pThis, param1,
param2, param3);
g_threadIdForXamlAltTabViewHost_CreateInstance = 0;
return ret;
}

BOOL Wh_ModInit() {
Wh_Log(L">");

// twinui.pcshell.dll
WindhawkUtils::SYMBOL_HOOK twinuiPcshellSymbolHooks[] = {
{
{LR"(public: virtual long __cdecl CVirtualDesktop::IsViewVisible(struct IApplicationView *,int *))"},
&CVirtualDesktop_IsViewVisible_Original,
CVirtualDesktop_IsViewVisible_Hook,
},
{
{LR"(const CWin32ApplicationView::`vftable'{for `IApplicationView'})"},
&CWin32ApplicationView_vtable,
},
{
{LR"(private: virtual long __cdecl CWin32ApplicationView::v_GetNativeWindow(struct HWND__ * *))"},
&CWin32ApplicationView_v_GetNativeWindow,
},
{
{LR"(const CWinRTApplicationView::`vftable'{for `IApplicationView'})"},
&CWinRTApplicationView_vtable,
},
{
{LR"(private: virtual long __cdecl CWinRTApplicationView::v_GetNativeWindow(struct HWND__ * *))"},
&CWinRTApplicationView_v_GetNativeWindow,
},
{
{LR"(public: virtual long __cdecl XamlAltTabViewHost::Show(struct IImmersiveMonitor *,enum ALT_TAB_VIEW_FLAGS,struct IApplicationView *))"},
&XamlAltTabViewHost_Show_Original,
XamlAltTabViewHost_Show_Hook,
},
{
{LR"(public: __cdecl winrt::impl::consume_Windows_Internal_Shell_TaskGroups_ITaskGroupWindowInformation<struct winrt::Windows::Internal::Shell::TaskGroups::ITaskGroupWindowInformation>::Position(struct winrt::Windows::Foundation::Rect const &)const )"},
&ITaskGroupWindowInformation_Position_Original,
ITaskGroupWindowInformation_Position_Hook,
},
{
{LR"(long __cdecl XamlAltTabViewHost_CreateInstance(struct XamlViewHostInitializeArgs const &,struct _GUID const &,void * *))"},
&XamlAltTabViewHost_CreateInstance_Original,
XamlAltTabViewHost_CreateInstance_Hook,
},
};

HMODULE twinuiPcshellModule = LoadLibrary(L"twinui.pcshell.dll");
if (!twinuiPcshellModule) {
Wh_Log(L"Couldn't load twinui.pcshell.dll");
return FALSE;
}

if (!HookSymbols(twinuiPcshellModule, twinuiPcshellSymbolHooks,
ARRAYSIZE(twinuiPcshellSymbolHooks))) {
return FALSE;
}

return TRUE;
}
31 changes: 16 additions & 15 deletions updates.atom
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,27 @@
<feed xmlns="http://www.w3.org/2005/Atom">
<id>https://windhawk.net/</id>
<title>Windhawk Mod Updates</title>
<updated>2024-10-27T22:54:21.000Z</updated>
<updated>2024-10-28T20:52:59.000Z</updated>
<generator>https://github.com/jpmonette/feed</generator>
<link rel="alternate" href="https://windhawk.net/"/>
<subtitle>Updates in the official collection of Windhawk mods</subtitle>
<icon>https://windhawk.net/favicon.ico</icon>
<rights>Ramen Software</rights>
<entry>
<title type="html"><![CDATA[Alt+Tab per monitor 1.0.0]]></title>
<id>https://windhawk.net/mods/alt-tab-per-monitor#1b53ec6de6072aae622f18e895fedd349521136c</id>
<link href="https://windhawk.net/mods/alt-tab-per-monitor"/>
<updated>2024-10-28T20:52:59.000Z</updated>
<content type="html"><![CDATA[<h1 id="alttabpermonitor">Alt+Tab per monitor</h1>
<p>When you press the Alt+Tab combination, the window switcher will appear on the
primary display, showing all open windows across all monitors. This mod
customizes the behavior to display the switcher on the monitor where the cursor
is currently located, showing only the windows present on that specific monitor.</p>]]></content>
<author>
<name>L3r0y</name>
<uri>https://github.com/L3r0yThingz</uri>
</author>
</entry>
<entry>
<title type="html"><![CDATA[Desktop icons view 1.0.2]]></title>
<id>https://windhawk.net/mods/desktop-icons-view#4accdef47703c83eb2afc92ce30a1c7589910f1c</id>
Expand Down Expand Up @@ -274,20 +289,6 @@ Previously, we attempted to draw the gripper overlay for any control that existe
<content type="html"><![CDATA[<ul>
<li>Fixed the mod not working in some cases. Specifically, if the Windows TaskbarShiftRightClickCrash feature flag was enabled, right click acted as a left click instead of showing the classic context menu.</li>
<li>The "Customize the old taskbar on Windows 11" option no longer needs to be enabled for the mod to work with the ExplorerPatcher taskbar.</li>
</ul>]]></content>
<author>
<name>m417z</name>
<uri>https://github.com/m417z</uri>
</author>
</entry>
<entry>
<title type="html"><![CDATA[Cycle through taskbar windows on click 1.1.1]]></title>
<id>https://windhawk.net/mods/taskbar-left-click-cycle#c04dfbc63407803920ca0699c8b2a160e23d757b</id>
<link href="https://windhawk.net/mods/taskbar-left-click-cycle"/>
<updated>2024-10-22T09:20:26.000Z</updated>
<content type="html"><![CDATA[<ul>
<li>Fixed initialization with the ExplorerPatcher taskbar. ExplorerPatcher 66.7 or newer is supported.</li>
<li>The "Customize the old taskbar on Windows 11" option no longer needs to be enabled for the mod to work with the ExplorerPatcher taskbar.</li>
</ul>]]></content>
<author>
<name>m417z</name>
Expand Down

0 comments on commit dd2283b

Please sign in to comment.