Skip to content

OLYM-9858: [Windows] A semantics node that is not selected no longer reads as selected (cherry-pick of #184223) - #11

Merged
MylioClaude merged 2 commits into
OlymEDRSupportfrom
claude/olym-9858
Nov 11, 2026
Merged

MylioClaude merged 2 commits into
OlymEDRSupportfrom
claude/olym-9858

Conversation

@MylioClaude

Copy link
Copy Markdown
Collaborator

Fixes OLYM-9858: on Windows, NVDA says "selected" on every right-panel tab, the Info tab's ⋮ (Customize sections), the Tab settings gear and the rail buttons (Info, Share, Edit, Show QuickAlbum, and the whole left navigation rail), not just the one that is open.

Root cause. In the shared desktop accessibility bridge, AccessibilityBridge::SetBooleanAttributesFromFlutterUpdate (engine/src/flutter/shell/platform/common/accessibility_bridge.cc) did:

node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, flags->is_selected);

is_selected is a FlutterTristate (none = 0, true = 1, false = 2). As a bool, false (2) is true, so a node whose Dart semantics say selected: false was reported as selected. Only nodes with no selected state at all (none) came out right. The repro read the MSAA tree on syswindows1 and found STATE_SYSTEM_SELECTED on every node that sets selected:, true or false. The Dart side passes the right values (Semantics(selected: widget.isSelected) on the tab cell, isSelected: _tabConfigMenuOpen on the gear). The Linux embedder does not use this bridge and already compares with kFlutterTristateTrue (fl_accessible_node.cc), so Linux was never affected. macOS uses the same bridge, so its roles that read kSelected get the same fix.

Fix. A cherry-pick of upstream flutter/flutter d04108d, "[a11y] fix selected tristate flags mismatch (flutter#184223)" (fixes flutter#184058), author kept. It compares with kFlutterTristateTrue, like is_expanded, is_toggled and is_focused in the same file, and adds the test AccessibilityBridgeTest.IsSelectedAttribute (none, true, false). Upstream first shipped it in 3.44.0; every 3.41.x tag (checked 3.41.4 to 3.41.9) still has the bug. A second commit adds it to UPSTREAM-CANDIDATES.md under "Not candidates", so it is dropped once the SDK is 3.44 or later.

How I tested.

  • Done on a Linux agent (sysubuntu4), which has no engine checkout or engine toolchain (no gn, no gclient), and whose embedder doesn't use this bridge. So I did not build the engine or try the fix with NVDA. The pre-merge Windows engine build isn't something the swarm can do today (fork PR OLYM-939: [Windows] Use the 8-bit window surface unless a display has HDR on #7 found no Windows machine with an engine setup), and Build Engine builds only the branch tip after a merge.
  • Compile check of the changed file: clang++ -std=c++20 -fsyntax-only on the branch's accessibility_bridge.cc against the engine's in-tree headers (stock 3.41.2): no errors. The same command reports an error when the new line is broken on purpose, so it does check that line.
  • Not run: the engine unit tests, including the new one (the swarm's check-in rules leave tests to CI and the standing builds).

After the merge. Someone runs Olym's Build Engine workflow for windows and windows-arm64 (and macos, which shares the bridge) so new tarballs go up under v3.41.2-edr. Olym's engine injector notices the new tarballs by their ETag, so nothing in Olym changes. Then on Windows with NVDA: select a photo, Tab through the right panel's tabs and the gear. Only the open tab should say "selected".

Ticket: https://mylio.atlassian.net/browse/OLYM-9858

🤖 Generated with Claude Code

hannah-hyj and others added 2 commits November 11, 2026 07:46
fix flutter#184058
The issue and solution was both pointed out in
flutter#184058

## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

(cherry picked from flutter/flutter commit d04108d, for OLYM-9858: on Windows NVDA said "selected" on every node whose semantics state selected: false.)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…selected tristate)

The shared desktop accessibility bridge reported a node whose semantics
say "not selected" as selected, so NVDA on Windows said "selected" on
every right-panel tab, the Tab settings gear and the rail buttons.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@MylioClaude MylioClaude left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: approved

The fix is right for OLYM-9858. The bridge now reports a node as selected only when its semantics flag is "true". Before, "false" (value 2) also counted as selected. Nothing must change before the merge. One suggestion below; it doesn't block the merge.

How I read it

  • The PR is two commits on top of OlymEDRSupport (2 ahead, 0 behind), so it merges cleanly. This machine has no checkout of the fork, so I read the diff and the files around it from GitHub at 9b9a111.
  • Same as upstream. The code change and the new test match upstream flutter/flutter d04108d exactly: the before and after blob hashes of both files are the same. The author is kept, and the commit message names the upstream commit.
  • Upstream release claims hold. The 3.41.2 and 3.41.9 tags still pass flags->is_selected as a bool. 3.44.0 has the fix. No stable 3.42 or 3.43 exists, so "it falls away once the SDK is 3.44 or later" is right.
  • What I checked from the review list:
    1. The new test can fail. On the base, the "false" node (value 2) becomes kSelected = true, so its EXPECT_FALSE fails there. The "none" and "true" nodes make sure the fix doesn't go too far. It follows the file's existing pattern (CreateSemanticsNode, then flags2 pointing to a local FlutterSemanticsFlags).
    2. Every door. accessibility_bridge.cc line 445 is the only place in the common, Windows and macOS accessibility code that reads is_selected (I searched the common bridge and node delegates, accessibility_bridge_windows.cc, flutter_platform_node_delegate_windows.cc, accessibility_plugin.cc and AccessibilityBridgeMac.mm). The other three-state flags in that file (is_expanded, is_toggled, is_focused) already compare with kFlutterTristateTrue. The Linux embedder doesn't use this bridge, and its fl_accessible_node.cc line 110 already compares correctly.
    3. The platform where the bug was seen. Windows. AXPlatformNodeWin sets STATE_SYSTEM_SELECTED from kSelected (ax_platform_node_win.cc line 5089), and that is the MSAA state the repro found on every node. The open tab still gets true, so it still says "selected". macOS shares the bridge and gets the same fix.
    4. Privacy, stored data, machine writes, async UI, undo: none of these applies to this change.
    5. Docs. The fork's UPSTREAM-CANDIDATES.md gets an entry under "Not candidates", next to the other cherry-picks. In Olym, BUILD_DEPLOY.md § "Patched Flutter Engine" names only some of the carried fixes ("including …") and points to this file. The right-rail PRD already says each tab cell's node carries its selected state, which this change makes true on Windows. So no Olym doc goes stale.
    • The change adds no warnings, dead code, logging, workarounds or dependencies. The code is upstream Flutter's own (BSD licence), so no licence question comes up.

Findings

1. Suggestion: try it with NVDA as soon as the Windows engine is rebuilt, before OLYM-9858 is closed

engine/src/flutter/shell/platform/common/accessibility_bridge.cc:445

  • What. The PR says the engine wasn't built and the fix wasn't tried on Windows. The swarm can't build the Windows engine before the merge, and the code is the same as a fix upstream has shipped since 3.44.0. So I'm not asking for this before the merge.
  • Why it matters. Build Engine uploads the new tarballs under the same v3.41.2-edr tag, and Olym's engine injector picks them up by their ETag. So the first Windows build with this fix goes straight to every Olym build. The NVDA check right after that build is the only time anyone tries this fix on Windows.
  • What to do. Keep OLYM-9858 open until that check has been done, as the PR's "After the merge" section says. Check the left navigation rail as well as the right panel's tabs, the ⋮ and the gear: only Library (or whichever view is open) should say "selected" there. On macOS, the earlier "no selected state at all" finding (OLYM-9026) takes a different route. Note any change there on that ticket, not this one.

@MylioClaude
MylioClaude merged commit a0ad2b3 into OlymEDRSupport Nov 11, 2026
1 check passed
@MylioClaude

Copy link
Copy Markdown
Collaborator Author

Merged by the swarm's jira-watch as review round 1 approved it: a review that approves a pull request merges it as it was reviewed, with no answer session (the swarm's check-in rules, rule 2). The review's suggestions stay on this pull request; the swarm took none of them in it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Windows] NVDA screen reader announces "selected" for widgets with selected: false

2 participants