Inline-built dialogs were invisible to the accessibility audit - which is exactly how
mnemonic-less buttons kept slipping through (the single-instance dialog Andre caught,
and now TWO more found by this very change: ManualPeerPrompt's OK/Cancel and
ProfileSaveAsPrompt's Cancel had no mnemonics - both fixed). Each inline dialog's
construction is split from its ShowDialog into a Build seam, and the audit now covers
15 dialog surfaces (was 8): manual peer prompt, quick profile switch, change password,
password manager, profile name prompt, and the service Additional-options window join
the eight Form dialogs. Behaviour unchanged.
The encoder-boundary clamp is now ONE shared rule (Core SampleClamp) instead of three
private copies in MixingEngine / AsioCaptureBackend / PushModeWasapiBackend - and the
ASIO copy's up-to-four interlocked increments per frame became one batched add per
buffer on the RT thread. Pinned by a new self-test (over-range clamps to exactly +/-1
and counts; +/-1 exactly passes untouched).
Gate 61/61.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
UPnP close hang:
- RouterPortMapper.Stop()/Dispose() does a SYNCHRONOUS DeletePortMap call to the router
(plus StopDiscovery). When the router is slow or unresponsive that blocks — and it ran on
the UI thread in FormClosing, so enabling UPnP could make RemSound impossible to close
(Andre, this morning; his logs show UPnP teardown taking several seconds even on a good
run). Moved the router teardown into the same bounded background-task pattern already used
for the ASIO audio dispose: UPnP + audio now tear down off the UI thread, in parallel, under
one 3s cap. Anything unfinished is reclaimed on process exit, so the window always closes.
Mnemonics on dialog buttons:
- Andre flagged the "RemSound is already running" dialog (single-instance) having no shortcut
keys. Its three TaskDialog buttons had no & mnemonics; added Alt+S / Alt+F / Alt+C.
- Swept every dialog. Custom TaskDialog buttons and Form OK/Cancel/Close buttons that lacked
mnemonics now have them: single-instance (Switch/Force/Cancel), save-onto-read-only
(Save/Cancel), Add EQ band, Change/Manage profile password, Quick profile switch (Close),
Rename peer (OK), About (Close). Cancel stays on Esc in the few dialogs where Alt+C is
already taken (Rename peer's Clear, Service profile's peers list) — by design, not a miss.
- The rest already had mnemonics (Keyboard-shortcut import, Update-install notice, Profile
selection, Recording settings). The dialog-accessibility gate (mnemonic uniqueness + names)
stays green, so nothing collides.
Gate 46/46.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Freezes the v3.4 feature set (everything since the v3.3 public release):
- Fix the receiver handle leak: the 3-second device-refresh timer reopened the
configured ASIO driver every tick, and Realtek's ASIO driver leaks Event+Mutant
handles on every open. Cache the ASIO probe per driver so it is opened once.
- Realtek ASIO block: detect a Realtek ASIO driver, offer once to disable it, and
never touch it again if disabled; Options-menu toggle to reverse. Global config.
- Device hot-plug is event-driven (AudioDeviceChangeNotifier) instead of a 3s poll;
debounced refresh, falls back to polling if registration fails.
- Quick profile switch: new global hotkey opens an NVDA-friendly popup of all
profiles (current marked); Enter/click switches; plays a new "profile menu open"
cue with Preferences mute + custom-sound.
- Announce assigned global hotkeys on the controls/menu items they drive (NVDA reads
"press X anywhere"). File > Open already had Ctrl+O.
- Held-back changes folded in: config-folder migration, codec-column fix, Tailscale
endpoint network-prune, empty-password guard, and the handle-leak diagnostics
(ProcessSelfMeter, HandleTypeProbe).
Version bumped to 3.4.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>