Skip to content

Commit

Permalink
Taskbar keyboard-only auto-hide v1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
m417z committed Feb 24, 2025
1 parent e7c61b9 commit e2a37f8
Showing 1 changed file with 341 additions and 0 deletions.
341 changes: 341 additions & 0 deletions mods/taskbar-auto-hide-keyboard-only.wh.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,341 @@
// ==WindhawkMod==
// @id taskbar-auto-hide-keyboard-only
// @name Taskbar keyboard-only auto-hide
// @description When taskbar auto-hide is enabled, the taskbar will only be unhidden with the keyboard, hovering the mouse over the taskbar will not unhide it
// @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==
/*
# Taskbar keyboard-only auto-hide
When taskbar auto-hide is enabled, the taskbar will only be unhidden with the
keyboard, hovering the mouse over the taskbar will not unhide it. For example,
the Win key or Ctrl+Esc will unhide the taskbar.
**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.
*/
// ==/WindhawkModReadme==

#include <windhawk_utils.h>

#include <psapi.h>

#include <atomic>

struct {
int showSpeedup;
int hideSpeedup;
int frameRate;
bool oldTaskbarOnWin11;
} g_settings;

enum class WinVersion {
Unsupported,
Win10,
Win11,
Win11_24H2,
};

WinVersion g_winVersion;

std::atomic<bool> g_initialized;
std::atomic<bool> g_explorerPatcherInitialized;

using TrayUI_SetUnhideTimer_t = void(WINAPI*)(void* pThis,
long param1,
long param2);
TrayUI_SetUnhideTimer_t TrayUI_SetUnhideTimer_Original;
void WINAPI TrayUI_SetUnhideTimer_Hook(void* pThis, long param1, long param2) {
Wh_Log(L">");

// TrayUI_SetUnhideTimer_Original(pThis, param1, param2);
}

bool HookTaskbarSymbols() {
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;
}
}

// Taskbar.dll, explorer.exe
WindhawkUtils::SYMBOL_HOOK symbolHooks[] = {
{
{LR"(public: virtual void __cdecl TrayUI::SetUnhideTimer(long,long))"},
&TrayUI_SetUnhideTimer_Original,
TrayUI_SetUnhideTimer_Hook,
},
};

if (!HookSymbols(module, symbolHooks, ARRAYSIZE(symbolHooks))) {
Wh_Log(L"HookSymbols failed");
return false;
}

return true;
}

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 if (build < 26100) {
return WinVersion::Win11;
} else {
return WinVersion::Win11_24H2;
}
break;
}

return WinVersion::Unsupported;
}

struct EXPLORER_PATCHER_HOOK {
PCSTR symbol;
void** pOriginalFunction;
void* hookFunction = nullptr;
bool optional = false;

template <typename Prototype>
EXPLORER_PATCHER_HOOK(
PCSTR symbol,
Prototype** originalFunction,
std::type_identity_t<Prototype*> hookFunction = nullptr,
bool optional = false)
: symbol(symbol),
pOriginalFunction(reinterpret_cast<void**>(originalFunction)),
hookFunction(reinterpret_cast<void*>(hookFunction)),
optional(optional) {}
};

bool HookExplorerPatcherSymbols(HMODULE explorerPatcherModule) {
if (g_explorerPatcherInitialized.exchange(true)) {
return true;
}

if (g_winVersion >= WinVersion::Win11) {
g_winVersion = WinVersion::Win10;
}

EXPLORER_PATCHER_HOOK hooks[] = {
{R"(?SetUnhideTimer@TrayUI@@UEAAXJJ@Z)",
&TrayUI_SetUnhideTimer_Original, TrayUI_SetUnhideTimer_Hook},
};

bool succeeded = true;

for (const auto& hook : hooks) {
void* ptr = (void*)GetProcAddress(explorerPatcherModule, hook.symbol);
if (!ptr) {
Wh_Log(L"ExplorerPatcher symbol%s doesn't exist: %S",
hook.optional ? L" (optional)" : L"", hook.symbol);
if (!hook.optional) {
succeeded = false;
}
continue;
}

if (hook.hookFunction) {
Wh_SetFunctionHook(ptr, hook.hookFunction, hook.pOriginalFunction);
} else {
*hook.pOriginalFunction = ptr;
}
}

if (!succeeded) {
Wh_Log(L"HookExplorerPatcherSymbols failed");
} else if (g_initialized) {
Wh_ApplyHookOperations();
}

return succeeded;
}

bool IsExplorerPatcherModule(HMODULE module) {
WCHAR moduleFilePath[MAX_PATH];
switch (
GetModuleFileName(module, moduleFilePath, ARRAYSIZE(moduleFilePath))) {
case 0:
case ARRAYSIZE(moduleFilePath):
return false;
}

PCWSTR moduleFileName = wcsrchr(moduleFilePath, L'\\');
if (!moduleFileName) {
return false;
}

moduleFileName++;

if (_wcsnicmp(L"ep_taskbar.", moduleFileName, sizeof("ep_taskbar.") - 1) ==
0) {
Wh_Log(L"ExplorerPatcher taskbar module: %s", moduleFileName);
return true;
}

return false;
}

bool HandleLoadedExplorerPatcher() {
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModules(GetCurrentProcess(), hMods, sizeof(hMods),
&cbNeeded)) {
for (size_t i = 0; i < cbNeeded / sizeof(HMODULE); i++) {
if (IsExplorerPatcherModule(hMods[i])) {
return HookExplorerPatcherSymbols(hMods[i]);
}
}
}

return true;
}

using LoadLibraryExW_t = decltype(&LoadLibraryExW);
LoadLibraryExW_t LoadLibraryExW_Original;
HMODULE WINAPI LoadLibraryExW_Hook(LPCWSTR lpLibFileName,
HANDLE hFile,
DWORD dwFlags) {
HMODULE module = LoadLibraryExW_Original(lpLibFileName, hFile, dwFlags);
if (module && !((ULONG_PTR)module & 3) && !g_explorerPatcherInitialized) {
if (IsExplorerPatcherModule(module)) {
HookExplorerPatcherSymbols(module);
}
}

return module;
}

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_settings.oldTaskbarOnWin11) {
bool hasWin10Taskbar = g_winVersion < WinVersion::Win11_24H2;

if (g_winVersion >= WinVersion::Win11) {
g_winVersion = WinVersion::Win10;
}

if (hasWin10Taskbar && !HookTaskbarSymbols()) {
return FALSE;
}
} else if (!HookTaskbarSymbols()) {
return FALSE;
}

if (!HandleLoadedExplorerPatcher()) {
Wh_Log(L"HandleLoadedExplorerPatcher failed");
return FALSE;
}

HMODULE kernelBaseModule = GetModuleHandle(L"kernelbase.dll");
auto pKernelBaseLoadLibraryExW = (decltype(&LoadLibraryExW))GetProcAddress(
kernelBaseModule, "LoadLibraryExW");
WindhawkUtils::Wh_SetFunctionHookT(pKernelBaseLoadLibraryExW,
LoadLibraryExW_Hook,
&LoadLibraryExW_Original);

g_initialized = true;

return TRUE;
}

void Wh_ModAfterInit() {
Wh_Log(L">");

// Try again in case there's a race between the previous attempt and the
// LoadLibraryExW hook.
if (!g_explorerPatcherInitialized) {
HandleLoadedExplorerPatcher();
}
}

void Wh_ModUninit() {
Wh_Log(L">");
}

BOOL Wh_ModSettingsChanged(BOOL* bReload) {
Wh_Log(L">");

bool prevOldTaskbarOnWin11 = g_settings.oldTaskbarOnWin11;

LoadSettings();

*bReload = g_settings.oldTaskbarOnWin11 != prevOldTaskbarOnWin11;

return TRUE;
}

0 comments on commit e2a37f8

Please sign in to comment.