Audio cues: per-cue default-sound picker, keyboard-click typing feedback, passkey on password fields

Cue sounds now ship as numbered variants ("connect 1.wav", "connect 2.wav", ...); the
count is never hard-coded so more can be added with no code change.

- CueSounds.cs: discovers a cue's "<base> <n>.wav" variants (case-insensitive) and
  resolves the active default: per-profile custom WAV > machine-wide chosen variant >
  first variant > silent. Wired into MainForm.TryLoadCueSound, the startup cue in
  Program.cs, and PreferencesDialog.ResolveCueFilePath.
- AppConfig: DefaultCueSounds (machine-wide cueId -> chosen filename) and
  EnableKeyboardClicks (on by default).
- Preferences: a "Choose default sound" listbox under the cue checklist - it lists the
  selected cue's variants, arrowing it previews each sound and makes it that cue's
  default. Plus a "Play keyboard clicks when typing into any edit field" checkbox.
- KeyClickService.cs: an app-wide WM_CHAR message filter + a low-latency NAudio mixer.
  Typing into any edit field plays a random key click (key 1..N.wav); password fields
  also play passkey.wav at the same instant. On/off live from the Preferences toggle.
  Inert if the sounds are missing or the device won't open; never consumes the keystroke.
- csproj: ship every sounds\*.wav via a wildcard (variants, key clicks, passkey, future
  additions) instead of stale per-file canonical names.
- Tests: resource checks (self-test + run-tests.ps1) now verify each cue has >=1 variant
  and that key 1.wav / passkey.wav are present. Accessibility audit still green with the
  new Preferences controls (Alt+D, Alt+K - no mnemonic clashes).
- Manual: variant picker, keyboard clicks, and the new sound-file naming documented.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ednunp
2026-06-13 00:06:07 +01:00
co-authored by Claude Opus 4.8
parent ad66fe5364
commit e526014e6a
11 changed files with 502 additions and 104 deletions
+10 -3
View File
@@ -44,10 +44,17 @@ if (-not (Test-Path -LiteralPath $exe)) {
# ---- 2. PACKAGE CONTENTS (must run BEFORE any CLI call: every RemSound launch consolidates the
# bundled sounds\ into 'user settings and logs\sounds\', emptying sounds\) ----
Write-Host "`nPackage contents:" -ForegroundColor Cyan
$wavCount = @(Get-ChildItem -LiteralPath (Join-Path $publishDir 'sounds') -Filter *.wav -ErrorAction SilentlyContinue).Count
$soundsPath = Join-Path $publishDir 'sounds'
$wavCount = @(Get-ChildItem -LiteralPath $soundsPath -Filter *.wav -ErrorAction SilentlyContinue).Count
if ($wavCount -ge 3) { Pass "cue sounds bundled ($wavCount .wav)" } else { Fail "cue sounds missing (found $wavCount) - this is the bug that shipped v3.9 with no sounds" }
foreach ($cue in @('connect.wav', 'disconnect.wav', 'start up.wav')) {
if (Test-Path -LiteralPath (Join-Path $publishDir "sounds\$cue")) { Pass "cue '$cue' present" } else { Fail "cue '$cue' missing from the published sounds\ folder" }
# Cues ship as numbered variants ("connect 1.wav", ...); each required cue needs at least one.
foreach ($base in @('connect', 'disconnect', 'start up')) {
$variants = @(Get-ChildItem -LiteralPath $soundsPath -Filter "$base*.wav" -ErrorAction SilentlyContinue)
if ($variants.Count -gt 0) { Pass "'$base' cue has $($variants.Count) sound variant(s)" } else { Fail "no sound variant for the '$base' cue" }
}
# Keyboard-click + password sounds.
foreach ($extra in @('key 1.wav', 'passkey.wav')) {
if (Test-Path -LiteralPath (Join-Path $soundsPath $extra)) { Pass "'$extra' present" } else { Fail "'$extra' missing from the published sounds\ folder" }
}
if (Test-Path -LiteralPath (Join-Path $publishDir 'readme.html')) { Pass "readme.html (F1 manual) bundled" } else { Fail "readme.html missing" }
if (Test-Path -LiteralPath (Join-Path $publishDir 'runtimes\win-x64\native\opus.dll')) { Pass "native opus.dll bundled" } else { Fail "native opus.dll missing (runtimes\win-x64\native\)" }