A Windows Alt+Tab replacement for a specific problem: when several windows are snapped together (Snap Layouts / Snap Groups), the native switcher shows them both as a group and as individual windows. That clutters the picker instead of simplifying it, and Windows has no official setting to fix it (Microsoft Community thread).
AltTabPlus replaces the switcher entirely: a snapped group becomes one tile, with a badge for how many windows it contains.
The UI follows the Windows display language (English by default, French when the OS UI is French).
Site: lefrancoisjc.github.io/alttabplus
Windows exposes no public API for “which windows belong to the same Snap
Group” — that bookkeeping lives in the shell (twinui.pcshell.dll) with no
documented interface. The project infers groups from geometry:
Hooking/KeyboardHook.cs— a low-level keyboard hook (WH_KEYBOARD_LL) intercepts Alt+Tab so it never reaches the native switcher. Same approach as tools like AltTabTerminator or GoToWindow; there is no clean official way to disable the built-in picker.Windows/WindowEnumerator.cs— enumerates Alt-Tab-eligible windows (visible, no owner, not tool windows, not cloaked).Grouping/SnapGroupDetector.cs— groups windows by monitor, links rectangles that touch edge-to-edge, and keeps a group only if it covers enough of the monitor work area (the geometric signature of a Snap Layout rather than two windows that happen to sit next to each other).UI/SwitcherOverlayForm.cs+UI/DwmThumbnail.cs— the overlay, with live thumbnails viaDwmRegisterThumbnail(the same mechanism as taskbar previews). The DWM destination must be the top-level window: a child Panel is rejected withE_INVALIDARG.Switching/SwitchTarget.cs— one tile is either a single window or a whole group;Activate()brings every window in the group forward.
The project targets net8.0-windows (WinForms). dotnet build must run
on Windows — WinForms and the user32/dwmapi P/Invokes only work there:
dotnet build AltTabPlus.sln
or open AltTabPlus.sln in Visual Studio / Rider.
From the repo root, on Windows, with the .NET 8 SDK:
powershell -ExecutionPolicy Bypass -File scripts\build-release.ps1
powershell -ExecutionPolicy Bypass -File scripts\publish-release.ps1
publish-release.ps1 writes a self-contained 64-bit exe (runtime included)
to dist\:
dist\AltTabPlus-1.0.0-win-x64.exe
dist\AltTabPlus-1.0.0-win-x64\AltTabPlus.exe
dist\AltTabPlus-1.0.0-win-x64.zip
dist\AltTabPlus-1.0.0-win-x64.sha256
Then pack the installer (Windows SDK — makeappx + a signing cert):
powershell -ExecutionPolicy Bypass -File scripts\publish-msix.ps1
dist\AltTabPlus-1.0.0-win-x64.msix
dist\AltTabPlus-1.0.0-win-x64.cer
dist\AltTabPlus-1.0.0-win-x64-msix.zip
The MSIX zip has Install.ps1: run it as administrator. It imports the
publisher certificate and sideloads the package. Settings stay in
%LOCALAPPDATA%\AltTabPlus\settings.json (the package does not virtualize
AppData).
Options: -Version 1.0.1, -Mode framework-dependent (smaller, needs the
.NET 8 Desktop x64 runtime), -SkipZip.
For a stable package identity across releases, create a cert once
(scripts\new-msix-cert.ps1) and add GitHub Actions secrets
MSIX_PFX_BASE64 and MSIX_PFX_PASSWORD. Without them, CI signs with a
fresh self-signed cert (fine to install, not a clean in-place update).
The GitHub Actions workflow (.github/workflows/ci.yml) runs those scripts
on windows-latest for every push and PR. Zips and the MSIX show up under
Actions. A v1.2.3 tag also publishes a GitHub Release.
For debug, run Visual Studio (or dotnet run) as administrator if you
need Alt+Tab inside elevated windows (classic UIPI: a non-admin keyboard
hook does not see keys destined for an admin window).
Prefer the MSIX from the latest GitHub Release (*-msix.zip). Open
the zip and run Install.ps1 as administrator. That imports the publisher
certificate and installs the package.
The portable .exe zip is still unsigned. Windows then shows SmartScreen
or Smart App Control (“the developer could not be verified”):
- Right-click
AltTabPlus.exe→ Properties → tick Unblock → OK. Or in PowerShell:Unblock-File .\AltTabPlus.exe - If SmartScreen still appears: More info → Run anyway.
- If Smart App Control is on (Windows 11): Settings → Privacy & security → Windows Security → App & browser control → Smart App Control → Off. Then launch again.
A local dotnet run from this repo is not marked as an internet download
and should start without that prompt.
- Heuristic detection, not guaranteed. Two windows resized by hand so
they touch can be treated as a group; a Snap Group resized afterwards can
be missed. The coverage threshold (
MinWorkAreaCoverageinSnapGroupDetector.cs) is adjustable. - Settings live in
%LOCALAPPDATA%\AltTabPlus\settings.jsonand the tray / settings window. The MSIX installer sideloads a signed package; the portable zip is still an unsigned exe. - No advanced multi-desktop management beyond the current filters.
- No telemetry, no network access — everything stays local.
- Persisted settings (alternate hotkey, launch at startup, taskbar)
- DWM thumbnails for each window in a group (mini-grid in the tile)
- Detection threshold and theme in settings
- Explicit Snap Layout API if it ever becomes public, with the heuristic as fallback
- MSIX sideload installer (
scripts/publish-msix.ps1) - Unit tests for
SnapGroupDetectorwith simulated window geometry (no Win32 dependency required)
The app has no console and no error UI, so everything is traced to
%LOCALAPPDATA%\AltTabPlus\log.txt (created on first launch): hook install,
window/group counts each time the switcher opens, HRESULT from
DwmRegisterThumbnail / DwmUpdateThumbnailProperties, and each
activation attempt. If something fails, start there.
Two classic Win32 traps already handled in the code:
GetWindowRectlies slightly. It includes an invisible resize-border that Windows 10/11 adds around most windows, so two snapped windows look like they overlap instead of touching.WindowEnumeratorusesDWMWA_EXTENDED_FRAME_BOUNDSfor the real visual rect.SetForegroundWindowis ignored from a background process. Windows blocks focus stealing; a direct call from our hook often does nothing.ForegroundActivatorusesAttachThreadInput, the usual workaround for third-party Alt+Tab replacements.
PolyForm Noncommercial 1.0.0
— see LICENSE.
Personal, non-profit, and research use is allowed. Commercialization (sale, paid licensing, inclusion in a paid product, etc.) is reserved to Jean-Charles Lefrançois. Commercial use requires written permission from the copyright holder.