From f12240ce8639addd9125ad163900929c421de379 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:38:25 +0600 Subject: [PATCH 01/17] Create samiulislam16.wh.cpp --- mods/mods/samiulislam16.wh.cpp | 253 +++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 mods/mods/samiulislam16.wh.cpp diff --git a/mods/mods/samiulislam16.wh.cpp b/mods/mods/samiulislam16.wh.cpp new file mode 100644 index 0000000000..3e20c371e9 --- /dev/null +++ b/mods/mods/samiulislam16.wh.cpp @@ -0,0 +1,253 @@ +// ==WindhawkMod== +// @id 11macos-shake-to-find-cursor +// @name 11macOS Shake to Find Cursor +// @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. +// @version 0.5 +// @author samiulislam16 +// @github https://github.com/samiulislam16 +// @include * +// @compilerOptions -luser32 -lgdi32 -lshcore +// @license MIT +// ==/WindhawkMod== + +// ==WindhawkModReadme== +/* +# Shake to Find Cursor + +Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! + +When you rapidly shake your mouse back and forth, the cursor temporarily +grows larger to help you spot it on screen. Once you stop shaking, it +smoothly animates back to its normal size. + +## How to Use +1. Shake your mouse rapidly left-right (or up-down) +2. The cursor enlarges so you can find it easily +3. Stop moving and it shrinks back to normal + +## Settings +- *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) +- *Enlarge duration* — how long the cursor stays big after shaking stops (ms) +- *Shake sensitivity* — minimum direction changes needed to trigger +*/ +// ==/WindhawkModReadme== + +// ==WindhawkModSettings== +/* +- cursorScale: 350 + $name: Cursor scale (%) + $description: How large the cursor grows. 200 = 2×, 350 = 3.5×, 500 = 5×. +- enlargeDuration: 500 + $name: Enlarge duration (ms) + $description: How long the cursor stays enlarged after you stop shaking. +- shakeSensitivity: 4 + $name: Shake sensitivity (direction changes) + $description: Minimum direction reversals needed to trigger. Lower = easier to trigger. +- minSpeed: 550 + $name: Minimum movement speed (pixels/sec) + $description: Average speed threshold for shake detection. Lower = easier to trigger. +*/ +// ==/WindhawkModSettings== + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +// ─── Runtime settings (loaded from Windhawk UI) ───────────────────────────── + +struct ModSettings { + double scaleFactor; + int enlargeDurationMs; + int minDirectionChanges; + double minMovementSpeed; +}; + +static ModSettings g_cfg; + +static void LoadSettings() { + int scale = Wh_GetIntSetting(L"cursorScale"); + if (scale <= 100) scale = 350; + g_cfg.scaleFactor = scale / 100.0; + + g_cfg.enlargeDurationMs = Wh_GetIntSetting(L"enlargeDuration"); + if (g_cfg.enlargeDurationMs <= 0) g_cfg.enlargeDurationMs = 500; + + g_cfg.minDirectionChanges = Wh_GetIntSetting(L"shakeSensitivity"); + if (g_cfg.minDirectionChanges <= 0) g_cfg.minDirectionChanges = 4; + + int speed = Wh_GetIntSetting(L"minSpeed"); + if (speed <= 0) speed = 550; + g_cfg.minMovementSpeed = (double)speed; +} + +// ─── Constants (non-configurable) ─────────────────────────────────────────── + +static constexpr size_t kHistorySize = 10; +static constexpr int kMaxTimeWindow = 400; + +struct MouseSample { + POINT pt; + DWORD time; +}; + +// ─── Global state ─────────────────────────────────────────────────────────── + +std::vector g_history; +bool g_isEnlarged = false; +HCURSOR g_hNormalCursor = NULL; +HCURSOR g_hEnlargedCursor = NULL; +UINT_PTR g_nResetTimerId = 0; +UINT_PTR g_nPollingTimerId = 0; + +// ─── Cursor scaling ───────────────────────────────────────────────────────── + +HCURSOR CreateScaledCursor(HCURSOR hSrcCursor, float scale) { + if (!hSrcCursor) return NULL; + ICONINFO iconInfo; + if (!GetIconInfo(hSrcCursor, &iconInfo)) return NULL; + + BITMAP bmColor; + GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor); + + int newWidth = (int)(bmColor.bmWidth * scale); + int newHeight = (int)(bmColor.bmHeight * scale); + + HDC hdc = GetDC(NULL); + HDC hdcSrc = CreateCompatibleDC(hdc); + HDC hdcDst = CreateCompatibleDC(hdc); + + HBITMAP hbmColorNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); + SelectObject(hdcSrc, iconInfo.hbmColor); + SelectObject(hdcDst, hbmColorNew); + StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); + + HBITMAP hbmMaskNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); + SelectObject(hdcSrc, iconInfo.hbmMask); + SelectObject(hdcDst, hbmMaskNew); + StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); + + DeleteDC(hdcSrc); + DeleteDC(hdcDst); + ReleaseDC(NULL, hdc); + + ICONINFO newIconInfo = iconInfo; + newIconInfo.fIcon = FALSE; + newIconInfo.xHotspot = (DWORD)(iconInfo.xHotspot * scale); + newIconInfo.yHotspot = (DWORD)(iconInfo.yHotspot * scale); + newIconInfo.hbmMask = hbmMaskNew; + newIconInfo.hbmColor = hbmColorNew; + + HCURSOR hNewCursor = CreateIconIndirect(&newIconInfo); + + DeleteObject(hbmMaskNew); + DeleteObject(hbmColorNew); + DeleteObject(iconInfo.hbmMask); + DeleteObject(iconInfo.hbmColor); + + return hNewCursor; +} + +// ─── Cursor restore ───────────────────────────────────────────────────────── + +void RestoreCursor() { + if (g_isEnlarged) { + SystemParametersInfo(SPI_SETCURSORS, 0, NULL, SPIF_SENDCHANGE); + g_isEnlarged = false; + } +} + +VOID CALLBACK ResetTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + KillTimer(NULL, g_nResetTimerId); + g_nResetTimerId = 0; + RestoreCursor(); +} + +// ─── Shake detection + trigger ────────────────────────────────────────────── + +void ProcessMouseTelemetry(POINT pt) { + DWORD time = GetTickCount(); + MouseSample sample = { pt, time }; + g_history.push_back(sample); + + if (g_history.size() > kHistorySize) { + g_history.erase(g_history.begin()); + } + + if (g_history.size() < 4) return; + + int dirChangesX = 0, dirChangesY = 0; + int lastDirX = 0, lastDirY = 0; + float totalDistance = 0.0f; + + for (size_t i = 1; i < g_history.size(); ++i) { + int dx = g_history[i].pt.x - g_history[i - 1].pt.x; + int dy = g_history[i].pt.y - g_history[i - 1].pt.y; + totalDistance += sqrt(float(dx * dx + dy * dy)); + + int dirX = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0); + int dirY = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0); + + if (dirX != 0) { + if (lastDirX != 0 && dirX != lastDirX) dirChangesX++; + lastDirX = dirX; + } + if (dirY != 0) { + if (lastDirY != 0 && dirY != lastDirY) dirChangesY++; + lastDirY = dirY; + } + } + + DWORD timeDelta = g_history.back().time - g_history.front().time; + if (timeDelta == 0 || timeDelta > (DWORD)kMaxTimeWindow) return; + + float speed = (totalDistance / (float)timeDelta) * 1000.0f; + + if (speed > g_cfg.minMovementSpeed && + (dirChangesX >= g_cfg.minDirectionChanges || dirChangesY >= g_cfg.minDirectionChanges)) { + + if (!g_isEnlarged) { + g_hNormalCursor = LoadCursor(NULL, IDC_ARROW); + g_hEnlargedCursor = CreateScaledCursor(g_hNormalCursor, (float)g_cfg.scaleFactor); + + if (g_hEnlargedCursor) { + SetSystemCursor(CopyCursor(g_hEnlargedCursor), 32512); // OCR_NORMAL + g_isEnlarged = true; + } + } + + if (g_nResetTimerId) KillTimer(NULL, g_nResetTimerId); + g_nResetTimerId = SetTimer(NULL, 0, g_cfg.enlargeDurationMs, ResetTimerProc); + } +} + +// ─── Polling timer ────────────────────────────────────────────────────────── + +VOID CALLBACK PollingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + CURSORINFO ci = { sizeof(CURSORINFO) }; + if (GetCursorInfo(&ci) && (ci.flags & CURSOR_SHOWING)) { + ProcessMouseTelemetry(ci.ptScreenPos); + } +} + +// ─── Windhawk entry points ────────────────────────────────────────────────── + +BOOL Wh_ModInit(void) { + LoadSettings(); + g_nPollingTimerId = SetTimer(NULL, 0, 16, PollingTimerProc); + return (g_nPollingTimerId != 0); +} + +void Wh_ModUninit(void) { + if (g_nPollingTimerId) { + KillTimer(NULL, g_nPollingTimerId); + } + if (g_nResetTimerId) { + KillTimer(NULL, g_nResetTimerId); + } + RestoreCursor(); +} + +void Wh_ModSettingsChanged(void) { + LoadSettings(); +} From 117539820a5dafc6e23171d9bd773ad58871f3f6 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:50:33 +0600 Subject: [PATCH 02/17] Create README.md --- mods/mods/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 mods/mods/README.md diff --git a/mods/mods/README.md b/mods/mods/README.md new file mode 100644 index 0000000000..006c87fa3b --- /dev/null +++ b/mods/mods/README.md @@ -0,0 +1,19 @@ + +# Shake to Find Cursor + +Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! + +When you rapidly shake your mouse back and forth, the cursor temporarily +grows larger to help you spot it on screen. Once you stop shaking, it +smoothly animates back to its normal size. +restart explorer if neened + +## How to Use +1. Shake your mouse rapidly left-right (or up-down) +2. The cursor enlarges so you can find it easily +3. Stop moving and it shrinks back to normal + +## Settings +- *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) +- *Enlarge duration* — how long the cursor stays big after shaking stops (ms) +- *Shake sensitivity* — minimum direction changes needed to trigger From f28cf1d754170858a1f443518d3390a572f056d3 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:51:31 +0600 Subject: [PATCH 03/17] Update README.md --- mods/mods/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/mods/README.md b/mods/mods/README.md index 006c87fa3b..8bbd7dd66f 100644 --- a/mods/mods/README.md +++ b/mods/mods/README.md @@ -6,12 +6,12 @@ Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! When you rapidly shake your mouse back and forth, the cursor temporarily grows larger to help you spot it on screen. Once you stop shaking, it smoothly animates back to its normal size. -restart explorer if neened ## How to Use 1. Shake your mouse rapidly left-right (or up-down) 2. The cursor enlarges so you can find it easily 3. Stop moving and it shrinks back to normal +4. Restart explorer if neened ## Settings - *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) From c84f87b265e443c0a56f397dde42deae5792ec72 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:51:55 +0600 Subject: [PATCH 04/17] Update README.md --- mods/mods/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/mods/README.md b/mods/mods/README.md index 8bbd7dd66f..8c2a94d61b 100644 --- a/mods/mods/README.md +++ b/mods/mods/README.md @@ -11,7 +11,7 @@ smoothly animates back to its normal size. 1. Shake your mouse rapidly left-right (or up-down) 2. The cursor enlarges so you can find it easily 3. Stop moving and it shrinks back to normal -4. Restart explorer if neened +4. Restart explorer if needed ## Settings - *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) From 9959fcd2bb3cb56c9739bf25f6d3670da049b600 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:52:49 +0600 Subject: [PATCH 05/17] Rename samiulislam16.wh.cpp to 11macos-shake-to-find-cursor.wh.cpp --- .../{samiulislam16.wh.cpp => 11macos-shake-to-find-cursor.wh.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mods/mods/{samiulislam16.wh.cpp => 11macos-shake-to-find-cursor.wh.cpp} (100%) diff --git a/mods/mods/samiulislam16.wh.cpp b/mods/mods/11macos-shake-to-find-cursor.wh.cpp similarity index 100% rename from mods/mods/samiulislam16.wh.cpp rename to mods/mods/11macos-shake-to-find-cursor.wh.cpp From 8ffe2394d5354018632b7454c7df5b27b35087ab Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 00:02:00 +0600 Subject: [PATCH 06/17] Create 11macos-shake-to-find-cursor.wh.cpp --- mods/11macos-shake-to-find-cursor.wh.cpp | 253 +++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 mods/11macos-shake-to-find-cursor.wh.cpp diff --git a/mods/11macos-shake-to-find-cursor.wh.cpp b/mods/11macos-shake-to-find-cursor.wh.cpp new file mode 100644 index 0000000000..3e20c371e9 --- /dev/null +++ b/mods/11macos-shake-to-find-cursor.wh.cpp @@ -0,0 +1,253 @@ +// ==WindhawkMod== +// @id 11macos-shake-to-find-cursor +// @name 11macOS Shake to Find Cursor +// @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. +// @version 0.5 +// @author samiulislam16 +// @github https://github.com/samiulislam16 +// @include * +// @compilerOptions -luser32 -lgdi32 -lshcore +// @license MIT +// ==/WindhawkMod== + +// ==WindhawkModReadme== +/* +# Shake to Find Cursor + +Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! + +When you rapidly shake your mouse back and forth, the cursor temporarily +grows larger to help you spot it on screen. Once you stop shaking, it +smoothly animates back to its normal size. + +## How to Use +1. Shake your mouse rapidly left-right (or up-down) +2. The cursor enlarges so you can find it easily +3. Stop moving and it shrinks back to normal + +## Settings +- *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) +- *Enlarge duration* — how long the cursor stays big after shaking stops (ms) +- *Shake sensitivity* — minimum direction changes needed to trigger +*/ +// ==/WindhawkModReadme== + +// ==WindhawkModSettings== +/* +- cursorScale: 350 + $name: Cursor scale (%) + $description: How large the cursor grows. 200 = 2×, 350 = 3.5×, 500 = 5×. +- enlargeDuration: 500 + $name: Enlarge duration (ms) + $description: How long the cursor stays enlarged after you stop shaking. +- shakeSensitivity: 4 + $name: Shake sensitivity (direction changes) + $description: Minimum direction reversals needed to trigger. Lower = easier to trigger. +- minSpeed: 550 + $name: Minimum movement speed (pixels/sec) + $description: Average speed threshold for shake detection. Lower = easier to trigger. +*/ +// ==/WindhawkModSettings== + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +// ─── Runtime settings (loaded from Windhawk UI) ───────────────────────────── + +struct ModSettings { + double scaleFactor; + int enlargeDurationMs; + int minDirectionChanges; + double minMovementSpeed; +}; + +static ModSettings g_cfg; + +static void LoadSettings() { + int scale = Wh_GetIntSetting(L"cursorScale"); + if (scale <= 100) scale = 350; + g_cfg.scaleFactor = scale / 100.0; + + g_cfg.enlargeDurationMs = Wh_GetIntSetting(L"enlargeDuration"); + if (g_cfg.enlargeDurationMs <= 0) g_cfg.enlargeDurationMs = 500; + + g_cfg.minDirectionChanges = Wh_GetIntSetting(L"shakeSensitivity"); + if (g_cfg.minDirectionChanges <= 0) g_cfg.minDirectionChanges = 4; + + int speed = Wh_GetIntSetting(L"minSpeed"); + if (speed <= 0) speed = 550; + g_cfg.minMovementSpeed = (double)speed; +} + +// ─── Constants (non-configurable) ─────────────────────────────────────────── + +static constexpr size_t kHistorySize = 10; +static constexpr int kMaxTimeWindow = 400; + +struct MouseSample { + POINT pt; + DWORD time; +}; + +// ─── Global state ─────────────────────────────────────────────────────────── + +std::vector g_history; +bool g_isEnlarged = false; +HCURSOR g_hNormalCursor = NULL; +HCURSOR g_hEnlargedCursor = NULL; +UINT_PTR g_nResetTimerId = 0; +UINT_PTR g_nPollingTimerId = 0; + +// ─── Cursor scaling ───────────────────────────────────────────────────────── + +HCURSOR CreateScaledCursor(HCURSOR hSrcCursor, float scale) { + if (!hSrcCursor) return NULL; + ICONINFO iconInfo; + if (!GetIconInfo(hSrcCursor, &iconInfo)) return NULL; + + BITMAP bmColor; + GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor); + + int newWidth = (int)(bmColor.bmWidth * scale); + int newHeight = (int)(bmColor.bmHeight * scale); + + HDC hdc = GetDC(NULL); + HDC hdcSrc = CreateCompatibleDC(hdc); + HDC hdcDst = CreateCompatibleDC(hdc); + + HBITMAP hbmColorNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); + SelectObject(hdcSrc, iconInfo.hbmColor); + SelectObject(hdcDst, hbmColorNew); + StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); + + HBITMAP hbmMaskNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); + SelectObject(hdcSrc, iconInfo.hbmMask); + SelectObject(hdcDst, hbmMaskNew); + StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); + + DeleteDC(hdcSrc); + DeleteDC(hdcDst); + ReleaseDC(NULL, hdc); + + ICONINFO newIconInfo = iconInfo; + newIconInfo.fIcon = FALSE; + newIconInfo.xHotspot = (DWORD)(iconInfo.xHotspot * scale); + newIconInfo.yHotspot = (DWORD)(iconInfo.yHotspot * scale); + newIconInfo.hbmMask = hbmMaskNew; + newIconInfo.hbmColor = hbmColorNew; + + HCURSOR hNewCursor = CreateIconIndirect(&newIconInfo); + + DeleteObject(hbmMaskNew); + DeleteObject(hbmColorNew); + DeleteObject(iconInfo.hbmMask); + DeleteObject(iconInfo.hbmColor); + + return hNewCursor; +} + +// ─── Cursor restore ───────────────────────────────────────────────────────── + +void RestoreCursor() { + if (g_isEnlarged) { + SystemParametersInfo(SPI_SETCURSORS, 0, NULL, SPIF_SENDCHANGE); + g_isEnlarged = false; + } +} + +VOID CALLBACK ResetTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + KillTimer(NULL, g_nResetTimerId); + g_nResetTimerId = 0; + RestoreCursor(); +} + +// ─── Shake detection + trigger ────────────────────────────────────────────── + +void ProcessMouseTelemetry(POINT pt) { + DWORD time = GetTickCount(); + MouseSample sample = { pt, time }; + g_history.push_back(sample); + + if (g_history.size() > kHistorySize) { + g_history.erase(g_history.begin()); + } + + if (g_history.size() < 4) return; + + int dirChangesX = 0, dirChangesY = 0; + int lastDirX = 0, lastDirY = 0; + float totalDistance = 0.0f; + + for (size_t i = 1; i < g_history.size(); ++i) { + int dx = g_history[i].pt.x - g_history[i - 1].pt.x; + int dy = g_history[i].pt.y - g_history[i - 1].pt.y; + totalDistance += sqrt(float(dx * dx + dy * dy)); + + int dirX = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0); + int dirY = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0); + + if (dirX != 0) { + if (lastDirX != 0 && dirX != lastDirX) dirChangesX++; + lastDirX = dirX; + } + if (dirY != 0) { + if (lastDirY != 0 && dirY != lastDirY) dirChangesY++; + lastDirY = dirY; + } + } + + DWORD timeDelta = g_history.back().time - g_history.front().time; + if (timeDelta == 0 || timeDelta > (DWORD)kMaxTimeWindow) return; + + float speed = (totalDistance / (float)timeDelta) * 1000.0f; + + if (speed > g_cfg.minMovementSpeed && + (dirChangesX >= g_cfg.minDirectionChanges || dirChangesY >= g_cfg.minDirectionChanges)) { + + if (!g_isEnlarged) { + g_hNormalCursor = LoadCursor(NULL, IDC_ARROW); + g_hEnlargedCursor = CreateScaledCursor(g_hNormalCursor, (float)g_cfg.scaleFactor); + + if (g_hEnlargedCursor) { + SetSystemCursor(CopyCursor(g_hEnlargedCursor), 32512); // OCR_NORMAL + g_isEnlarged = true; + } + } + + if (g_nResetTimerId) KillTimer(NULL, g_nResetTimerId); + g_nResetTimerId = SetTimer(NULL, 0, g_cfg.enlargeDurationMs, ResetTimerProc); + } +} + +// ─── Polling timer ────────────────────────────────────────────────────────── + +VOID CALLBACK PollingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + CURSORINFO ci = { sizeof(CURSORINFO) }; + if (GetCursorInfo(&ci) && (ci.flags & CURSOR_SHOWING)) { + ProcessMouseTelemetry(ci.ptScreenPos); + } +} + +// ─── Windhawk entry points ────────────────────────────────────────────────── + +BOOL Wh_ModInit(void) { + LoadSettings(); + g_nPollingTimerId = SetTimer(NULL, 0, 16, PollingTimerProc); + return (g_nPollingTimerId != 0); +} + +void Wh_ModUninit(void) { + if (g_nPollingTimerId) { + KillTimer(NULL, g_nPollingTimerId); + } + if (g_nResetTimerId) { + KillTimer(NULL, g_nResetTimerId); + } + RestoreCursor(); +} + +void Wh_ModSettingsChanged(void) { + LoadSettings(); +} From d4371bf1be01e6092cdc3b7bcb2e94c397f22dce Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 00:03:21 +0600 Subject: [PATCH 07/17] Update 11macos-shake-to-find-cursor.wh.cpp --- mods/11macos-shake-to-find-cursor.wh.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/11macos-shake-to-find-cursor.wh.cpp b/mods/11macos-shake-to-find-cursor.wh.cpp index 3e20c371e9..1072ede7c5 100644 --- a/mods/11macos-shake-to-find-cursor.wh.cpp +++ b/mods/11macos-shake-to-find-cursor.wh.cpp @@ -24,6 +24,7 @@ smoothly animates back to its normal size. 1. Shake your mouse rapidly left-right (or up-down) 2. The cursor enlarges so you can find it easily 3. Stop moving and it shrinks back to normal +4. Restart explorer if needed ## Settings - *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) From 671a039a3f2dfea428fab27c55fd8053ee2f342a Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:23:12 +0600 Subject: [PATCH 08/17] Create macos-shake-to-find-cursor.wh.cpp --- mods/macos-shake-to-find-cursor.wh.cpp | 254 +++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 mods/macos-shake-to-find-cursor.wh.cpp diff --git a/mods/macos-shake-to-find-cursor.wh.cpp b/mods/macos-shake-to-find-cursor.wh.cpp new file mode 100644 index 0000000000..1072ede7c5 --- /dev/null +++ b/mods/macos-shake-to-find-cursor.wh.cpp @@ -0,0 +1,254 @@ +// ==WindhawkMod== +// @id 11macos-shake-to-find-cursor +// @name 11macOS Shake to Find Cursor +// @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. +// @version 0.5 +// @author samiulislam16 +// @github https://github.com/samiulislam16 +// @include * +// @compilerOptions -luser32 -lgdi32 -lshcore +// @license MIT +// ==/WindhawkMod== + +// ==WindhawkModReadme== +/* +# Shake to Find Cursor + +Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! + +When you rapidly shake your mouse back and forth, the cursor temporarily +grows larger to help you spot it on screen. Once you stop shaking, it +smoothly animates back to its normal size. + +## How to Use +1. Shake your mouse rapidly left-right (or up-down) +2. The cursor enlarges so you can find it easily +3. Stop moving and it shrinks back to normal +4. Restart explorer if needed + +## Settings +- *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) +- *Enlarge duration* — how long the cursor stays big after shaking stops (ms) +- *Shake sensitivity* — minimum direction changes needed to trigger +*/ +// ==/WindhawkModReadme== + +// ==WindhawkModSettings== +/* +- cursorScale: 350 + $name: Cursor scale (%) + $description: How large the cursor grows. 200 = 2×, 350 = 3.5×, 500 = 5×. +- enlargeDuration: 500 + $name: Enlarge duration (ms) + $description: How long the cursor stays enlarged after you stop shaking. +- shakeSensitivity: 4 + $name: Shake sensitivity (direction changes) + $description: Minimum direction reversals needed to trigger. Lower = easier to trigger. +- minSpeed: 550 + $name: Minimum movement speed (pixels/sec) + $description: Average speed threshold for shake detection. Lower = easier to trigger. +*/ +// ==/WindhawkModSettings== + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +// ─── Runtime settings (loaded from Windhawk UI) ───────────────────────────── + +struct ModSettings { + double scaleFactor; + int enlargeDurationMs; + int minDirectionChanges; + double minMovementSpeed; +}; + +static ModSettings g_cfg; + +static void LoadSettings() { + int scale = Wh_GetIntSetting(L"cursorScale"); + if (scale <= 100) scale = 350; + g_cfg.scaleFactor = scale / 100.0; + + g_cfg.enlargeDurationMs = Wh_GetIntSetting(L"enlargeDuration"); + if (g_cfg.enlargeDurationMs <= 0) g_cfg.enlargeDurationMs = 500; + + g_cfg.minDirectionChanges = Wh_GetIntSetting(L"shakeSensitivity"); + if (g_cfg.minDirectionChanges <= 0) g_cfg.minDirectionChanges = 4; + + int speed = Wh_GetIntSetting(L"minSpeed"); + if (speed <= 0) speed = 550; + g_cfg.minMovementSpeed = (double)speed; +} + +// ─── Constants (non-configurable) ─────────────────────────────────────────── + +static constexpr size_t kHistorySize = 10; +static constexpr int kMaxTimeWindow = 400; + +struct MouseSample { + POINT pt; + DWORD time; +}; + +// ─── Global state ─────────────────────────────────────────────────────────── + +std::vector g_history; +bool g_isEnlarged = false; +HCURSOR g_hNormalCursor = NULL; +HCURSOR g_hEnlargedCursor = NULL; +UINT_PTR g_nResetTimerId = 0; +UINT_PTR g_nPollingTimerId = 0; + +// ─── Cursor scaling ───────────────────────────────────────────────────────── + +HCURSOR CreateScaledCursor(HCURSOR hSrcCursor, float scale) { + if (!hSrcCursor) return NULL; + ICONINFO iconInfo; + if (!GetIconInfo(hSrcCursor, &iconInfo)) return NULL; + + BITMAP bmColor; + GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor); + + int newWidth = (int)(bmColor.bmWidth * scale); + int newHeight = (int)(bmColor.bmHeight * scale); + + HDC hdc = GetDC(NULL); + HDC hdcSrc = CreateCompatibleDC(hdc); + HDC hdcDst = CreateCompatibleDC(hdc); + + HBITMAP hbmColorNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); + SelectObject(hdcSrc, iconInfo.hbmColor); + SelectObject(hdcDst, hbmColorNew); + StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); + + HBITMAP hbmMaskNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); + SelectObject(hdcSrc, iconInfo.hbmMask); + SelectObject(hdcDst, hbmMaskNew); + StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); + + DeleteDC(hdcSrc); + DeleteDC(hdcDst); + ReleaseDC(NULL, hdc); + + ICONINFO newIconInfo = iconInfo; + newIconInfo.fIcon = FALSE; + newIconInfo.xHotspot = (DWORD)(iconInfo.xHotspot * scale); + newIconInfo.yHotspot = (DWORD)(iconInfo.yHotspot * scale); + newIconInfo.hbmMask = hbmMaskNew; + newIconInfo.hbmColor = hbmColorNew; + + HCURSOR hNewCursor = CreateIconIndirect(&newIconInfo); + + DeleteObject(hbmMaskNew); + DeleteObject(hbmColorNew); + DeleteObject(iconInfo.hbmMask); + DeleteObject(iconInfo.hbmColor); + + return hNewCursor; +} + +// ─── Cursor restore ───────────────────────────────────────────────────────── + +void RestoreCursor() { + if (g_isEnlarged) { + SystemParametersInfo(SPI_SETCURSORS, 0, NULL, SPIF_SENDCHANGE); + g_isEnlarged = false; + } +} + +VOID CALLBACK ResetTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + KillTimer(NULL, g_nResetTimerId); + g_nResetTimerId = 0; + RestoreCursor(); +} + +// ─── Shake detection + trigger ────────────────────────────────────────────── + +void ProcessMouseTelemetry(POINT pt) { + DWORD time = GetTickCount(); + MouseSample sample = { pt, time }; + g_history.push_back(sample); + + if (g_history.size() > kHistorySize) { + g_history.erase(g_history.begin()); + } + + if (g_history.size() < 4) return; + + int dirChangesX = 0, dirChangesY = 0; + int lastDirX = 0, lastDirY = 0; + float totalDistance = 0.0f; + + for (size_t i = 1; i < g_history.size(); ++i) { + int dx = g_history[i].pt.x - g_history[i - 1].pt.x; + int dy = g_history[i].pt.y - g_history[i - 1].pt.y; + totalDistance += sqrt(float(dx * dx + dy * dy)); + + int dirX = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0); + int dirY = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0); + + if (dirX != 0) { + if (lastDirX != 0 && dirX != lastDirX) dirChangesX++; + lastDirX = dirX; + } + if (dirY != 0) { + if (lastDirY != 0 && dirY != lastDirY) dirChangesY++; + lastDirY = dirY; + } + } + + DWORD timeDelta = g_history.back().time - g_history.front().time; + if (timeDelta == 0 || timeDelta > (DWORD)kMaxTimeWindow) return; + + float speed = (totalDistance / (float)timeDelta) * 1000.0f; + + if (speed > g_cfg.minMovementSpeed && + (dirChangesX >= g_cfg.minDirectionChanges || dirChangesY >= g_cfg.minDirectionChanges)) { + + if (!g_isEnlarged) { + g_hNormalCursor = LoadCursor(NULL, IDC_ARROW); + g_hEnlargedCursor = CreateScaledCursor(g_hNormalCursor, (float)g_cfg.scaleFactor); + + if (g_hEnlargedCursor) { + SetSystemCursor(CopyCursor(g_hEnlargedCursor), 32512); // OCR_NORMAL + g_isEnlarged = true; + } + } + + if (g_nResetTimerId) KillTimer(NULL, g_nResetTimerId); + g_nResetTimerId = SetTimer(NULL, 0, g_cfg.enlargeDurationMs, ResetTimerProc); + } +} + +// ─── Polling timer ────────────────────────────────────────────────────────── + +VOID CALLBACK PollingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + CURSORINFO ci = { sizeof(CURSORINFO) }; + if (GetCursorInfo(&ci) && (ci.flags & CURSOR_SHOWING)) { + ProcessMouseTelemetry(ci.ptScreenPos); + } +} + +// ─── Windhawk entry points ────────────────────────────────────────────────── + +BOOL Wh_ModInit(void) { + LoadSettings(); + g_nPollingTimerId = SetTimer(NULL, 0, 16, PollingTimerProc); + return (g_nPollingTimerId != 0); +} + +void Wh_ModUninit(void) { + if (g_nPollingTimerId) { + KillTimer(NULL, g_nPollingTimerId); + } + if (g_nResetTimerId) { + KillTimer(NULL, g_nResetTimerId); + } + RestoreCursor(); +} + +void Wh_ModSettingsChanged(void) { + LoadSettings(); +} From e1c1a295204e48b7c1dafc970b0cebe8ad5f4fc5 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:31:40 +0600 Subject: [PATCH 09/17] Delete mods/mods/README.md --- mods/mods/README.md | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 mods/mods/README.md diff --git a/mods/mods/README.md b/mods/mods/README.md deleted file mode 100644 index 8c2a94d61b..0000000000 --- a/mods/mods/README.md +++ /dev/null @@ -1,19 +0,0 @@ - -# Shake to Find Cursor - -Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! - -When you rapidly shake your mouse back and forth, the cursor temporarily -grows larger to help you spot it on screen. Once you stop shaking, it -smoothly animates back to its normal size. - -## How to Use -1. Shake your mouse rapidly left-right (or up-down) -2. The cursor enlarges so you can find it easily -3. Stop moving and it shrinks back to normal -4. Restart explorer if needed - -## Settings -- *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) -- *Enlarge duration* — how long the cursor stays big after shaking stops (ms) -- *Shake sensitivity* — minimum direction changes needed to trigger From a267cbe871fe9ff1f7524b99da43150a5a5019c0 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:32:37 +0600 Subject: [PATCH 10/17] Delete mods/mods/11macos-shake-to-find-cursor.wh.cpp accidental --- mods/mods/11macos-shake-to-find-cursor.wh.cpp | 253 ------------------ 1 file changed, 253 deletions(-) delete mode 100644 mods/mods/11macos-shake-to-find-cursor.wh.cpp diff --git a/mods/mods/11macos-shake-to-find-cursor.wh.cpp b/mods/mods/11macos-shake-to-find-cursor.wh.cpp deleted file mode 100644 index 3e20c371e9..0000000000 --- a/mods/mods/11macos-shake-to-find-cursor.wh.cpp +++ /dev/null @@ -1,253 +0,0 @@ -// ==WindhawkMod== -// @id 11macos-shake-to-find-cursor -// @name 11macOS Shake to Find Cursor -// @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. -// @version 0.5 -// @author samiulislam16 -// @github https://github.com/samiulislam16 -// @include * -// @compilerOptions -luser32 -lgdi32 -lshcore -// @license MIT -// ==/WindhawkMod== - -// ==WindhawkModReadme== -/* -# Shake to Find Cursor - -Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! - -When you rapidly shake your mouse back and forth, the cursor temporarily -grows larger to help you spot it on screen. Once you stop shaking, it -smoothly animates back to its normal size. - -## How to Use -1. Shake your mouse rapidly left-right (or up-down) -2. The cursor enlarges so you can find it easily -3. Stop moving and it shrinks back to normal - -## Settings -- *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) -- *Enlarge duration* — how long the cursor stays big after shaking stops (ms) -- *Shake sensitivity* — minimum direction changes needed to trigger -*/ -// ==/WindhawkModReadme== - -// ==WindhawkModSettings== -/* -- cursorScale: 350 - $name: Cursor scale (%) - $description: How large the cursor grows. 200 = 2×, 350 = 3.5×, 500 = 5×. -- enlargeDuration: 500 - $name: Enlarge duration (ms) - $description: How long the cursor stays enlarged after you stop shaking. -- shakeSensitivity: 4 - $name: Shake sensitivity (direction changes) - $description: Minimum direction reversals needed to trigger. Lower = easier to trigger. -- minSpeed: 550 - $name: Minimum movement speed (pixels/sec) - $description: Average speed threshold for shake detection. Lower = easier to trigger. -*/ -// ==/WindhawkModSettings== - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -// ─── Runtime settings (loaded from Windhawk UI) ───────────────────────────── - -struct ModSettings { - double scaleFactor; - int enlargeDurationMs; - int minDirectionChanges; - double minMovementSpeed; -}; - -static ModSettings g_cfg; - -static void LoadSettings() { - int scale = Wh_GetIntSetting(L"cursorScale"); - if (scale <= 100) scale = 350; - g_cfg.scaleFactor = scale / 100.0; - - g_cfg.enlargeDurationMs = Wh_GetIntSetting(L"enlargeDuration"); - if (g_cfg.enlargeDurationMs <= 0) g_cfg.enlargeDurationMs = 500; - - g_cfg.minDirectionChanges = Wh_GetIntSetting(L"shakeSensitivity"); - if (g_cfg.minDirectionChanges <= 0) g_cfg.minDirectionChanges = 4; - - int speed = Wh_GetIntSetting(L"minSpeed"); - if (speed <= 0) speed = 550; - g_cfg.minMovementSpeed = (double)speed; -} - -// ─── Constants (non-configurable) ─────────────────────────────────────────── - -static constexpr size_t kHistorySize = 10; -static constexpr int kMaxTimeWindow = 400; - -struct MouseSample { - POINT pt; - DWORD time; -}; - -// ─── Global state ─────────────────────────────────────────────────────────── - -std::vector g_history; -bool g_isEnlarged = false; -HCURSOR g_hNormalCursor = NULL; -HCURSOR g_hEnlargedCursor = NULL; -UINT_PTR g_nResetTimerId = 0; -UINT_PTR g_nPollingTimerId = 0; - -// ─── Cursor scaling ───────────────────────────────────────────────────────── - -HCURSOR CreateScaledCursor(HCURSOR hSrcCursor, float scale) { - if (!hSrcCursor) return NULL; - ICONINFO iconInfo; - if (!GetIconInfo(hSrcCursor, &iconInfo)) return NULL; - - BITMAP bmColor; - GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor); - - int newWidth = (int)(bmColor.bmWidth * scale); - int newHeight = (int)(bmColor.bmHeight * scale); - - HDC hdc = GetDC(NULL); - HDC hdcSrc = CreateCompatibleDC(hdc); - HDC hdcDst = CreateCompatibleDC(hdc); - - HBITMAP hbmColorNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); - SelectObject(hdcSrc, iconInfo.hbmColor); - SelectObject(hdcDst, hbmColorNew); - StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); - - HBITMAP hbmMaskNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); - SelectObject(hdcSrc, iconInfo.hbmMask); - SelectObject(hdcDst, hbmMaskNew); - StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); - - DeleteDC(hdcSrc); - DeleteDC(hdcDst); - ReleaseDC(NULL, hdc); - - ICONINFO newIconInfo = iconInfo; - newIconInfo.fIcon = FALSE; - newIconInfo.xHotspot = (DWORD)(iconInfo.xHotspot * scale); - newIconInfo.yHotspot = (DWORD)(iconInfo.yHotspot * scale); - newIconInfo.hbmMask = hbmMaskNew; - newIconInfo.hbmColor = hbmColorNew; - - HCURSOR hNewCursor = CreateIconIndirect(&newIconInfo); - - DeleteObject(hbmMaskNew); - DeleteObject(hbmColorNew); - DeleteObject(iconInfo.hbmMask); - DeleteObject(iconInfo.hbmColor); - - return hNewCursor; -} - -// ─── Cursor restore ───────────────────────────────────────────────────────── - -void RestoreCursor() { - if (g_isEnlarged) { - SystemParametersInfo(SPI_SETCURSORS, 0, NULL, SPIF_SENDCHANGE); - g_isEnlarged = false; - } -} - -VOID CALLBACK ResetTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - KillTimer(NULL, g_nResetTimerId); - g_nResetTimerId = 0; - RestoreCursor(); -} - -// ─── Shake detection + trigger ────────────────────────────────────────────── - -void ProcessMouseTelemetry(POINT pt) { - DWORD time = GetTickCount(); - MouseSample sample = { pt, time }; - g_history.push_back(sample); - - if (g_history.size() > kHistorySize) { - g_history.erase(g_history.begin()); - } - - if (g_history.size() < 4) return; - - int dirChangesX = 0, dirChangesY = 0; - int lastDirX = 0, lastDirY = 0; - float totalDistance = 0.0f; - - for (size_t i = 1; i < g_history.size(); ++i) { - int dx = g_history[i].pt.x - g_history[i - 1].pt.x; - int dy = g_history[i].pt.y - g_history[i - 1].pt.y; - totalDistance += sqrt(float(dx * dx + dy * dy)); - - int dirX = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0); - int dirY = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0); - - if (dirX != 0) { - if (lastDirX != 0 && dirX != lastDirX) dirChangesX++; - lastDirX = dirX; - } - if (dirY != 0) { - if (lastDirY != 0 && dirY != lastDirY) dirChangesY++; - lastDirY = dirY; - } - } - - DWORD timeDelta = g_history.back().time - g_history.front().time; - if (timeDelta == 0 || timeDelta > (DWORD)kMaxTimeWindow) return; - - float speed = (totalDistance / (float)timeDelta) * 1000.0f; - - if (speed > g_cfg.minMovementSpeed && - (dirChangesX >= g_cfg.minDirectionChanges || dirChangesY >= g_cfg.minDirectionChanges)) { - - if (!g_isEnlarged) { - g_hNormalCursor = LoadCursor(NULL, IDC_ARROW); - g_hEnlargedCursor = CreateScaledCursor(g_hNormalCursor, (float)g_cfg.scaleFactor); - - if (g_hEnlargedCursor) { - SetSystemCursor(CopyCursor(g_hEnlargedCursor), 32512); // OCR_NORMAL - g_isEnlarged = true; - } - } - - if (g_nResetTimerId) KillTimer(NULL, g_nResetTimerId); - g_nResetTimerId = SetTimer(NULL, 0, g_cfg.enlargeDurationMs, ResetTimerProc); - } -} - -// ─── Polling timer ────────────────────────────────────────────────────────── - -VOID CALLBACK PollingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - CURSORINFO ci = { sizeof(CURSORINFO) }; - if (GetCursorInfo(&ci) && (ci.flags & CURSOR_SHOWING)) { - ProcessMouseTelemetry(ci.ptScreenPos); - } -} - -// ─── Windhawk entry points ────────────────────────────────────────────────── - -BOOL Wh_ModInit(void) { - LoadSettings(); - g_nPollingTimerId = SetTimer(NULL, 0, 16, PollingTimerProc); - return (g_nPollingTimerId != 0); -} - -void Wh_ModUninit(void) { - if (g_nPollingTimerId) { - KillTimer(NULL, g_nPollingTimerId); - } - if (g_nResetTimerId) { - KillTimer(NULL, g_nResetTimerId); - } - RestoreCursor(); -} - -void Wh_ModSettingsChanged(void) { - LoadSettings(); -} From b9a763d40c0f151229b9cce5a1c2f765514d5e97 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:39:45 +0600 Subject: [PATCH 11/17] Update macos-shake-to-find-cursor.wh.cpp updated accidental mistakes --- mods/macos-shake-to-find-cursor.wh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/macos-shake-to-find-cursor.wh.cpp b/mods/macos-shake-to-find-cursor.wh.cpp index 1072ede7c5..5b650055f4 100644 --- a/mods/macos-shake-to-find-cursor.wh.cpp +++ b/mods/macos-shake-to-find-cursor.wh.cpp @@ -1,6 +1,6 @@ // ==WindhawkMod== -// @id 11macos-shake-to-find-cursor -// @name 11macOS Shake to Find Cursor +// @id macos-shake-to-find-cursor +// @name macOS Shake to Find Cursor // @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. // @version 0.5 // @author samiulislam16 From 373bfb0aa33cfa47154cb1f07e629733b5a6b4d2 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:40:26 +0600 Subject: [PATCH 12/17] Update and rename 11macos-shake-to-find-cursor.wh.cpp to mac-os-shake-to-find-cursor.wh.cpp --- ...-find-cursor.wh.cpp => mac-os-shake-to-find-cursor.wh.cpp} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename mods/{11macos-shake-to-find-cursor.wh.cpp => mac-os-shake-to-find-cursor.wh.cpp} (98%) diff --git a/mods/11macos-shake-to-find-cursor.wh.cpp b/mods/mac-os-shake-to-find-cursor.wh.cpp similarity index 98% rename from mods/11macos-shake-to-find-cursor.wh.cpp rename to mods/mac-os-shake-to-find-cursor.wh.cpp index 1072ede7c5..5b650055f4 100644 --- a/mods/11macos-shake-to-find-cursor.wh.cpp +++ b/mods/mac-os-shake-to-find-cursor.wh.cpp @@ -1,6 +1,6 @@ // ==WindhawkMod== -// @id 11macos-shake-to-find-cursor -// @name 11macOS Shake to Find Cursor +// @id macos-shake-to-find-cursor +// @name macOS Shake to Find Cursor // @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. // @version 0.5 // @author samiulislam16 From c876ee45b3f2ee6436e2516977902996b009de41 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:56:00 +0600 Subject: [PATCH 13/17] Delete mods/mac-os-shake-to-find-cursor.wh.cpp --- mods/mac-os-shake-to-find-cursor.wh.cpp | 254 ------------------------ 1 file changed, 254 deletions(-) delete mode 100644 mods/mac-os-shake-to-find-cursor.wh.cpp diff --git a/mods/mac-os-shake-to-find-cursor.wh.cpp b/mods/mac-os-shake-to-find-cursor.wh.cpp deleted file mode 100644 index 5b650055f4..0000000000 --- a/mods/mac-os-shake-to-find-cursor.wh.cpp +++ /dev/null @@ -1,254 +0,0 @@ -// ==WindhawkMod== -// @id macos-shake-to-find-cursor -// @name macOS Shake to Find Cursor -// @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. -// @version 0.5 -// @author samiulislam16 -// @github https://github.com/samiulislam16 -// @include * -// @compilerOptions -luser32 -lgdi32 -lshcore -// @license MIT -// ==/WindhawkMod== - -// ==WindhawkModReadme== -/* -# Shake to Find Cursor - -Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! - -When you rapidly shake your mouse back and forth, the cursor temporarily -grows larger to help you spot it on screen. Once you stop shaking, it -smoothly animates back to its normal size. - -## How to Use -1. Shake your mouse rapidly left-right (or up-down) -2. The cursor enlarges so you can find it easily -3. Stop moving and it shrinks back to normal -4. Restart explorer if needed - -## Settings -- *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) -- *Enlarge duration* — how long the cursor stays big after shaking stops (ms) -- *Shake sensitivity* — minimum direction changes needed to trigger -*/ -// ==/WindhawkModReadme== - -// ==WindhawkModSettings== -/* -- cursorScale: 350 - $name: Cursor scale (%) - $description: How large the cursor grows. 200 = 2×, 350 = 3.5×, 500 = 5×. -- enlargeDuration: 500 - $name: Enlarge duration (ms) - $description: How long the cursor stays enlarged after you stop shaking. -- shakeSensitivity: 4 - $name: Shake sensitivity (direction changes) - $description: Minimum direction reversals needed to trigger. Lower = easier to trigger. -- minSpeed: 550 - $name: Minimum movement speed (pixels/sec) - $description: Average speed threshold for shake detection. Lower = easier to trigger. -*/ -// ==/WindhawkModSettings== - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -// ─── Runtime settings (loaded from Windhawk UI) ───────────────────────────── - -struct ModSettings { - double scaleFactor; - int enlargeDurationMs; - int minDirectionChanges; - double minMovementSpeed; -}; - -static ModSettings g_cfg; - -static void LoadSettings() { - int scale = Wh_GetIntSetting(L"cursorScale"); - if (scale <= 100) scale = 350; - g_cfg.scaleFactor = scale / 100.0; - - g_cfg.enlargeDurationMs = Wh_GetIntSetting(L"enlargeDuration"); - if (g_cfg.enlargeDurationMs <= 0) g_cfg.enlargeDurationMs = 500; - - g_cfg.minDirectionChanges = Wh_GetIntSetting(L"shakeSensitivity"); - if (g_cfg.minDirectionChanges <= 0) g_cfg.minDirectionChanges = 4; - - int speed = Wh_GetIntSetting(L"minSpeed"); - if (speed <= 0) speed = 550; - g_cfg.minMovementSpeed = (double)speed; -} - -// ─── Constants (non-configurable) ─────────────────────────────────────────── - -static constexpr size_t kHistorySize = 10; -static constexpr int kMaxTimeWindow = 400; - -struct MouseSample { - POINT pt; - DWORD time; -}; - -// ─── Global state ─────────────────────────────────────────────────────────── - -std::vector g_history; -bool g_isEnlarged = false; -HCURSOR g_hNormalCursor = NULL; -HCURSOR g_hEnlargedCursor = NULL; -UINT_PTR g_nResetTimerId = 0; -UINT_PTR g_nPollingTimerId = 0; - -// ─── Cursor scaling ───────────────────────────────────────────────────────── - -HCURSOR CreateScaledCursor(HCURSOR hSrcCursor, float scale) { - if (!hSrcCursor) return NULL; - ICONINFO iconInfo; - if (!GetIconInfo(hSrcCursor, &iconInfo)) return NULL; - - BITMAP bmColor; - GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor); - - int newWidth = (int)(bmColor.bmWidth * scale); - int newHeight = (int)(bmColor.bmHeight * scale); - - HDC hdc = GetDC(NULL); - HDC hdcSrc = CreateCompatibleDC(hdc); - HDC hdcDst = CreateCompatibleDC(hdc); - - HBITMAP hbmColorNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); - SelectObject(hdcSrc, iconInfo.hbmColor); - SelectObject(hdcDst, hbmColorNew); - StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); - - HBITMAP hbmMaskNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); - SelectObject(hdcSrc, iconInfo.hbmMask); - SelectObject(hdcDst, hbmMaskNew); - StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); - - DeleteDC(hdcSrc); - DeleteDC(hdcDst); - ReleaseDC(NULL, hdc); - - ICONINFO newIconInfo = iconInfo; - newIconInfo.fIcon = FALSE; - newIconInfo.xHotspot = (DWORD)(iconInfo.xHotspot * scale); - newIconInfo.yHotspot = (DWORD)(iconInfo.yHotspot * scale); - newIconInfo.hbmMask = hbmMaskNew; - newIconInfo.hbmColor = hbmColorNew; - - HCURSOR hNewCursor = CreateIconIndirect(&newIconInfo); - - DeleteObject(hbmMaskNew); - DeleteObject(hbmColorNew); - DeleteObject(iconInfo.hbmMask); - DeleteObject(iconInfo.hbmColor); - - return hNewCursor; -} - -// ─── Cursor restore ───────────────────────────────────────────────────────── - -void RestoreCursor() { - if (g_isEnlarged) { - SystemParametersInfo(SPI_SETCURSORS, 0, NULL, SPIF_SENDCHANGE); - g_isEnlarged = false; - } -} - -VOID CALLBACK ResetTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - KillTimer(NULL, g_nResetTimerId); - g_nResetTimerId = 0; - RestoreCursor(); -} - -// ─── Shake detection + trigger ────────────────────────────────────────────── - -void ProcessMouseTelemetry(POINT pt) { - DWORD time = GetTickCount(); - MouseSample sample = { pt, time }; - g_history.push_back(sample); - - if (g_history.size() > kHistorySize) { - g_history.erase(g_history.begin()); - } - - if (g_history.size() < 4) return; - - int dirChangesX = 0, dirChangesY = 0; - int lastDirX = 0, lastDirY = 0; - float totalDistance = 0.0f; - - for (size_t i = 1; i < g_history.size(); ++i) { - int dx = g_history[i].pt.x - g_history[i - 1].pt.x; - int dy = g_history[i].pt.y - g_history[i - 1].pt.y; - totalDistance += sqrt(float(dx * dx + dy * dy)); - - int dirX = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0); - int dirY = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0); - - if (dirX != 0) { - if (lastDirX != 0 && dirX != lastDirX) dirChangesX++; - lastDirX = dirX; - } - if (dirY != 0) { - if (lastDirY != 0 && dirY != lastDirY) dirChangesY++; - lastDirY = dirY; - } - } - - DWORD timeDelta = g_history.back().time - g_history.front().time; - if (timeDelta == 0 || timeDelta > (DWORD)kMaxTimeWindow) return; - - float speed = (totalDistance / (float)timeDelta) * 1000.0f; - - if (speed > g_cfg.minMovementSpeed && - (dirChangesX >= g_cfg.minDirectionChanges || dirChangesY >= g_cfg.minDirectionChanges)) { - - if (!g_isEnlarged) { - g_hNormalCursor = LoadCursor(NULL, IDC_ARROW); - g_hEnlargedCursor = CreateScaledCursor(g_hNormalCursor, (float)g_cfg.scaleFactor); - - if (g_hEnlargedCursor) { - SetSystemCursor(CopyCursor(g_hEnlargedCursor), 32512); // OCR_NORMAL - g_isEnlarged = true; - } - } - - if (g_nResetTimerId) KillTimer(NULL, g_nResetTimerId); - g_nResetTimerId = SetTimer(NULL, 0, g_cfg.enlargeDurationMs, ResetTimerProc); - } -} - -// ─── Polling timer ────────────────────────────────────────────────────────── - -VOID CALLBACK PollingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - CURSORINFO ci = { sizeof(CURSORINFO) }; - if (GetCursorInfo(&ci) && (ci.flags & CURSOR_SHOWING)) { - ProcessMouseTelemetry(ci.ptScreenPos); - } -} - -// ─── Windhawk entry points ────────────────────────────────────────────────── - -BOOL Wh_ModInit(void) { - LoadSettings(); - g_nPollingTimerId = SetTimer(NULL, 0, 16, PollingTimerProc); - return (g_nPollingTimerId != 0); -} - -void Wh_ModUninit(void) { - if (g_nPollingTimerId) { - KillTimer(NULL, g_nPollingTimerId); - } - if (g_nResetTimerId) { - KillTimer(NULL, g_nResetTimerId); - } - RestoreCursor(); -} - -void Wh_ModSettingsChanged(void) { - LoadSettings(); -} From a637a443e57b0d175de09525e1f880384cd2ed4e Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:57:35 +0600 Subject: [PATCH 14/17] Update macos-shake-to-find-cursor.wh.cpp updated mistakes --- mods/macos-shake-to-find-cursor.wh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/macos-shake-to-find-cursor.wh.cpp b/mods/macos-shake-to-find-cursor.wh.cpp index 5b650055f4..0d1b4eef3e 100644 --- a/mods/macos-shake-to-find-cursor.wh.cpp +++ b/mods/macos-shake-to-find-cursor.wh.cpp @@ -1,6 +1,6 @@ // ==WindhawkMod== // @id macos-shake-to-find-cursor -// @name macOS Shake to Find Cursor +// @name 11macOS Shake to Find Cursor // @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. // @version 0.5 // @author samiulislam16 From 7f1d845c090c6fcdb75001a93789d8b1ad586d8e Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 04:55:30 +0600 Subject: [PATCH 15/17] Update macos-shake-to-find-cursor.wh.cpp Refactor to use explorer.exe thread polling to fix global message loops --- mods/macos-shake-to-find-cursor.wh.cpp | 99 ++++++++++++-------------- 1 file changed, 44 insertions(+), 55 deletions(-) diff --git a/mods/macos-shake-to-find-cursor.wh.cpp b/mods/macos-shake-to-find-cursor.wh.cpp index 0d1b4eef3e..4f9550a84f 100644 --- a/mods/macos-shake-to-find-cursor.wh.cpp +++ b/mods/macos-shake-to-find-cursor.wh.cpp @@ -2,10 +2,10 @@ // @id macos-shake-to-find-cursor // @name 11macOS Shake to Find Cursor // @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. -// @version 0.5 +// @version 1.0.0 // @author samiulislam16 // @github https://github.com/samiulislam16 -// @include * +// @include explorer.exe // @compilerOptions -luser32 -lgdi32 -lshcore // @license MIT // ==/WindhawkMod== @@ -20,12 +20,6 @@ When you rapidly shake your mouse back and forth, the cursor temporarily grows larger to help you spot it on screen. Once you stop shaking, it smoothly animates back to its normal size. -## How to Use -1. Shake your mouse rapidly left-right (or up-down) -2. The cursor enlarges so you can find it easily -3. Stop moving and it shrinks back to normal -4. Restart explorer if needed - ## Settings - *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) - *Enlarge duration* — how long the cursor stays big after shaking stops (ms) @@ -55,8 +49,6 @@ smoothly animates back to its normal size. #include #include -// ─── Runtime settings (loaded from Windhawk UI) ───────────────────────────── - struct ModSettings { double scaleFactor; int enlargeDurationMs; @@ -82,8 +74,6 @@ static void LoadSettings() { g_cfg.minMovementSpeed = (double)speed; } -// ─── Constants (non-configurable) ─────────────────────────────────────────── - static constexpr size_t kHistorySize = 10; static constexpr int kMaxTimeWindow = 400; @@ -92,16 +82,11 @@ struct MouseSample { DWORD time; }; -// ─── Global state ─────────────────────────────────────────────────────────── - std::vector g_history; bool g_isEnlarged = false; -HCURSOR g_hNormalCursor = NULL; -HCURSOR g_hEnlargedCursor = NULL; -UINT_PTR g_nResetTimerId = 0; -UINT_PTR g_nPollingTimerId = 0; - -// ─── Cursor scaling ───────────────────────────────────────────────────────── +DWORD g_lastShakeTime = 0; +HANDLE g_hThread = NULL; +bool g_runThread = false; HCURSOR CreateScaledCursor(HCURSOR hSrcCursor, float scale) { if (!hSrcCursor) return NULL; @@ -119,8 +104,8 @@ HCURSOR CreateScaledCursor(HCURSOR hSrcCursor, float scale) { HDC hdcDst = CreateCompatibleDC(hdc); HBITMAP hbmColorNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); - SelectObject(hdcSrc, iconInfo.hbmColor); - SelectObject(hdcDst, hbmColorNew); + HGDIOBJ hOldSrc = SelectObject(hdcSrc, iconInfo.hbmColor); + HGDIOBJ hOldDst = SelectObject(hdcDst, hbmColorNew); StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); HBITMAP hbmMaskNew = CreateCompatibleBitmap(hdc, newWidth, newHeight); @@ -128,6 +113,8 @@ HCURSOR CreateScaledCursor(HCURSOR hSrcCursor, float scale) { SelectObject(hdcDst, hbmMaskNew); StretchBlt(hdcDst, 0, 0, newWidth, newHeight, hdcSrc, 0, 0, bmColor.bmWidth, bmColor.bmHeight, SRCCOPY); + SelectObject(hdcSrc, hOldSrc); + SelectObject(hdcDst, hOldDst); DeleteDC(hdcSrc); DeleteDC(hdcDst); ReleaseDC(NULL, hdc); @@ -149,8 +136,6 @@ HCURSOR CreateScaledCursor(HCURSOR hSrcCursor, float scale) { return hNewCursor; } -// ─── Cursor restore ───────────────────────────────────────────────────────── - void RestoreCursor() { if (g_isEnlarged) { SystemParametersInfo(SPI_SETCURSORS, 0, NULL, SPIF_SENDCHANGE); @@ -158,14 +143,6 @@ void RestoreCursor() { } } -VOID CALLBACK ResetTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - KillTimer(NULL, g_nResetTimerId); - g_nResetTimerId = 0; - RestoreCursor(); -} - -// ─── Shake detection + trigger ────────────────────────────────────────────── - void ProcessMouseTelemetry(POINT pt) { DWORD time = GetTickCount(); MouseSample sample = { pt, time }; @@ -184,7 +161,7 @@ void ProcessMouseTelemetry(POINT pt) { for (size_t i = 1; i < g_history.size(); ++i) { int dx = g_history[i].pt.x - g_history[i - 1].pt.x; int dy = g_history[i].pt.y - g_history[i - 1].pt.y; - totalDistance += sqrt(float(dx * dx + dy * dy)); + totalDistance += std::sqrt((float)(dx * dx + dy * dy)); int dirX = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0); int dirY = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0); @@ -207,44 +184,56 @@ void ProcessMouseTelemetry(POINT pt) { if (speed > g_cfg.minMovementSpeed && (dirChangesX >= g_cfg.minDirectionChanges || dirChangesY >= g_cfg.minDirectionChanges)) { + g_lastShakeTime = time; + if (!g_isEnlarged) { - g_hNormalCursor = LoadCursor(NULL, IDC_ARROW); - g_hEnlargedCursor = CreateScaledCursor(g_hNormalCursor, (float)g_cfg.scaleFactor); + HCURSOR hNormalCursor = LoadCursor(NULL, IDC_ARROW); + HCURSOR hEnlargedCursor = CreateScaledCursor(hNormalCursor, (float)g_cfg.scaleFactor); - if (g_hEnlargedCursor) { - SetSystemCursor(CopyCursor(g_hEnlargedCursor), 32512); // OCR_NORMAL + if (hEnlargedCursor) { + SetSystemCursor(hEnlargedCursor, 32512); // 32512 = OCR_NORMAL g_isEnlarged = true; } } - - if (g_nResetTimerId) KillTimer(NULL, g_nResetTimerId); - g_nResetTimerId = SetTimer(NULL, 0, g_cfg.enlargeDurationMs, ResetTimerProc); + } else { + if (g_isEnlarged && (time - g_lastShakeTime > (DWORD)g_cfg.enlargeDurationMs)) { + RestoreCursor(); + } } } -// ─── Polling timer ────────────────────────────────────────────────────────── - -VOID CALLBACK PollingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - CURSORINFO ci = { sizeof(CURSORINFO) }; - if (GetCursorInfo(&ci) && (ci.flags & CURSOR_SHOWING)) { - ProcessMouseTelemetry(ci.ptScreenPos); +DWORD WINAPI HardwarePollingThread(LPVOID lpParam) { + while (g_runThread) { + POINT pt; + if (GetPhysicalCursorPos(&pt)) { + ProcessMouseTelemetry(pt); + } + Sleep(16); // 16ms sleep corresponds to ~60Hz polling } + return 0; } -// ─── Windhawk entry points ────────────────────────────────────────────────── - BOOL Wh_ModInit(void) { LoadSettings(); - g_nPollingTimerId = SetTimer(NULL, 0, 16, PollingTimerProc); - return (g_nPollingTimerId != 0); + + // Strict isolation enforcement constraint layout paths + wchar_t processPath[MAX_PATH]; + GetModuleFileNameW(NULL, processPath, MAX_PATH); + if (wcsstr(processPath, L"explorer.exe") == nullptr) { + return TRUE; + } + + g_runThread = true; + g_hThread = CreateThread(NULL, 0, HardwarePollingThread, NULL, 0, NULL); + return (g_hThread != NULL); } void Wh_ModUninit(void) { - if (g_nPollingTimerId) { - KillTimer(NULL, g_nPollingTimerId); - } - if (g_nResetTimerId) { - KillTimer(NULL, g_nResetTimerId); + g_runThread = false; + if (g_hThread) { + WaitForSingleObject(g_hThread, 500); + CloseHandle(g_hThread); + g_hThread = NULL; } RestoreCursor(); } From 45e1d215a042094f0978cc3e3463e2c1d959e27f Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 20:25:41 +0600 Subject: [PATCH 16/17] Update macos-shake-to-find-cursor.wh.cpp --- mods/macos-shake-to-find-cursor.wh.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/macos-shake-to-find-cursor.wh.cpp b/mods/macos-shake-to-find-cursor.wh.cpp index 4f9550a84f..58b6d596eb 100644 --- a/mods/macos-shake-to-find-cursor.wh.cpp +++ b/mods/macos-shake-to-find-cursor.wh.cpp @@ -1,8 +1,8 @@ // ==WindhawkMod== // @id macos-shake-to-find-cursor -// @name 11macOS Shake to Find Cursor +// @name macOS Shake to Find Cursor // @description Smoothly enlarges the mouse cursor when shaken back and forth system-wide. -// @version 1.0.0 +// @version 1.0.1 // @author samiulislam16 // @github https://github.com/samiulislam16 // @include explorer.exe @@ -15,10 +15,10 @@ # Shake to Find Cursor Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! - +https://raw.githubusercontent.com/samiulislam16/windhawk-mods/refs/heads/main/mods/mods/Recording%202026-07-07%20201826.gif When you rapidly shake your mouse back and forth, the cursor temporarily grows larger to help you spot it on screen. Once you stop shaking, it -smoothly animates back to its normal size. +smoothly animates back to its normal size. Restart explorer if needed ## Settings - *Cursor scale* — how large the cursor grows (e.g. 350 = 3.5×) From d430982448cf4ee7891f12b6fc66432b0b937d62 Mon Sep 17 00:00:00 2001 From: samiulislam16 <88020360+samiulislam16@users.noreply.github.com> Date: Tue, 7 Jul 2026 23:04:02 +0600 Subject: [PATCH 17/17] Update macos-shake-to-find-cursor.wh.cpp gif added --- mods/macos-shake-to-find-cursor.wh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/macos-shake-to-find-cursor.wh.cpp b/mods/macos-shake-to-find-cursor.wh.cpp index 58b6d596eb..2415e10c5d 100644 --- a/mods/macos-shake-to-find-cursor.wh.cpp +++ b/mods/macos-shake-to-find-cursor.wh.cpp @@ -15,7 +15,7 @@ # Shake to Find Cursor Brings the beloved macOS "Shake mouse pointer to locate" feature to Windows! -https://raw.githubusercontent.com/samiulislam16/windhawk-mods/refs/heads/main/mods/mods/Recording%202026-07-07%20201826.gif +![Preview](https://raw.githubusercontent.com/samiulislam16/windhawk-mods/refs/heads/main/mods/mods/Recording%202026-07-07%20201826.gif) When you rapidly shake your mouse back and forth, the cursor temporarily grows larger to help you spot it on screen. Once you stop shaking, it smoothly animates back to its normal size. Restart explorer if needed