SIGN IN SIGN UP

fix: handle COMError in UIA selectionContainer to prevent silent focus (#20255)

No GitHub issue filed — happy to open one if preferred. The bug is diagnosable from a UIA debug log and the fix is a defensive try/except matching an existing pattern in the same file three lines above.
Summary of the issue:

When NVDA focuses a UIA list item whose provider exposes the SelectionItem pattern but errors when asked for the SelectionContainer, NVDAObjects.UIA.UIA._get_selectionContainer raises an uncaught COMError. The exception propagates up through reportFocus → speakObject → getObjectPropertiesSpeech, aborting speech for the entire focus event — the user hears nothing on focus.

The trigger is the SELECTABLE | FOCUSABLE | SELECTED branch in speech/speech.py:801-818 (the code that suppresses redundant "selected" announcements when only one item is selected). That branch queries obj.selectionContainer, which fails.

Reproduced in Telegram Desktop built against Qt 5.15.19 with the UIA backend (qwindowsuiaaccessibility). The chat list (Dialogs::InnerWidget) exposes ListItem-role virtual children with a single selected row. UIA debug log of the crash:

DEBUGWARNING - eventHandler.executeEvent ...
error executing event: gainFocus on <NVDAObjects.UIA.ListItem ...>
Traceback (most recent call last):
  File "eventHandler.pyc", line 354, in executeEvent
  File "NVDAObjects/UIA/__init__.pyc", line 1573, in event_gainFocus
  File "NVDAObjects/__init__.pyc", line 1208, in reportFocus
  File "speech/speech.pyc", line 816, in speakObject
  File "speech/speech.pyc", line 771, in getObjectPropertiesSpeech
  File "baseObject.pyc", line 167, in _getPropertyViaCache
  File "NVDAObjects/UIA/__init__.pyc", line 1677, in _get_selectionContainer
  File "comtypes/_post_coinit/_cominterface_meta_patcher.pyc", line 21, in __getattr__
_ctypes.COMError: (-2147220991, 'An event was unable to invoke any of the subscribers', ...)

Qt's QWindowsUiaSelectionItemProvider::get_SelectionContainer requires actionInterface() to be non-null even though it never uses the action interface (see qwindowsuiaselectionitemprovider.cpp:183-185). When the accessible interface has no action interface — as is the case for Telegram Desktop's chat row items, which only expose name/role/state/rect — Qt returns UIA_E_ELEMENTNOTAVAILABLE (0x80040201), surfaced as a COMError. This is arguably an upstream Qt bug too, but Qt 5.15 LTS is closed for community fixes, and any UIA provider that errors on this property has the same effect on NVDA today.

The bug is invisible until a list item with SELECTED state is encountered. With state.selected not set, the speech.py guard is skipped, selectionContainer is never fetched, and the same focus path completes normally — which is why the symptom looks like "NVDA only goes silent on selected items".
Description of user facing changes:

Focus is no longer silent on list items in Qt-based UIA applications (such as Telegram Desktop) when the item exposes SelectionItemPattern but its provider errors on SelectionContainer. NVDA treats the error the same as a NULL selection container — focus speech proceeds normally.
Description of developer facing changes:

NVDAObjects.UIA.UIA._get_selectionContainer now catches COMError from IUIAutomationSelectionItemPattern::CurrentSelectionContainer and returns None. This matches the defensive pattern already used by _get_UIASelectionPattern2 three lines above.
Description of development approach:

Diagnosed from a UIA debug log captured in Telegram Desktop (see traceback above). The log shows gainFocus correctly queued for the new list item, then reportFocus failing inside getObjectPropertiesSpeech at the p.currentSelectionContainer COM call. Wrapping that single property access in try / except COMError (and returning None on failure) fixes the crash. The rest of the method already handles the NULL case via the existing if not e: return None branch, so no other changes are needed.
R
Reza Bakhshi Laktasaraei committed
1c29cf37bf3c09cbd8e6801fa6942d5ff92a443f
Parent: e088bca
Committed by GitHub <noreply@github.com> on 6/1/2026, 1:10:23 AM