JUCE Accessibility on `develop`

Hi, thanks for the answer. I did actually look in breaking changes.txt but somehow managed to miss the explanation.

Narrator doesn’t seem to be reading out the help texts for sliders. You can reproduce this in DemoRunner by adding the following statements to setupSlider (line 266) in AccessibilityDemo.h:

slider.setWantsKeyboardFocus(true);
slider.setHelpText ("Help Text");

in MacOS/VoiceOver this will read the help text, but in Windows/Narrator it won’t. I can’t find the source of the problem - AccessibilityHandler seems to be picking up the text correctly, but it’s not being picked up by Narrator.

Helptext is bound to the UIA_HelpTextProperty. I think UIA_FullDescriptionProperty is more common these days, though I have no hard evidence of that. NVDA will try FullDescription first, then falls back to HelpText.

In ā€œmodules\juce_gui_basics\native\accessibility\juce_win32_AccessibilityElement.cppā€, what happens if you change case UIA_HelpTextPropertyId: to case UIA_FullDescriptionPropertyId:

Tried it and doesn’t seem to change anything. In the debugger the text is still being picked up, it just isn’t being read by Narrator.

Ugh, that’s a drawback. If it doesn’t read either of them, I don’t think there’s much you could do.
However, note that most screen reader users are likely using NVDA or JAWS, Narrator has a pretty small market share.

Indeed - any idea why this behaviour would be limited to sliders?

Have you set the highest level of detail? IIRC, sliders’ help texts are not read in the default level (3), but they are in 5 and maybe 4.

Edit: sorry, it’s not the level of detail, it’s a separate option:
helptext
OTOH, the help texts for buttons do depend on the level of detail, they appear at 3. That seems inconsistent, but maybe it’s on Narrator’s side.

Shouldn’t this commit include Button too?

That works, thanks. Indeed a little inconsistent here.

Thanks for reporting. I was able to reproduce the issue and have pushed a fix disabling accessibility for tooltip windows in 422c8f8. We now rely on the help text for reading out tooltips which seems in line with what other accessible apps and the native applications do.

I’ve pushed a fix for this to develop here:

Does this solve the issue for you?

Yes, thanks for pointing that out. I’ll push something shortly.

What I’ve implemented, which is very useful, is that when there is a tooltip but no help text, then the help text defaults to the tooltip text. This saves me doing everything twice, as I’m a heavy tooltip user.

Thanks. That does give me the ability to access the table rows with voiceover. However, this is the only thing I can do. I can’t access the table header and I can’t move on to the next component. With Narrator I can do both.

Hi Ed, that does make it possible to navigate the rows via voiceover. And thanks @duvrin for the simple example project.

I’m having a bit of trouble figuring out how to get voiceover to navigate the columns of the rows and to read out the text contained in each cell of the table. It seems like if you are painting the text inside of the usual paintCell overrided function then it would not be possible for voiceover to know the contents through the default RowAccessibilityHandler. I’m guessing I will need to create a custom AccessibilityHandler to achieve this, so any guidance would be much appreciated, thanks! (also I am wondering if you would consider implementing this to be the default behavior for listbox accessibility).

Hi @ed95!
Unfortunately it seems like after integrate accessibility support our apps has some memory leaks.
Is it something that happens to you too?

Yes, thank you for reporting. I’ll push a fix shortly.

1 Like

I’ve just moved to modal overlays (I had been using another solution), and found a little issue. When a modal ends by closing, it’s enough to call setVisible (false), as it triggers ModalComponentManager::ModalItem::cancel(), so there’s no need to call exitModalState(). This still works by itself, but it makes Narrator get stuck on the hidden component, because setVisible() changes focus before notifying listeners, so it happens before the modal is ended. Calling exitModalState() before setVisible() fixes it, but it kind of defeats the purpose of the notification.

So, after some digging through the juce source (juce_mac_Accessibility.cpp), I’m noticing that the NSAccessibility notification selectors of getAccessibilityRows and getAccessibilityColumns on macOS are currently implemented to only ever retrieve the row and column cell handlers of the first row/col. More specifically, the only calls to getCellHandler for an AccessibilityTableInterface have either 0 for the row or zero for the column, making it not possible for the macOS voiceover to read the middle cells in a TableListBox that has more than one column.

if (auto* handler = tableInterface->getCellHandler (row, 0))
if (auto* handler = tableInterface->getCellHandler (0, column))

Im not sure how best to solve this, any help would be appreciated. The main goal is just to be able to read out/navigate each cell of a TableListBox with voiceover. Can also provide more information if you don’t see what I’m referring to.