Skip to content

A ContextMenuStrip opened from the keyboard is silent for screen readers (no MenuOpened the first time, no item focused) #15178

Description

@kastwey

.NET version

.NET 10 (10.0.11). Same code in main. The behaviour is also there in .NET 9.

Did it work in .NET Framework?

No. I built the same repro for .NET Framework 4.8: NVDA 2026.2.0 is silent on opening there too, and no item is selected. (With the arrows it then says "DropDown toolbar, Open", without the position; on .NET the items are read better, "Open, 1 of 4".) The MSAA events on 4.8 are MENUPOPUPSTART name="DropDown" role=MENUPOPUP on opening and no FOCUS until an arrow key is pressed. So this is a long-standing gap, not a regression.

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No. #3334 reported it for .NET Core 3.1; it was closed as an NVDA problem after checking that the UIA tree was correct. The tree is correct; the problem is in the events.

Issue description

Open a ContextMenuStrip with Shift+F10 or the Applications key (the menu is just assigned to Control.ContextMenuStrip). With NVDA nothing is announced until an arrow key is pressed. I am a blind developer and I hit this in my own app, so I listened to the UIA and MSAA events from another process and read the source. There are three separate causes:

  1. MenuOpened is not raised the first time the menu opens. ContextMenuStrip.OnOpened only raises UIA_MenuOpenedEventId when IsAccessibilityObjectCreated is true. The first time a context menu opens nothing has asked for its accessible object yet: it has no owner item and it was never part of the tree a client walked. From the second opening on, the event is raised.

  2. No item is selected, so nothing gets the accessibility focus. ContextMenuStrip.ShowInternal(source, location, isKeyboardActivated) only turns the mnemonic underlines on. A submenu opened from the keyboard selects its first item (ToolStripMenuItem calls DropDown.SelectNextToolStripItem(start: null, forward: true)), and so does a native Windows menu opened from the keyboard: for the system menu the WinEvents are MENUPOPUPSTART followed at once by FOCUS on "Restore".

  3. The focus event of an item can be skipped in a context menu. ToolStripItem.Select decides whether accessibility is on with:

    IsOnDropDown ? OwnerItem?.IsAccessibilityObjectCreated ?? false : IsParentAccessibilityObjectCreated

    The items of a ContextMenuStrip are on a drop-down that has no OwnerItem, so this is always false unless the item's own accessible object already exists.

A related point: the menu has no accessible name, because ToolStripDropDownAccessibleObject.Name takes it from the owner item and a context menu has none. On .NET Framework 4.8 it was named "DropDown". Native context menus are named "Context", which screen readers announce followed by the role ("Context menu").

Measurements: the UIA events seen from another process, before and after

Stock .NET 10.0.11. First opening with Shift+F10, then Down, Down:

(nothing on opening)
FocusChanged: MenuItem "Open"   <- only after pressing Down
FocusChanged: MenuItem "Edit"
MenuClosed:   Menu ""

With the proposed changes:

MenuOpened:   Menu "Context"
FocusChanged: MenuItem "Open"   <- on opening
FocusChanged: MenuItem "Edit"   <- Down

What screen readers say with the proposed changes

That is the same experience the readers give with the other WinForms menus on .NET: Alt+F on a MenuStrip, where the first item has always been selected at once, gives "New, 1 of 3" in NVDA and in JAWS, and neither says "menu". They announce the focused item rather than the menu because its focus event follows MenuOpened at once; that is a matter for the readers (for NVDA I traced it to MenuOpened being dropped when the menu does not report HasKeyboardFocus, and I will report it there), not something the menu should work around.

Steps to reproduce

Button button = new() { Text = "Button with a ContextMenuStrip", AutoSize = true };
ContextMenuStrip menu = new();
menu.Items.Add("&Open");
menu.Items.Add("&Edit");
button.ContextMenuStrip = menu;
Controls.Add(button);
  1. Run it with NVDA. Focus the button and press Shift+F10.
  2. Nothing is announced. Press Down: "Open, 1 of 2".

I have the changes with unit tests ready and will open a pull request.

A draft pull request with the changes is open alongside this issue, in case it helps to judge the direction; I am happy to adjust it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions