Announce the outcome of a Delete in both remembered lists through the screen reader

Deleting a remembered app (or peer) was SILENT to NVDA: the next row lands on the same
list index the deleted one had and the list already has focus, so no focus/selection
event fires - nothing to announce (Ed, 2026-07-26: deleting foobar said nothing).

FocusAndAnnounceAfterDelete now follows the focus move with a Tolk line through the
existing ScreenReader channel (the house pattern for feedback the screen reader can't
observe): '<deleted row> removed. <row now under focus>.' - or that the list is empty.
No dialog, no popup; applied to the remembered applications AND remembered peers lists
so the two stay identical.

Gate 60/60.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Ednunp
2026-07-26 22:27:55 +01:00
co-authored by Claude Fable 5
parent 64c92a67bb
commit e2211f8a40
+19 -2
View File
@@ -3475,9 +3475,11 @@ public sealed class MainForm : Form
if (args.KeyCode == Keys.Delete)
{
var prevIndex = rememberedPeersList.SelectedIndex;
var deletedLabel = (rememberedPeersList.SelectedItem as RememberedPeerItem)?.ToString();
RemoveSelectedRememberedPeer(rememberedPeersList);
SyncAllPeerLists();
FocusListItemAfterDelete(rememberedPeersList, prevIndex);
if (deletedLabel is not null) FocusAndAnnounceAfterDelete(rememberedPeersList, deletedLabel, prevIndex);
else FocusListItemAfterDelete(rememberedPeersList, prevIndex);
args.Handled = true;
args.SuppressKeyPress = true;
}
@@ -3750,8 +3752,9 @@ public sealed class MainForm : Form
args.SuppressKeyPress = true;
if (rememberedAppsList.SelectedItem is not AudioAppChoice choice) return;
var prevIndex = rememberedAppsList.SelectedIndex;
var deletedLabel = choice.ToString() ?? choice.ProcessName; // announce what the row read as
RemoveRememberedApplication(choice.ProcessName);
FocusListItemAfterDelete(rememberedAppsList, prevIndex);
FocusAndAnnounceAfterDelete(rememberedAppsList, deletedLabel, prevIndex);
};
// Reconcile the app list on a slow timer so entries appear/disappear as apps open and close,
@@ -7503,6 +7506,20 @@ public sealed class MainForm : Form
}
/// <summary>After a Delete in a remembered list: focus the next item AND speak the outcome through
/// the screen reader. The speech is load-bearing, not decoration: the next item usually lands on the
/// SAME index the deleted one had, and the list already has focus — so no focus or selection event
/// fires and NVDA would otherwise say nothing at all (Ed, 2026-07-26: deleting foobar gave silence).
/// Speaks "«deleted» removed." plus the row now under focus, or that the list is empty.</summary>
private static void FocusAndAnnounceAfterDelete(CheckedListBox list, string deletedLabel, int prevIndex)
{
FocusListItemAfterDelete(list, prevIndex);
var now = list.SelectedItem?.ToString();
ScreenReader.Speak(string.IsNullOrWhiteSpace(now)
? $"{deletedLabel} removed. The list is empty."
: $"{deletedLabel} removed. {now}.");
}
/// <summary>
/// After deleting an item from a CheckedListBox, focus the next sensible item so NVDA
/// announces the new selection. If something exists at the same index that the deleted