fix(banner): prevent focus stealing in fullscreen games with multi-layer defense#2241
Merged
Merged
Conversation
…yer defense - Remove redundant TopMost=true from constructor (already set via CreateParams) - Add WS_EX_LAYERED to CreateParams to prevent handle recreation when Opacity is changed, which would trigger a focus-stealing cycle - Handle WM_WINDOWPOSCHANGING to inject SWP_NOACTIVATE into ALL window position/z-order changes, including internal WinForms and system calls - Handle WM_ACTIVATE to always force WA_INACTIVE state - Handle WM_MOUSEACTIVATE with MA_NOACTIVATE to prevent mouse-click activation while still delivering click events - Clean up stale comment from previous PR Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com>
Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
soundswitch | a02055c | Jun 21 2026, 11:22 PM |
Copilot
AI
changed the title
[WIP] Fix banner focus issue in full-screen CS2 game
fix(banner): prevent focus stealing in fullscreen games with multi-layer defense
Jun 21, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR strengthens the non-activating behavior of BannerForm to prevent banner notifications from stealing focus (and minimizing exclusive fullscreen games), and updates documentation to reflect the intended focus-safety guarantees.
Changes:
- Adds a
WM_WINDOWPOSCHANGINGhook to injectSWP_NOACTIVATEinto all position changes. - Creates the banner window as layered from the start (
WS_EX_LAYERED) to avoid handle recreation when settingOpacity. - Adds message-level activation defenses (
WM_ACTIVATE,WM_MOUSEACTIVATE) and updates docs accordingly.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| website/src/configuration/notifications.md | Documents banner focus-safety behavior (needs wording tightened to avoid overpromising visibility in exclusive fullscreen). |
| SoundSwitch/Framework/Banner/BannerForm.cs | Implements multi-layer non-activation defenses in CreateParams and WndProc. |
| docs/banner-manager.md | Updates banner manager design table with focus-safety details (needs wording tightened to avoid overpromising visibility). |
Comment on lines
+209
to
+212
| case WM_ACTIVATE: | ||
| // Always force inactive state to prevent the banner from stealing focus | ||
| m.Result = (IntPtr)WA_INACTIVE; | ||
| return; |
Comment on lines
+195
to
+196
| const int WM_WINDOWPOSCHANGING = 0x0046; | ||
| const uint SWP_NOACTIVATE = 0x0010; |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
github-actions Bot
pushed a commit
that referenced
this pull request
Jun 21, 2026
## [7.1.1-beta.2](v7.1.1-beta.1...v7.1.1-beta.2) (2026-06-21) ### Enhancements * **tray:** reduce click delay to 250ms, add Disabled double-click option ([aa2c03b](aa2c03b)) ### Bug Fixes * **app-rules:** fallback to glob when regex pattern is invalid ([4672c6b](4672c6b)) * **banner:** prevent focus stealing and fix drag-position/NRE bugs in BannerForm ([feefcd6](feefcd6)) * **banner:** prevent focus stealing in fullscreen games with multi-layer defense ([#2241](#2241)) ([a81f169](a81f169)), closes [#2240](#2240) * build error and review feedback ([6f4ef44](6f4ef44)) * **build:** avoid CS8417 compiler bug with using var and await using in PlaySoundJob.cs ([9b7e9a9](9b7e9a9)) * clean up doc comments and add dispose idempotency ([366ecb4](366ecb4)) * **installer:** update required .NET version to 10.0.9 in installer scripts ([385819b](385819b)) * **notification:** implement mic mute sound notification and harden PlaySoundJob ([d030236](d030236)), closes [#2187](#2187) * review feedback improvements ([ddc896f](ddc896f)) * **tray-icon:** add monochrome systray icon option ([05e08e5](05e08e5)), closes [#2029](#2029) * **website:** finding-soundswitch FAQ — reopening opens settings ([#2221](#2221)) ([590b247](590b247)) ### Languages * **Chinese (Simplified Han script):** Translated Settings using Weblate ([99cb9be](99cb9be)) * **Chinese (Simplified Han script):** Translated Tray Icon using Weblate ([5cb5e90](5cb5e90)) * **French:** Translated Settings using Weblate ([d823469](d823469)) * **Hebrew:** Translated Tray Icon using Weblate ([385e059](385e059)) * **Italian:** Translated Settings using Weblate ([e8dfb91](e8dfb91)) * **Italian:** Translated Settings using Weblate ([0541491](0541491)) * **Italian:** Translated Tray Icon using Weblate ([c83eb2b](c83eb2b)) * **Japanese:** Translated Settings using Weblate ([2bfdf54](2bfdf54)) * **Japanese:** Translated Tray Icon using Weblate ([ba89f4a](ba89f4a)) * **Portuguese (Brazil):** Translated Tray Icon using Weblate ([f18b4dd](f18b4dd)) * **Spanish:** Translated Settings using Weblate ([44bbb0e](44bbb0e)) * **Spanish:** Translated Tray Icon using Weblate ([a38c28c](a38c28c)) * **Spanish:** Translated Update Download using Weblate ([906b4ac](906b4ac)) * **Swedish:** Translated Settings using Weblate ([0696a33](0696a33)) * **Swedish:** Translated Tray Icon using Weblate ([c038b30](c038b30))
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Banner notifications still minimize exclusive fullscreen games (e.g. CS2) despite PR #2156's
SWP_NOACTIVATEfix. Multiple internal WinForms code paths bypass that guard and trigger window activation.Changes
WM_WINDOWPOSCHANGINGhandler — Intercepts everySetWindowPoscall (including WinForms-internal and system-initiated) and injectsSWP_NOACTIVATEinto theWINDOWPOSstruct before it takes effectWS_EX_LAYEREDinCreateParams— Window is created layered from the start, preventing WinForms from recreating the handle whenOpacityis set (handle recreation is a known activation trigger)WM_ACTIVATE→WA_INACTIVE— Rejects any activation attempt at the message levelWM_MOUSEACTIVATE→MA_NOACTIVATE— Prevents click-activation while still delivering the click event (changed fromMA_NOACTIVATEANDEATwhich swallowed clicks)TopMost = truefrom constructor — already set viaWS_EX_TOPMOSTinCreateParams; the WinForms property setter triggered its own unguardedSetWindowPosduring handle creationCore of the fix in
WndProc:Docs
website/src/configuration/notifications.mdto document that banners never steal focus from fullscreen appsdocs/banner-manager.mddesign table with focus safety details