How is screen reader supposed to work with viewports?

I have my mod matrix in a view port. There are 18 rows. I navigate there with screen reader, it will only show me 13 rows. I scroll up, now I can access all 18. It seems any component that is outside the window bounds doesn’t work with screen reader.

Is there a way to auto scroll the viewport? Otherwise there is no way a blind user will know to scroll the viewport or how hard to scroll it.

According to this stack overflow post, when the focus changes it is the developers responsibility to scroll into view. ios - VoiceOver not scrolling to elements offscreen in landscape? - Stack Overflow

With the current API, I don’t see any way to do this. I think AccessibilityHandler::grabFocusInternal needs to walk up the component hierarchy and find an viewports and scroll the component into view. I’m not sure how this would work with custom scrolling components that aren’t viewports.

Hi @ed95, We’ve just encountered the problem reported by @RolandMR, is there any news?

We’re also seeing the same problem.

Components that are not within the visible area of the viewport can still gain keyboard focus using Tab, but the VoiceOver cursor doesn’t follow them. Using VO+arrow keys to navigate only lets you access things that are visible in the viewport.

It’s also possible to access the scrollbars using a screenreader which seems odd to me - a screenreader user shouldn’t really need to be aware that they’re in a viewport as it’s a purely visual concept IMO.

In general it seems that it would make sense for a Viewport to check if the component with keyboard focus is within its hierarchy and if so automatically scroll to make that component centred. I assume that would then allow screenreaders to follow focus when using Tab, but don’t think it would solve the “normal” VO+arrow keys traversal.

1 Like

I think we need:

void FocusChangeListener::globalAccessibilityFocusChanged (Component* focusedComponent)

and

void Viewport::ensureVisible (Component *)

then we could connect them.

2 Likes

It would be really nice if we could move the accessibility focus too, like when my inspector opens, the accessibility focus should jump to it.

One of our Qt coworkers shared this gif showing how the equivalent works in Qt if it’s of any use:

qscrollarea-demo

Esentially the ScrollArea knows if the next thing to be tabbed-to is not entirely on-screen and so scrolls along to make sure it’s fully visible before passing on the keyboard focus.

Not sure how it works for horizontal + vertical scrolling but I’d imagine very similar behaviour.

1 Like

Hi,

I have found a workaround to make the Viewport more accessible. The main idea is to make sure that the child components are visible by the accessibility client, even when they are not visible on screen.

For that I used a custom AccessibilityHandler whose only purpose is to raise the AccessibleState:: Flags::accessibleOffscreen flag:

class AlwaysVisibleAccessibilityHandler : public AccessibilityHandler {
  public:
    explicit AlwaysVisibleAccessibilityHandler(Component &c) : AccessibilityHandler(c, AccessibilityRole::group) {}
    AccessibleState getCurrentState() const override {
      return AccessibilityHandler::getCurrentState().withAccessibleOffscreen();
    }
};

Then override the createAccessibilityHandler() function in your child components:

std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override {
  return std::make_unique<AlwaysVisibleAccessibilityHandler>(*this);
}

A global search on the string “withAccessibleOffscreen” on juce code shows that it is used for these three classes: PopupMenu, ListBox, TreeView :wink:

Side note: I have also disabled the viewport scrollbar. In my case:

viewport.getVerticalScrollBar().setAccessible(false);

Can we convert this to a Feature Request?

It would be great if the Viewport could scroll based on VoiceOver navigation, similar to the ListBox class.