Accessibility and custom toggleButton

Hi!

This is less of a question and more of a comment, really.

We have a custom toggle button class in Surge and I implemented accessibility for it roughly how you would expect

         explicit SwitchAH(Switch *s)
        : mswitch(s), juce::AccessibilityHandler(
                          *s,
                          s->isMultiIntegerValued() ? juce::AccessibilityRole::button
                                                    : juce::AccessibilityRole::toggleButton,
                          juce::AccessibilityActions()
                              .addAction(juce::AccessibilityActionType::showMenu,
                                         [this]() { this->showMenu(); })
                              .addAction(juce::AccessibilityActionType::press,
                                         [this]() { this->press(); }))
    {
    }

    juce::AccessibleState getCurrentState() const override
    {
        auto state = AccessibilityHandler::getCurrentState();
        state = state.withCheckable();
        if (mswitch->getValue() > 0.5)
            state = state.withChecked();

        return state;
    }

This worked great on macOS, but on windows it reported no errors or concerns, but didn’t show a value. The reason, which you may see, is that I don’t implement the ::toggle action.

In juce_win32_AccesibilityElement.cpp you see this

               case UIA_TogglePatternId:
                {
                    if (accessibilityHandler.getActions().contains (AccessibilityActionType::toggle)
                        && accessibilityHandler.getCurrentState().isCheckable())
                    {
                        return new UIAToggleProvider (this);
                    }

                    break;
                }

which explains why it didn’t work; if you don’t implement :toggle then no accessible value.

But

1: Toggle doesn’t shine through as an event in mac accesibility inspector and
2: I “am” a toggleButton role

So I think that maybe this condition is wrong, but if it isn’t for some reason (I didn’t dig too far into the UIAToggleProvider) it would have been super awesome for the AH to have something like

if (role == toggleButton && ! actions.contain(::toggle))
   // comment comment
   jassert(false)

so I could have at least known it wouldn’t work on windows after writing it on mac.

Anyway nothing beats testing and we found this and I added the ::toggle method but just wanted to share this experience in case either (1) @reuk you would consider such an assertion and if you can’t for some reason (2) someone else could find this in the future

Surge Accessibility is looking really good and looks like we will be able to release next week or thereabouts. Exciting!

1 Like

Given that toggle isn’t available on some platforms, and the semantics of ‘press’ and ‘toggle’ are quite similar for something with checkable state, I wonder whether we should be attempting to invoke the toggle action if it exists, but falling back to the press action otherwise. I think we should probably follow this procedure on both macOS and Windows, so that interacting with a Checkable item on both platforms will prefer calling the toggle action, but still fall back to the press action on failure.

This would technically be a breaking change (controls may be able to trigger press/toggle actions that weren’t previously made available) but I think likely harmless in practice, as developers are unlikely to add accessibility actions that they don’t want to be called.

Does that sound like a reasonable resolution to you? Do you foresee such a change causing problems in Surge?

I made toggle call press so that’s perfect for me

Another solution I was considering is: if your accessible role is toggle button and you don’t implement toggle put in a jassert so the dev knows

I think the real thing is the windows code is using has toggle as the condition in the accessible code as opposed to is toggle button or has checkable state

But easy for me to work around whatever you decide! And thanks as always

I think this is because the TogglePattern interface requires both a ‘value’ and a ‘toggle’ action. It makes sense for JUCE to check whether the AccessibilityHandler is actually capable of providing both of those things, rather than just checking the handler’s role.

It sounds like the suggested change won’t cause issues for you, so I’ll go ahead with that approach.

Thanks for the feedback!

Yeah right! So elevate press to toggle if press is there and toggle isn’t seems smart!

Thanks for looking!

I’ve made the suggested change here:

If you run into any problems with the change, please let us know.