From 2c1f1174c471ca44c5a614b3ae6b0db5121dcb3e Mon Sep 17 00:00:00 2001 From: Alekseev Date: Sat, 17 May 2025 23:44:26 +0700 Subject: [PATCH 1/4] added mod auto-hide-desktop-after-inactivity.wh.cpp --- .../auto-hide-desktop-after-inactivity.wh.cpp | 327 ++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 mods/auto-hide-desktop-after-inactivity.wh.cpp diff --git a/mods/auto-hide-desktop-after-inactivity.wh.cpp b/mods/auto-hide-desktop-after-inactivity.wh.cpp new file mode 100644 index 000000000..0bc176c49 --- /dev/null +++ b/mods/auto-hide-desktop-after-inactivity.wh.cpp @@ -0,0 +1,327 @@ +// ==WindhawkMod== +// @id auto-hide-desktop-after-inactivity +// @name Auto Hide Desktop After Inactivity +// @description Automatically hides all windows and shows the desktop after a period of user inactivity +// @version 0.5 +// @author alekseev2014s +// @github https://github.com/Alekseev2014s +// @include explorer.exe +// @compilerOptions -lcomdlg32 +// ==/WindhawkMod== + +// ==WindhawkModReadme== +/* +# Auto Hide Desktop After Inactivity + +This mod automatically minimizes all open windows and hides the desktop +after a period of user inactivity. It's useful for shared environments, +kiosks, or simply to reduce visual clutter after you're away from your PC. + +## Features +- **Inactivity timeout**: Automatically hide the desktop after no input for a configurable number of seconds. +- **Lock screen timeout**: Optionally lock the workstation after a longer period of inactivity. +- **Fullscreen app detection**: Prevents the desktop from being hidden if a fullscreen application is active. +- **Process exclusions**: You can specify a list of executable names (like `vlc.exe`) to ignore during monitoring. + +## How it works +- When the system is idle for the specified timeout, the mod simulates a `Win+D` keystroke to hide all windows and show the desktop. +- If configured, after further inactivity, it automatically locks the workstation. +- User input such as mouse movement or keyboard activity restores the previous window state. +- Foreground fullscreen applications and excluded processes will prevent the desktop from being hidden. + +## Getting started +1. Install the mod in Windhawk. +2. Adjust the settings for: + - Timeout (in seconds) + - Lock timeout (optional) + - Excluded processes + - Fullscreen app handling +3. Let the system idle and watch the desktop auto-hide behavior in action. + +## Example use cases +- **Privacy**: Automatically hides sensitive windows when away. +- **Kiosk mode**: Resets to desktop after inactivity. +- **Clutter reduction**: Keeps your desktop clean when you're not using the PC. + +## Troubleshooting +- If the desktop is not hidden as expected, check that no fullscreen app or excluded process is active. +- To ensure it only runs once, the mod uses a global mutex to avoid interfering with other `explorer.exe` instances. +*/ +// ==/WindhawkModReadme== + +// ==WindhawkModSettings== +/* +- timeoutSeconds: 300 + $name: Inactivity timeout (seconds) + $description: The number of seconds of inactivity before hiding the desktop. + +- lockTimeoutSeconds: 600 + $name: Lock screen timeout (seconds) + $description: The number of seconds of inactivity before locking the workstation. + +- excludeProcesses: "" + $name: Excluded processes + $description: Semicolon-separated list of executable names to exclude from triggering desktop show (e.g. "vlc.exe;notepad.exe") + +- ignoreFullscreenApps: true + $name: Ignore fullscreen applications + $description: Prevent desktop from being shown if a fullscreen application is active. +*/ +// ==/WindhawkModSettings== + +#include +#include + +std::vector g_minimizedWindows; +std::vector excludedProcessList; + +DWORD setting_timeoutSeconds = 300; +DWORD setting_lockTimeoutSeconds = 600; +bool setting_ignoreFullscreenApps = true; + +constexpr DWORD kMouseMoveThreshold = 10; + +HANDLE hThread = nullptr; +bool stopThread = false; +bool desktopShownByMod = false; +POINT lastMousePos = {}; + +HANDLE g_singletonMutex = nullptr; + +bool lockPending = false; +DWORD timeDesktopShown = 0; + +enum class DesktopState { + Normal, + HiddenByMod +}; + +DesktopState desktopState = DesktopState::Normal; + +bool IsDesktopVisible() { + HWND shellWindow = GetShellWindow(); + HWND foreground = GetForegroundWindow(); + return foreground == shellWindow; +} + +void ToggleDesktopWithWinD() { + keybd_event(VK_LWIN, 0, 0, 0); // Win down + keybd_event('D', 0, 0, 0); // D down + keybd_event('D', 0, KEYEVENTF_KEYUP, 0); // D up + keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0); // Win up +} + +void HideDesktop() { + if (!IsDesktopVisible()) { + ToggleDesktopWithWinD(); + } + GetCursorPos(&lastMousePos); + desktopShownByMod = true; + timeDesktopShown = GetTickCount(); + lockPending = (setting_lockTimeoutSeconds > 0); +} + +void RestoreWindows() { + if (IsDesktopVisible()) { + ToggleDesktopWithWinD(); + } + + desktopShownByMod = false; +} + +void LoadSettings() { + int value; + value = Wh_GetIntSetting(L"timeoutSeconds"); + setting_timeoutSeconds = (value > 0) ? value : 300; + + value = Wh_GetIntSetting(L"lockTimeoutSeconds"); + setting_lockTimeoutSeconds = (value >= 0) ? value : 0; + + setting_ignoreFullscreenApps = Wh_GetIntSetting(L"ignoreFullscreenApps"); + + const wchar_t* excludeList = Wh_GetStringSetting(L"excludeProcesses"); + excludedProcessList.clear(); + if (excludeList && *excludeList) { + std::wstring listStr(excludeList); + size_t pos = 0; + while ((pos = listStr.find(L';')) != std::wstring::npos) { + std::wstring token = listStr.substr(0, pos); + if (!token.empty()) + excludedProcessList.push_back(token); + listStr.erase(0, pos + 1); + } + if (!listStr.empty()) + excludedProcessList.push_back(listStr); + } + + Wh_Log(L"Settings loaded: timeoutSeconds = %d, lockTimeoutSeconds = %d", + setting_timeoutSeconds, setting_lockTimeoutSeconds); +} + +bool IsExcludedProcessRunning() { + HWND hwnd = GetForegroundWindow(); + if (!hwnd) + return false; + + DWORD pid; + GetWindowThreadProcessId(hwnd, &pid); + + HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if (!hProcess) + return false; + + wchar_t exePath[MAX_PATH]; + DWORD size = ARRAYSIZE(exePath); + bool result = false; + + if (QueryFullProcessImageNameW(hProcess, 0, exePath, &size)) { + std::wstring exeName = exePath; + size_t pos = exeName.find_last_of(L"\\/"); + if (pos != std::wstring::npos) + exeName = exeName.substr(pos + 1); + + Wh_Log(L"Foreground exe: %s", exeName.c_str()); // ADD THIS + + for (const auto& excluded : excludedProcessList) { + if (_wcsicmp(exeName.c_str(), excluded.c_str()) == 0) { + result = true; + break; + } + } + } + + CloseHandle(hProcess); + return result; +} + +bool IsForegroundWindowFullscreen() { + HWND hwnd = GetForegroundWindow(); + if (!hwnd || hwnd == GetShellWindow()) + return false; + + MONITORINFO monitorInfo = { sizeof(monitorInfo) }; + HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + if (!GetMonitorInfo(hMonitor, &monitorInfo)) + return false; + + RECT windowRect; + GetWindowRect(hwnd, &windowRect); + + return EqualRect(&windowRect, &monitorInfo.rcMonitor); +} + +DWORD WINAPI MonitorThread(LPVOID) { + Wh_Log(L"Monitor thread started"); + + DWORD effectiveLastInputTime = GetTickCount(); + + while (!stopThread) { + LASTINPUTINFO lii = { sizeof(LASTINPUTINFO) }; + if (GetLastInputInfo(&lii)) { + DWORD currentTick = GetTickCount(); + DWORD systemLastInputTime = lii.dwTime; + + if (systemLastInputTime > effectiveLastInputTime) { + effectiveLastInputTime = systemLastInputTime; + } + + DWORD idleTime = currentTick - effectiveLastInputTime; + + DWORD desktopTimeoutMs = setting_timeoutSeconds * 1000; + DWORD lockTimeoutMs = setting_lockTimeoutSeconds * 1000; + + if (idleTime >= lockTimeoutMs) { + Wh_Log(L"Locking workstation"); + RestoreWindows(); + LockWorkStation(); + effectiveLastInputTime = GetTickCount(); + continue; + } + + if (desktopState == DesktopState::Normal && + idleTime >= desktopTimeoutMs) + { + if (setting_ignoreFullscreenApps && IsForegroundWindowFullscreen()) { + Wh_Log(L"Skipping hide: Fullscreen app detected"); + effectiveLastInputTime = GetTickCount(); + } else if (IsExcludedProcessRunning()) { + Wh_Log(L"Skipping hide: Excluded process detected"); + effectiveLastInputTime = GetTickCount(); + } else { + Wh_Log(L"Inactivity detected, showing desktop"); + HideDesktop(); + desktopState = DesktopState::HiddenByMod; + } + } + + if (desktopState == DesktopState::HiddenByMod) { + POINT currentMousePos; + GetCursorPos(¤tMousePos); + DWORD dx = abs(currentMousePos.x - lastMousePos.x); + DWORD dy = abs(currentMousePos.y - lastMousePos.y); + + if (dx >= kMouseMoveThreshold || dy >= kMouseMoveThreshold) { + Wh_Log(L"Restoring windows unlock input"); + RestoreWindows(); + desktopState = DesktopState::Normal; + effectiveLastInputTime = GetTickCount(); + } + } + } + + Sleep(200); + } + + Wh_Log(L"Monitor thread exiting"); + return 0; +} + +bool IsMainExplorerProcess() { + g_singletonMutex = CreateMutexW(nullptr, TRUE, L"Global\\WH_AutoShowDesktop_Mutex"); + if (g_singletonMutex && GetLastError() == ERROR_ALREADY_EXISTS) { + CloseHandle(g_singletonMutex); + g_singletonMutex = nullptr; + return false; + } + return true; +} + +void CleanupSingletonMutex() { + if (g_singletonMutex) { + CloseHandle(g_singletonMutex); + g_singletonMutex = nullptr; + } +} + +BOOL Wh_ModInit() { + LoadSettings(); + + if (!IsMainExplorerProcess()) + return TRUE; + + stopThread = false; + hThread = CreateThread(nullptr, 0, MonitorThread, nullptr, 0, nullptr); + + if (!hThread) { + CleanupSingletonMutex(); + return FALSE; + } + + return TRUE; +} + +void Wh_ModUninit() { + stopThread = true; + + if (hThread) { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + hThread = nullptr; + } + + CleanupSingletonMutex(); +} + +void Wh_ModSettingsChanged() { + LoadSettings(); +} From 09987e6bb782a4ab8b05ae577b056c7b0adf2587 Mon Sep 17 00:00:00 2001 From: Alekseev Date: Sun, 18 May 2025 02:33:40 +0700 Subject: [PATCH 2/4] excludedPrograms array, correct sleep, correct IsForegroundWindowFullscreen, correct FindCurrentProcessTaskbarWnd --- .../auto-hide-desktop-after-inactivity.wh.cpp | 247 ++++++++++++------ 1 file changed, 165 insertions(+), 82 deletions(-) diff --git a/mods/auto-hide-desktop-after-inactivity.wh.cpp b/mods/auto-hide-desktop-after-inactivity.wh.cpp index 0bc176c49..e99c59812 100644 --- a/mods/auto-hide-desktop-after-inactivity.wh.cpp +++ b/mods/auto-hide-desktop-after-inactivity.wh.cpp @@ -2,7 +2,7 @@ // @id auto-hide-desktop-after-inactivity // @name Auto Hide Desktop After Inactivity // @description Automatically hides all windows and shows the desktop after a period of user inactivity -// @version 0.5 +// @version 0.6 // @author alekseev2014s // @github https://github.com/Alekseev2014s // @include explorer.exe @@ -13,39 +13,43 @@ /* # Auto Hide Desktop After Inactivity -This mod automatically minimizes all open windows and hides the desktop -after a period of user inactivity. It's useful for shared environments, -kiosks, or simply to reduce visual clutter after you're away from your PC. +This mod automatically minimizes all open windows and shows the desktop +after a period of user inactivity. It is useful for shared environments, +kiosks, or simply to reduce visual clutter when you're away from your PC. ## Features -- **Inactivity timeout**: Automatically hide the desktop after no input for a configurable number of seconds. -- **Lock screen timeout**: Optionally lock the workstation after a longer period of inactivity. -- **Fullscreen app detection**: Prevents the desktop from being hidden if a fullscreen application is active. -- **Process exclusions**: You can specify a list of executable names (like `vlc.exe`) to ignore during monitoring. +- **Inactivity timeout**: Automatically shows the desktop after a configurable number of seconds without input. +- **Lock screen timeout**: Optionally locks the workstation after additional idle time. +- **Fullscreen app detection**: Prevents the desktop from being shown if a fullscreen application is active (optional). +- **Process exclusions**: Prevents desktop from hiding if any excluded program is currently focused. +- **Smart restoration**: Moving the mouse restores the previous window state automatically. ## How it works -- When the system is idle for the specified timeout, the mod simulates a `Win+D` keystroke to hide all windows and show the desktop. -- If configured, after further inactivity, it automatically locks the workstation. -- User input such as mouse movement or keyboard activity restores the previous window state. -- Foreground fullscreen applications and excluded processes will prevent the desktop from being hidden. - -## Getting started -1. Install the mod in Windhawk. -2. Adjust the settings for: - - Timeout (in seconds) - - Lock timeout (optional) - - Excluded processes - - Fullscreen app handling -3. Let the system idle and watch the desktop auto-hide behavior in action. - -## Example use cases -- **Privacy**: Automatically hides sensitive windows when away. -- **Kiosk mode**: Resets to desktop after inactivity. -- **Clutter reduction**: Keeps your desktop clean when you're not using the PC. +- After the inactivity timeout (`timeoutSeconds`), the desktop is shown by simulating the `Win+D` keystroke. +- If `lockTimeoutSeconds` is configured, and idle time continues past this value, the workstation is locked. +- The desktop is not shown if a fullscreen app is active (unless disabled), or if a specified excluded process is in the foreground. +- After the desktop is shown, moving the mouse restores the previous window state. +- Foreground fullscreen applications and excluded processes prevent activation of the mod. + +## Configuration +- `Inactivity timeout (seconds)`: Time of user inactivity after which the desktop will be shown. + - Set to **0** to disable automatic desktop hiding. +- `Lock screen timeout (seconds)`: Time of user inactivity after which the workstation will be locked. + - Set to **0** to disable automatic locking. +- `Excluded programs`: A list of process names (e.g., `vlc.exe`, `notepad.exe`) that will prevent desktop from being shown when focused. +- `Ignore fullscreen applications`: If enabled, fullscreen apps block desktop hiding. + +## Notes +- Runs only in the main `explorer.exe` process (the one that owns the taskbar). +- Uses `GetLastInputInfo` to track idle time. +- Foreground process name is compared case-insensitively against the excluded list. +- Fullscreen state is detected via `SHQueryUserNotificationState`. ## Troubleshooting -- If the desktop is not hidden as expected, check that no fullscreen app or excluded process is active. -- To ensure it only runs once, the mod uses a global mutex to avoid interfering with other `explorer.exe` instances. +- If nothing happens after the timeout, ensure: + - No excluded process is in the foreground. + - No fullscreen app is active (unless ignored). + - Mod settings are configured correctly and saved. */ // ==/WindhawkModReadme== @@ -59,8 +63,8 @@ kiosks, or simply to reduce visual clutter after you're away from your PC. $name: Lock screen timeout (seconds) $description: The number of seconds of inactivity before locking the workstation. -- excludeProcesses: "" - $name: Excluded processes +- excludedPrograms: [excluded1.exe] + $name: Excluded programs $description: Semicolon-separated list of executable names to exclude from triggering desktop show (e.g. "vlc.exe;notepad.exe") - ignoreFullscreenApps: true @@ -72,22 +76,27 @@ kiosks, or simply to reduce visual clutter after you're away from your PC. #include #include +#define TIMEIOUT_HIDE_DEFAULT (300) +#define TIMEIOUT_LOCK_DEFAULT (600) + std::vector g_minimizedWindows; std::vector excludedProcessList; -DWORD setting_timeoutSeconds = 300; -DWORD setting_lockTimeoutSeconds = 600; +DWORD setting_timeoutSeconds = TIMEIOUT_HIDE_DEFAULT; +DWORD setting_lockTimeoutSeconds = TIMEIOUT_LOCK_DEFAULT; bool setting_ignoreFullscreenApps = true; +bool timeoutHide = true; +bool timeoutLock = true; + constexpr DWORD kMouseMoveThreshold = 10; +HANDLE hStopEvent = nullptr; HANDLE hThread = nullptr; bool stopThread = false; bool desktopShownByMod = false; POINT lastMousePos = {}; -HANDLE g_singletonMutex = nullptr; - bool lockPending = false; DWORD timeDesktopShown = 0; @@ -129,33 +138,63 @@ void RestoreWindows() { desktopShownByMod = false; } +void LogExcludedProcesses() { + if (excludedProcessList.empty()) { + Wh_Log(L"Excluded processes list is empty"); + return; + } + + std::wstring message = L"Excluded processes:"; + + for (const auto& proc : excludedProcessList) { + message += L" " + proc; + } + + Wh_Log(L"%s", message.c_str()); +} + void LoadSettings() { int value; value = Wh_GetIntSetting(L"timeoutSeconds"); - setting_timeoutSeconds = (value > 0) ? value : 300; + if (value > 4) { + setting_timeoutSeconds = value; + } else { + setting_timeoutSeconds = TIMEIOUT_HIDE_DEFAULT; + timeoutHide = false; + } value = Wh_GetIntSetting(L"lockTimeoutSeconds"); - setting_lockTimeoutSeconds = (value >= 0) ? value : 0; + if (value > 5) { + setting_lockTimeoutSeconds = value; + } else { + setting_lockTimeoutSeconds = TIMEIOUT_LOCK_DEFAULT; + timeoutLock = false; + } + + if (setting_timeoutSeconds >= setting_lockTimeoutSeconds) { + timeoutLock = false; + } setting_ignoreFullscreenApps = Wh_GetIntSetting(L"ignoreFullscreenApps"); - const wchar_t* excludeList = Wh_GetStringSetting(L"excludeProcesses"); excludedProcessList.clear(); - if (excludeList && *excludeList) { - std::wstring listStr(excludeList); - size_t pos = 0; - while ((pos = listStr.find(L';')) != std::wstring::npos) { - std::wstring token = listStr.substr(0, pos); - if (!token.empty()) - excludedProcessList.push_back(token); - listStr.erase(0, pos + 1); + + for (int i = 0;; i++) { + wchar_t settingName[64]; + swprintf(settingName, ARRAYSIZE(settingName), L"excludedPrograms[%d]", i); + + const wchar_t* item = Wh_GetStringSetting(settingName); + if (!item || *item == L'\0') { + break; } - if (!listStr.empty()) - excludedProcessList.push_back(listStr); + + excludedProcessList.emplace_back(item); } Wh_Log(L"Settings loaded: timeoutSeconds = %d, lockTimeoutSeconds = %d", setting_timeoutSeconds, setting_lockTimeoutSeconds); + + LogExcludedProcesses(); } bool IsExcludedProcessRunning() { @@ -195,19 +234,28 @@ bool IsExcludedProcessRunning() { } bool IsForegroundWindowFullscreen() { - HWND hwnd = GetForegroundWindow(); - if (!hwnd || hwnd == GetShellWindow()) - return false; - - MONITORINFO monitorInfo = { sizeof(monitorInfo) }; - HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - if (!GetMonitorInfo(hMonitor, &monitorInfo)) - return false; - - RECT windowRect; - GetWindowRect(hwnd, &windowRect); - - return EqualRect(&windowRect, &monitorInfo.rcMonitor); + QUERY_USER_NOTIFICATION_STATE pquns; + if (FAILED(SHQueryUserNotificationState(&pquns))) { + return false; + } + + switch (pquns) { + case QUNS_NOT_PRESENT: + case QUNS_BUSY: + case QUNS_RUNNING_D3D_FULL_SCREEN: + return true; + + case QUNS_PRESENTATION_MODE: + case QUNS_ACCEPTS_NOTIFICATIONS: + case QUNS_QUIET_TIME: + case QUNS_APP: + return false; + + default: + Wh_Log(L"Unhandled QUERY_USER_NOTIFICATION_STATE: %d", pquns); + } + + return false; } DWORD WINAPI MonitorThread(LPVOID) { @@ -215,8 +263,10 @@ DWORD WINAPI MonitorThread(LPVOID) { DWORD effectiveLastInputTime = GetTickCount(); - while (!stopThread) { + while (true) { LASTINPUTINFO lii = { sizeof(LASTINPUTINFO) }; + DWORD waitTime = 200; + if (GetLastInputInfo(&lii)) { DWORD currentTick = GetTickCount(); DWORD systemLastInputTime = lii.dwTime; @@ -230,7 +280,16 @@ DWORD WINAPI MonitorThread(LPVOID) { DWORD desktopTimeoutMs = setting_timeoutSeconds * 1000; DWORD lockTimeoutMs = setting_lockTimeoutSeconds * 1000; - if (idleTime >= lockTimeoutMs) { + if (desktopState == DesktopState::Normal) { + DWORD minTimeout = std::min(desktopTimeoutMs, lockTimeoutMs); + if (idleTime < minTimeout) { + waitTime = std::min(minTimeout - idleTime, desktopTimeoutMs); + } else { + waitTime = 0; + } + } + + if (timeoutLock && idleTime >= lockTimeoutMs) { Wh_Log(L"Locking workstation"); RestoreWindows(); LockWorkStation(); @@ -238,7 +297,8 @@ DWORD WINAPI MonitorThread(LPVOID) { continue; } - if (desktopState == DesktopState::Normal && + if (timeoutHide && + desktopState == DesktopState::Normal && idleTime >= desktopTimeoutMs) { if (setting_ignoreFullscreenApps && IsForegroundWindowFullscreen()) { @@ -248,7 +308,7 @@ DWORD WINAPI MonitorThread(LPVOID) { Wh_Log(L"Skipping hide: Excluded process detected"); effectiveLastInputTime = GetTickCount(); } else { - Wh_Log(L"Inactivity detected, showing desktop"); + Wh_Log(L"Inactivity detected, hiding desktop"); HideDesktop(); desktopState = DesktopState::HiddenByMod; } @@ -268,42 +328,60 @@ DWORD WINAPI MonitorThread(LPVOID) { } } } + if (waitTime < 200) waitTime = 200; - Sleep(200); + DWORD waitResult = WaitForSingleObject(hStopEvent, waitTime); + if (waitResult == WAIT_OBJECT_0) { + break; + } } Wh_Log(L"Monitor thread exiting"); return 0; } -bool IsMainExplorerProcess() { - g_singletonMutex = CreateMutexW(nullptr, TRUE, L"Global\\WH_AutoShowDesktop_Mutex"); - if (g_singletonMutex && GetLastError() == ERROR_ALREADY_EXISTS) { - CloseHandle(g_singletonMutex); - g_singletonMutex = nullptr; - return false; +static BOOL CALLBACK EnumTaskbarWndProc(HWND hWnd, LPARAM lParam) +{ + DWORD pid = 0; + WCHAR className[32] = { 0 }; + GetWindowThreadProcessId(hWnd, &pid); + if (pid == GetCurrentProcessId() && + GetClassNameW(hWnd, className, ARRAYSIZE(className)) && + _wcsicmp(className, L"Shell_TrayWnd") == 0) + { + *reinterpret_cast(lParam) = hWnd; + return FALSE; // stop enumeration } - return true; + return TRUE; // continue } -void CleanupSingletonMutex() { - if (g_singletonMutex) { - CloseHandle(g_singletonMutex); - g_singletonMutex = nullptr; - } +static HWND FindCurrentProcessTaskbarWnd() +{ + HWND hTaskbarWnd = nullptr; + EnumWindows(EnumTaskbarWndProc, reinterpret_cast(&hTaskbarWnd)); + return hTaskbarWnd; } BOOL Wh_ModInit() { + if (!FindCurrentProcessTaskbarWnd()) { + HWND hTaskbarWnd = FindWindowW(L"Shell_TrayWnd", nullptr); + if (hTaskbarWnd) { + // The taskbar exists, but it's not owned by the current process. + return FALSE; + } + } + LoadSettings(); - if (!IsMainExplorerProcess()) - return TRUE; + hStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (!hStopEvent) { + return FALSE; + } stopThread = false; hThread = CreateThread(nullptr, 0, MonitorThread, nullptr, 0, nullptr); if (!hThread) { - CleanupSingletonMutex(); return FALSE; } @@ -311,7 +389,9 @@ BOOL Wh_ModInit() { } void Wh_ModUninit() { - stopThread = true; + if (hStopEvent) { + SetEvent(hStopEvent); + } if (hThread) { WaitForSingleObject(hThread, INFINITE); @@ -319,7 +399,10 @@ void Wh_ModUninit() { hThread = nullptr; } - CleanupSingletonMutex(); + if (hStopEvent) { + CloseHandle(hStopEvent); + hStopEvent = nullptr; + } } void Wh_ModSettingsChanged() { From 8ef11b764271cd6d6d8195d626264a4fee46cd3b Mon Sep 17 00:00:00 2001 From: Alekseev Date: Sun, 18 May 2025 12:09:45 +0700 Subject: [PATCH 3/4] correct event timeLock --- mods/auto-hide-desktop-after-inactivity.wh.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mods/auto-hide-desktop-after-inactivity.wh.cpp b/mods/auto-hide-desktop-after-inactivity.wh.cpp index e99c59812..c5257816e 100644 --- a/mods/auto-hide-desktop-after-inactivity.wh.cpp +++ b/mods/auto-hide-desktop-after-inactivity.wh.cpp @@ -171,10 +171,6 @@ void LoadSettings() { timeoutLock = false; } - if (setting_timeoutSeconds >= setting_lockTimeoutSeconds) { - timeoutLock = false; - } - setting_ignoreFullscreenApps = Wh_GetIntSetting(L"ignoreFullscreenApps"); excludedProcessList.clear(); @@ -289,7 +285,9 @@ DWORD WINAPI MonitorThread(LPVOID) { } } - if (timeoutLock && idleTime >= lockTimeoutMs) { + if (timeoutLock && + idleTime >= lockTimeoutMs && + desktopState == DesktopState::HiddenByMod) { Wh_Log(L"Locking workstation"); RestoreWindows(); LockWorkStation(); From 26f6c99150e1c451c27ea86cf20ff33c1aee7443 Mon Sep 17 00:00:00 2001 From: Alekseev Date: Sun, 18 May 2025 18:14:19 +0700 Subject: [PATCH 4/4] correct readme section, added use Wh_FreeStringSetting --- mods/auto-hide-desktop-after-inactivity.wh.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mods/auto-hide-desktop-after-inactivity.wh.cpp b/mods/auto-hide-desktop-after-inactivity.wh.cpp index c5257816e..6ec4c9fc6 100644 --- a/mods/auto-hide-desktop-after-inactivity.wh.cpp +++ b/mods/auto-hide-desktop-after-inactivity.wh.cpp @@ -14,8 +14,8 @@ # Auto Hide Desktop After Inactivity This mod automatically minimizes all open windows and shows the desktop -after a period of user inactivity. It is useful for shared environments, -kiosks, or simply to reduce visual clutter when you're away from your PC. +after a period of user inactivity. Optionally, it can also lock the workstation +after continued inactivity. It is useful for shared environments, or simply to reduce visual clutter and protect your session when you're away from your PC. ## Features - **Inactivity timeout**: Automatically shows the desktop after a configurable number of seconds without input. @@ -26,8 +26,8 @@ kiosks, or simply to reduce visual clutter when you're away from your PC. ## How it works - After the inactivity timeout (`timeoutSeconds`), the desktop is shown by simulating the `Win+D` keystroke. -- If `lockTimeoutSeconds` is configured, and idle time continues past this value, the workstation is locked. -- The desktop is not shown if a fullscreen app is active (unless disabled), or if a specified excluded process is in the foreground. +- If `lockTimeoutSeconds` is configured and idle time continues past this value, the workstation is locked. +- The desktop is not shown if a fullscreen app is active (unless disabled), or if a specified excluded process is in the focus. - After the desktop is shown, moving the mouse restores the previous window state. - Foreground fullscreen applications and excluded processes prevent activation of the mod. @@ -36,7 +36,7 @@ kiosks, or simply to reduce visual clutter when you're away from your PC. - Set to **0** to disable automatic desktop hiding. - `Lock screen timeout (seconds)`: Time of user inactivity after which the workstation will be locked. - Set to **0** to disable automatic locking. -- `Excluded programs`: A list of process names (e.g., `vlc.exe`, `notepad.exe`) that will prevent desktop from being shown when focused. +- `Excluded programs`: An array of process names (e.g., `vlc.exe`, `notepad.exe`) that will prevent the desktop from being shown or the system from being locked when focused. - `Ignore fullscreen applications`: If enabled, fullscreen apps block desktop hiding. ## Notes @@ -183,6 +183,7 @@ void LoadSettings() { if (!item || *item == L'\0') { break; } + Wh_FreeStringSetting(item); excludedProcessList.emplace_back(item); }