Skip to content

Instantly share code, notes, and snippets.

@pongo
Created March 18, 2025 16:50
Show Gist options
  • Save pongo/4ef98cac1f63ecf9785ab139bec8b02c to your computer and use it in GitHub Desktop.
Save pongo/4ef98cac1f63ecf9785ab139bec8b02c to your computer and use it in GitHub Desktop.
NoFlashWindow for 10 seconds
// ==WindhawkMod==
// @id no-flash-window-fork
// @name NoFlashWindow
// @description Prevent programs from flashing their windows on the taskbar
// @version 1.0
// @author m417z
// @github https://github.com/m417z
// @twitter https://twitter.com/m417z
// @homepage https://m417z.com/
// @include *
// ==/WindhawkMod==
// 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==
/*
# NoFlashWindow
Prevent programs from flashing their windows on the taskbar.
Inspired by [NoFlashWindow](https://github.com/mrexodia/NoFlashWindow) by Duncan
Ogilvie.
**Note**: Windows 11 seems to have [a native option for
this](https://www.elevenforum.com/t/enable-or-disable-show-flashing-on-taskbar-apps-in-windows-11.9968/).
![Screenshot](https://i.imgur.com/nVmyZrM.png)
*/
// ==/WindhawkModReadme==
// ==WindhawkModSettings==
/*
- mode: prevent
$name: Mode
$options:
- prevent: Prevent flashing
- limitToOne: Limit flashing to one time
- limitToTenSeconds: Limit flashing to 10 seconds
*/
// ==/WindhawkModSettings==
#include <unordered_map>
#include <vector>
#include <windows.h>
enum class Mode {
prevent,
limitToOne,
limitToTenSeconds,
};
struct {
Mode mode;
} g_settings;
struct WindowFlashInfo {
DWORD startTime;
HWND hWnd;
};
// Хранит информацию о мигающих окнах и времени начала мигания
std::unordered_map<HWND, DWORD> g_flashingWindows;
// Таймер для проверки и сброса мигающих окон
UINT_PTR g_flashTimer = 0;
// Функция обратного вызова для таймера
VOID CALLBACK FlashTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {
Wh_Log(L"Checking flashing windows timer");
DWORD currentTime = GetTickCount();
std::vector<HWND> windowsToReset;
// Проверяем все мигающие окна
for (auto it = g_flashingWindows.begin(); it != g_flashingWindows.end(); ++it) {
HWND hWnd = it->first;
DWORD startTime = it->second;
// Если окно мигает более 10 секунд (10000 мс)
if (currentTime - startTime > 10000) {
windowsToReset.push_back(hWnd);
}
}
// Сбрасываем мигание для окон, которые мигали слишком долго
for (HWND hWnd : windowsToReset) {
Wh_Log(L"Resetting flash for window after 10 seconds");
FLASHWINFO fwi = {};
fwi.cbSize = sizeof(FLASHWINFO);
fwi.hwnd = hWnd;
fwi.dwFlags = FLASHW_STOP;
FlashWindowEx(&fwi);
g_flashingWindows.erase(hWnd);
}
// Если больше нет мигающих окон, удаляем таймер
if (g_flashingWindows.empty() && g_flashTimer != 0) {
KillTimer(NULL, g_flashTimer);
g_flashTimer = 0;
Wh_Log(L"No more flashing windows, killing timer");
}
}
using FlashWindow_t = decltype(&FlashWindow);
FlashWindow_t FlashWindow_Original;
BOOL WINAPI FlashWindow_Hook(HWND hWnd, WINBOOL bInvert) {
Wh_Log(L"FlashWindow called");
if (g_settings.mode == Mode::prevent) {
return TRUE;
}
if (g_settings.mode == Mode::limitToTenSeconds) {
// Записываем время начала мигания
if (bInvert) {
g_flashingWindows[hWnd] = GetTickCount();
// Создаем таймер, если он еще не создан
if (g_flashTimer == 0) {
g_flashTimer = SetTimer(NULL, 0, 1000, FlashTimerProc);
Wh_Log(L"Created flash timer");
}
}
}
return FlashWindow_Original(hWnd, bInvert);
}
using FlashWindowEx_t = decltype(&FlashWindowEx);
FlashWindowEx_t FlashWindowEx_Original;
BOOL WINAPI FlashWindowEx_Hook(PFLASHWINFO pfwi) {
Wh_Log(L"FlashWindowEx called");
if (g_settings.mode == Mode::prevent) {
return TRUE;
}
FLASHWINFO newFwi = *pfwi;
if (g_settings.mode == Mode::limitToOne) {
newFwi.dwFlags &= ~(FLASHW_TIMER | FLASHW_TIMERNOFG);
if (newFwi.uCount > 1) {
newFwi.uCount = 1;
}
}
else if (g_settings.mode == Mode::limitToTenSeconds) {
// Если это не запрос на остановку мигания
if (!(pfwi->dwFlags & FLASHW_STOP)) {
// Записываем время начала мигания
g_flashingWindows[pfwi->hwnd] = GetTickCount();
// Создаем таймер, если он еще не создан
if (g_flashTimer == 0) {
g_flashTimer = SetTimer(NULL, 0, 1000, FlashTimerProc);
Wh_Log(L"Created flash timer for FlashWindowEx");
}
}
else {
// Если это запрос на остановку мигания, удаляем окно из списка
g_flashingWindows.erase(pfwi->hwnd);
}
}
return FlashWindowEx_Original(&newFwi);
}
void LoadSettings() {
PCWSTR mode = Wh_GetStringSetting(L"mode");
g_settings.mode = Mode::prevent;
if (wcscmp(mode, L"limitToOne") == 0) {
g_settings.mode = Mode::limitToOne;
}
else if (wcscmp(mode, L"limitToTenSeconds") == 0) {
g_settings.mode = Mode::limitToTenSeconds;
}
Wh_FreeStringSetting(mode);
}
BOOL Wh_ModInit() {
Wh_Log(L"Mod initializing");
LoadSettings();
Wh_SetFunctionHook((void*)FlashWindow, (void*)FlashWindow_Hook,
(void**)&FlashWindow_Original);
Wh_SetFunctionHook((void*)FlashWindowEx, (void*)FlashWindowEx_Hook,
(void**)&FlashWindowEx_Original);
return TRUE;
}
void Wh_ModUninit() {
Wh_Log(L"Mod unloading");
// Удаляем таймер при выгрузке мода
if (g_flashTimer != 0) {
KillTimer(NULL, g_flashTimer);
g_flashTimer = 0;
}
// Очищаем список мигающих окон
g_flashingWindows.clear();
}
void Wh_ModSettingsChanged() {
Wh_Log(L"Settings changed");
LoadSettings();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment