v4.1: two screen-reader fixes — silent start-in-tray, announce on restore
- Starting straight into the tray (StartMinimised / --minimized) no longer plays the "minimise" cue; only a genuine user minimise does (the startup path passes playCue:false) - Restoring the window from the tray now lands focus on a real named control on the active tab so NVDA announces it, instead of resting on the role-less QuietTabControl and surfacing silently - Shared the focus-a-leaf-for-announcement helper between the main window and Preferences Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a408d2b56e
commit
5abbeefe29
@@ -27,6 +27,36 @@ internal static class WinEventNotifier
|
||||
NotifyWinEvent(EVENT_OBJECT_FOCUS, control.Handle, OBJID_CLIENT, CHILDID_SELF);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Land NVDA on a named control so a freshly-shown window or dialog announces itself
|
||||
/// instead of surfacing silently. Focuses the first focusable leaf inside <paramref name="page"/>
|
||||
/// (falling back to <paramref name="fallback"/>), forcing a genuine focus CHANGE (ActiveControl=null
|
||||
/// first) and re-firing the MSAA focus event. Used by the Preferences dialog on open and by the
|
||||
/// main window when it's restored from the tray. The page sits inside a <see cref="QuietTabControl"/>
|
||||
/// whose own accessible object is deliberately role-less and nameless, so focusing the tab control
|
||||
/// itself would be silent — this finds a real leaf (the first interactive control on whatever tab
|
||||
/// is showing) instead. Best run deferred (BeginInvoke), after the show/foreground settles.</summary>
|
||||
public static void AnnounceByFocusingLeaf(ContainerControl form, Control? page, Control fallback)
|
||||
{
|
||||
var leaf = FirstFocusableLeaf(page) ?? fallback;
|
||||
form.ActiveControl = null;
|
||||
leaf.Focus();
|
||||
if (leaf.IsHandleCreated) NotifyFocus(leaf);
|
||||
}
|
||||
|
||||
/// <summary>The first visible, enabled, tab-stop control inside <paramref name="container"/>,
|
||||
/// searched depth-first in child order (which matches the order controls were added). Returns a
|
||||
/// real leaf (button / list / combo / checkbox) — never a layout panel or the role-less tab strip.</summary>
|
||||
private static Control? FirstFocusableLeaf(Control? container)
|
||||
{
|
||||
if (container is null) return null;
|
||||
foreach (Control c in container.Controls)
|
||||
{
|
||||
if (c is { CanSelect: true, TabStop: true, Visible: true, Enabled: true }) return c;
|
||||
if (FirstFocusableLeaf(c) is { } nested) return nested;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user