From 7d05ba57eae05a56469e932b4457548bffc73989 Mon Sep 17 00:00:00 2001 From: Michael Maltsev <4129781+m417z@users.noreply.github.com> Date: Fri, 13 Sep 2024 14:55:06 +0300 Subject: [PATCH] Cycle through taskbar windows on click v1.0 --- mods/taskbar-left-click-cycle.wh.cpp | 228 +++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 mods/taskbar-left-click-cycle.wh.cpp diff --git a/mods/taskbar-left-click-cycle.wh.cpp b/mods/taskbar-left-click-cycle.wh.cpp new file mode 100644 index 000000000..4166168d3 --- /dev/null +++ b/mods/taskbar-left-click-cycle.wh.cpp @@ -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 + +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 - Win10) + // 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; +}