-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cycle through taskbar windows on click v1.0 (#950)
- Loading branch information
Showing
1 changed file
with
228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
// ==WindhawkMod== | ||
// @id taskbar-left-click-cycle | ||
// @name Cycle through taskbar windows on click | ||
// @description Makes clicking on combined taskbar items cycle through windows instead of opening thumbnail previews | ||
// @version 1.0 | ||
// @author m417z | ||
// @github https://github.com/m417z | ||
// @twitter https://twitter.com/m417z | ||
// @homepage https://m417z.com/ | ||
// @include explorer.exe | ||
// @architecture x86-64 | ||
// @compilerOptions -lversion | ||
// ==/WindhawkMod== | ||
|
||
// Source code is published under The GNU General Public License v3.0. | ||
// | ||
// For bug reports and feature requests, please open an issue here: | ||
// https://github.com/ramensoftware/windhawk-mods/issues | ||
// | ||
// For pull requests, development takes place here: | ||
// https://github.com/m417z/my-windhawk-mods | ||
|
||
// ==WindhawkModReadme== | ||
/* | ||
# Cycle through taskbar windows on click | ||
Makes clicking on combined taskbar items cycle through windows instead of | ||
opening thumbnail previews. It's still possible to open thumbnail previews by | ||
holding the Ctrl key while clicking. | ||
Only Windows 10 64-bit and Windows 11 are supported. For other Windows versions | ||
check out [7+ Taskbar Tweaker](https://tweaker.ramensoftware.com/). | ||
**Note:** To customize the old taskbar on Windows 11 (if using ExplorerPatcher | ||
or a similar tool), enable the relevant option in the mod's settings. | ||
![Demonstration](https://i.imgur.com/ecYYtGU.gif) | ||
*/ | ||
// ==/WindhawkModReadme== | ||
|
||
// ==WindhawkModSettings== | ||
/* | ||
- oldTaskbarOnWin11: false | ||
$name: Customize the old taskbar on Windows 11 | ||
$description: >- | ||
Enable this option to customize the old taskbar on Windows 11 (if using | ||
ExplorerPatcher or a similar tool). | ||
*/ | ||
// ==/WindhawkModSettings== | ||
|
||
#include <windhawk_utils.h> | ||
|
||
struct { | ||
bool oldTaskbarOnWin11; | ||
} g_settings; | ||
|
||
enum class WinVersion { | ||
Unsupported, | ||
Win10, | ||
Win11, | ||
}; | ||
|
||
WinVersion g_winVersion; | ||
|
||
using CTaskBtnGroup_GetGroupType_t = int(WINAPI*)(PVOID pThis); | ||
CTaskBtnGroup_GetGroupType_t CTaskBtnGroup_GetGroupType_Original; | ||
|
||
using CTaskListWnd__HandleClick_t = void(WINAPI*)(PVOID pThis, | ||
PVOID taskBtnGroup, | ||
int taskItemIndex, | ||
int clickAction, | ||
int param4, | ||
int param5); | ||
CTaskListWnd__HandleClick_t CTaskListWnd__HandleClick_Original; | ||
void WINAPI CTaskListWnd__HandleClick_Hook(PVOID pThis, | ||
PVOID taskBtnGroup, | ||
int taskItemIndex, | ||
int clickAction, | ||
int param4, | ||
int param5) { | ||
Wh_Log(L"> %d", clickAction); | ||
|
||
auto original = [&]() { | ||
CTaskListWnd__HandleClick_Original(pThis, taskBtnGroup, taskItemIndex, | ||
clickAction, param4, param5); | ||
}; | ||
|
||
constexpr int kClick = 0; | ||
constexpr int kShiftClick = 4; | ||
|
||
if (clickAction != kClick && clickAction != kShiftClick) { | ||
return original(); | ||
} | ||
|
||
// Group types: | ||
// 1 - Single item or multiple uncombined items | ||
// 2 - Pinned item | ||
// 3 - Multiple combined items | ||
int groupType = CTaskBtnGroup_GetGroupType_Original(taskBtnGroup); | ||
if (groupType != 3) { | ||
return original(); | ||
} | ||
|
||
CTaskListWnd__HandleClick_Original( | ||
pThis, taskBtnGroup, taskItemIndex, | ||
clickAction == kClick ? kShiftClick : kClick, param4, param5); | ||
} | ||
|
||
VS_FIXEDFILEINFO* GetModuleVersionInfo(HMODULE hModule, UINT* puPtrLen) { | ||
void* pFixedFileInfo = nullptr; | ||
UINT uPtrLen = 0; | ||
|
||
HRSRC hResource = | ||
FindResource(hModule, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); | ||
if (hResource) { | ||
HGLOBAL hGlobal = LoadResource(hModule, hResource); | ||
if (hGlobal) { | ||
void* pData = LockResource(hGlobal); | ||
if (pData) { | ||
if (!VerQueryValue(pData, L"\\", &pFixedFileInfo, &uPtrLen) || | ||
uPtrLen == 0) { | ||
pFixedFileInfo = nullptr; | ||
uPtrLen = 0; | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (puPtrLen) { | ||
*puPtrLen = uPtrLen; | ||
} | ||
|
||
return (VS_FIXEDFILEINFO*)pFixedFileInfo; | ||
} | ||
|
||
WinVersion GetExplorerVersion() { | ||
VS_FIXEDFILEINFO* fixedFileInfo = GetModuleVersionInfo(nullptr, nullptr); | ||
if (!fixedFileInfo) { | ||
return WinVersion::Unsupported; | ||
} | ||
|
||
WORD major = HIWORD(fixedFileInfo->dwFileVersionMS); | ||
WORD minor = LOWORD(fixedFileInfo->dwFileVersionMS); | ||
WORD build = HIWORD(fixedFileInfo->dwFileVersionLS); | ||
WORD qfe = LOWORD(fixedFileInfo->dwFileVersionLS); | ||
|
||
Wh_Log(L"Version: %u.%u.%u.%u", major, minor, build, qfe); | ||
|
||
switch (major) { | ||
case 10: | ||
if (build < 22000) { | ||
return WinVersion::Win10; | ||
} else { | ||
return WinVersion::Win11; | ||
} | ||
break; | ||
} | ||
|
||
return WinVersion::Unsupported; | ||
} | ||
|
||
void LoadSettings() { | ||
g_settings.oldTaskbarOnWin11 = Wh_GetIntSetting(L"oldTaskbarOnWin11"); | ||
} | ||
|
||
BOOL Wh_ModInit() { | ||
Wh_Log(L">"); | ||
|
||
LoadSettings(); | ||
|
||
g_winVersion = GetExplorerVersion(); | ||
if (g_winVersion == WinVersion::Unsupported) { | ||
Wh_Log(L"Unsupported Windows version"); | ||
return FALSE; | ||
} | ||
|
||
if (g_winVersion >= WinVersion::Win11 && g_settings.oldTaskbarOnWin11) { | ||
g_winVersion = WinVersion::Win10; | ||
} | ||
|
||
// Taskbar.dll, explorer.exe | ||
WindhawkUtils::SYMBOL_HOOK symbolHooks[] = { | ||
{ | ||
{ | ||
LR"(public: virtual enum eTBGROUPTYPE __cdecl CTaskBtnGroup::GetGroupType(void))", | ||
LR"(public: virtual enum eTBGROUPTYPE __cdecl CTaskBtnGroup::GetGroupType(void) __ptr64)", | ||
}, | ||
(void**)&CTaskBtnGroup_GetGroupType_Original, | ||
}, | ||
{ | ||
{ | ||
LR"(protected: void __cdecl CTaskListWnd::_HandleClick(struct ITaskBtnGroup *,int,enum CTaskListWnd::eCLICKACTION,int,int))", | ||
LR"(protected: void __cdecl CTaskListWnd::_HandleClick(struct ITaskBtnGroup * __ptr64,int,enum CTaskListWnd::eCLICKACTION,int,int) __ptr64)", | ||
}, | ||
(void**)&CTaskListWnd__HandleClick_Original, | ||
(void*)CTaskListWnd__HandleClick_Hook, | ||
}, | ||
}; | ||
|
||
HMODULE module; | ||
if (g_winVersion <= WinVersion::Win10) { | ||
module = GetModuleHandle(nullptr); | ||
} else { | ||
module = LoadLibrary(L"taskbar.dll"); | ||
if (!module) { | ||
Wh_Log(L"Couldn't load taskbar.dll"); | ||
return FALSE; | ||
} | ||
} | ||
|
||
if (!HookSymbols(module, symbolHooks, ARRAYSIZE(symbolHooks))) { | ||
return FALSE; | ||
} | ||
|
||
return TRUE; | ||
} | ||
|
||
BOOL Wh_ModSettingsChanged(BOOL* bReload) { | ||
Wh_Log(L">"); | ||
|
||
bool prevOldTaskbarOnWin11 = g_settings.oldTaskbarOnWin11; | ||
|
||
LoadSettings(); | ||
|
||
*bReload = g_settings.oldTaskbarOnWin11 != prevOldTaskbarOnWin11; | ||
|
||
return TRUE; | ||
} |