USEPA / emf

Emissions Modeling Framework (EMF)
6 stars 3 forks source link

screen reader: make text in dialog boxes accessible #51

Open cseppan opened 3 years ago

cseppan commented 3 years ago

Not sure if it's a Java problem or an NVDA issue, but dialogs that use the JOptionPane types QUESTION_MESSAGE or PLAIN_MESSAGE (no icon) don't get their text read. Looking at where JOptionPane.showConfirmDialog() is used, most are warning messages that need the user to confirm (e.g. Are you sure you want to delete this item?), so converting to type WARNING_MESSAGE is appropriate.

cseppan commented 3 years ago

823be104c6def4037e66efeac63ab26ba5f7744c

cseppan commented 3 years ago

JAWS seems to not read the dialog text when the JOptionPanel parent component is an EmfInternalFrame or EmfConsole. It will read the text when LoginWindow is the parent. The parent component determines the initial position of the dialog window. Using null as the parent seems to always work with JAWS, but the dialog is then centered on the entire screen.

The best solution seems to be to wrap the dialog text in a Label so that it can be focusable. This has the benefit of letting the user cycle back to the text as many times if needed. Commit 558c6fabc3292c3928b5cea2f6ab8e2a2dc50844 adds Label for a few dialogs, using HTML formatting for multi-line messages.

One problem with this approach is that focus is initially on the default button in the dialog window, not on the label, so the user has to tab through the buttons to get back to the label text. We can build a custom dialog that overrides selectInitialValue() like this Stack Overflow code:

    public static String getPassword(String title) {
        JPanel panel = new JPanel();
        final JPasswordField passwordField = new JPasswordField(10);
        panel.add(new JLabel("Password"));
        panel.add(passwordField);
        JOptionPane pane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
            @Override
            public void selectInitialValue() {
                passwordField.requestFocusInWindow();
            }
        };
        pane.createDialog(null, title).setVisible(true);
        return passwordField.getPassword().length == 0 ? null : new String(passwordField.getPassword());
    }

In addition to code directly calling JOptionPane.showConfirmDialog(), there are two competing library functions: YesNoDialog in EMF and ConfirmDialog in Commons. The focusable Label class is part of EMF, and so can't currently be used by ConfirmDialog.