diff --git a/src/RemSound.App/AccessibleCheckBox.cs b/src/RemSound.App/AccessibleCheckBox.cs index a6ea60c..ba5a7a1 100644 --- a/src/RemSound.App/AccessibleCheckBox.cs +++ b/src/RemSound.App/AccessibleCheckBox.cs @@ -51,6 +51,14 @@ internal sealed class AccessibleCheckBox : CheckBox [DllImport("user32.dll")] private static extern void NotifyWinEvent(uint eventMin, nint hwnd, int idObject, int idChild); + /// Optional gate, called with the new Checked state just before the generic checkbox + /// tick/untick sound plays; return true to suppress it. The send/receive checkboxes set this so + /// that when their OWN dedicated cue (send/receive turned on/off) is enabled, only that cue + /// plays - the generic checkbox sound doesn't double up on top of it. When their dedicated cue + /// is set to "(none)", this returns false and the generic checkbox sound plays as normal. + [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)] + public Func? SuppressCheckSound { get; set; } + protected override void OnCheckedChanged(EventArgs e) { base.OnCheckedChanged(e); @@ -61,8 +69,9 @@ internal sealed class AccessibleCheckBox : CheckBox { NotifyWinEvent(EVENT_OBJECT_FOCUS, Handle, OBJID_CLIENT, CHILDID_SELF); // Audible tick/untick feedback. Gated on Focused so it fires for a genuine user toggle - // (click or spacebar) but stays silent for the bulk programmatic checking on profile load. - CheckSoundService.Play(Checked); + // (click or spacebar) but stays silent for the bulk programmatic checking on profile + // load - and skipped when a control has its own dedicated cue (send/receive). + if (SuppressCheckSound?.Invoke(Checked) != true) CheckSoundService.Play(Checked); } } } diff --git a/src/RemSound.App/MainForm.cs b/src/RemSound.App/MainForm.cs index 299d3f1..7682884 100644 --- a/src/RemSound.App/MainForm.cs +++ b/src/RemSound.App/MainForm.cs @@ -1009,6 +1009,11 @@ public sealed class MainForm : Form // --- Wire main-form events --- receiveAudioCheckbox.CheckedChanged += (_, _) => OnStreamingCheckboxChanged(receiveAudioCheckbox); sendMyAudioCheckbox.CheckedChanged += (_, _) => OnStreamingCheckboxChanged(sendMyAudioCheckbox); + // Send/receive have their own dedicated cue sounds (send/receive turned on/off). When that + // dedicated cue is on, only it plays - suppress the generic checkbox tick/untick on these two. + // When the dedicated cue is "(none)", these return false and the checkbox sound plays as normal. + sendMyAudioCheckbox.SuppressCheckSound = on => on ? AppConfig.Load().EnableSendOnCue : AppConfig.Load().EnableSendOffCue; + receiveAudioCheckbox.SuppressCheckSound = on => on ? AppConfig.Load().EnableReceiveOnCue : AppConfig.Load().EnableReceiveOffCue; volumeBar.Scroll += (_, _) => { receiver.Volume = volumeBar.Value / 100f; MarkProfileDirty(); }; WireCheckedListAccessibility(receiveOutputDevicesList, receiveOutputDevicesStatusLabel, "receive output device"); receiveOutputDevicesList.ItemCheck += (_, e) =>