Topics

How to add a fake IAccessible element to a dialog


Oleksandr Gryshchenko
 


Hi friends,
Dialog box of one program is partially accessible to NVDA. I'm trying to fix this.

This dialog contains the following elements:
1. window title;
2. static text label;
3. checkbox with text description;
4. button "OK".

The problem is that the static text label is not voiced by NVDA. Only 1, 3 and 4 elements are accessable.
The class of this window contains only two children: checkbox (3) and button (4).

If you could tell me please, how can I add another fake StaticText child to the class of this dialog?

Here is the my appModule code:

import appModuleHandler
import controlTypes
from NVDAObjects.IAccessible import StaticText, delphi

class DialogMessage(StaticText):
    role = controlTypes.ROLE_STATICTEXT

    def _get_name(self):
        return self.displayText


class ExtendedDialog(delphi.Form):
    role = controlTypes.ROLE_DIALOG

    # how to add DialogMessage child to ExtendedDialog?


class AppModule(appModuleHandler.AppModule):

    def chooseNVDAObjectOverlayClasses(self, obj, clsList):
        if obj.windowClassName == "TMessageForm" and obj.role==controlTypes.ROLE_PANE:
            clsList.insert(0, ExtendedDialog)

    def __init__(self, *args, **kwargs):
        super(AppModule, self).__init__(*args, **kwargs)


Please help me to understand this issue.
I'm very grateful for any tips.
Oleksandr


Tony Malykh
 

Can you see static text with review cursor? If not, then probably there is no way to access this element, since this text might be presented as an image or something. Or a great deal of hacking might be required.
If review cursor gets there, then I think the best strategy would be to redefine how the whole dialog box is spoken once it receives focus. But that would imply that static text already has IAccessible2 implementation, it's just not focusable.
--Tony

------ Original Message ------
From: "Oleksandr Gryshchenko" <kita.zup+groups@...>
Sent: 12/30/2020 3:23:50 PM
Subject: [nvda-addons] How to add a fake IAccessible element to a dialog


Hi friends,
Dialog box of one program is partially accessible to NVDA. I'm trying to fix this.

This dialog contains the following elements:
1. window title;
2. static text label;
3. checkbox with text description;
4. button "OK".

The problem is that the static text label is not voiced by NVDA. Only 1, 3 and 4 elements are accessable.
The class of this window contains only two children: checkbox (3) and button (4).

If you could tell me please, how can I add another fake StaticText child to the class of this dialog?

Here is the my appModule code:

import appModuleHandler
import controlTypes
from NVDAObjects.IAccessible import StaticText, delphi

class DialogMessage(StaticText):
    role = controlTypes.ROLE_STATICTEXT

    def _get_name(self):
        return self.displayText


class ExtendedDialog(delphi.Form):
    role = controlTypes.ROLE_DIALOG

    # how to add DialogMessage child to ExtendedDialog?


class AppModule(appModuleHandler.AppModule):

    def chooseNVDAObjectOverlayClasses(self, obj, clsList):
        if obj.windowClassName == "TMessageForm" and obj.role==controlTypes.ROLE_PANE:
            clsList.insert(0, ExtendedDialog)

    def __init__(self, *args, **kwargs):
        super(AppModule, self).__init__(*args, **kwargs)


Please help me to understand this issue.
I'm very grateful for any tips.
Oleksandr


Oleksandr Gryshchenko
 


Hi Tony,

> Can you see static text with review cursor?
Yes, I see this text.
I also managed to get the text of the entire dialog box except for the title as follows:

fg = api.getForegroundObject()
fg.displayText
or
fg.parent.makeTextInfo(textInfos.POSITION_ALL).text

> I think the best strategy would be to redefine how the whole dialog box is spoken once it receives focus
Yes, you are right - this static text already has IAccessible2 implementation, it's just not focusable.

But I don't understand what is the correct practice of redefining the pronunciation of the whole dialog box.

When I change the fg.name attribute, the text of the window title changes.
So I thought it would be right to add another child that has the StaticText type.
For example as follows:
fg.children.append(SomeStaticTextObject)
But it doesn't work...

Could you give examples of code?
Or tell me please in which add-ons it is already implemented.

Very grateful for any advice.
Oleksandr


Lukasz Golonka
 

Hello Oleksandr,

On Wed, 30 Dec 2020 15:23:50 -0800
"Oleksandr Gryshchenko" <kita.zup+groups@gmail.com> wrote:

Dialog box of one program is partially accessible to NVDA. I'm trying to fix this.

This dialog contains the following elements:
1. window title;
2. static text label;
Can you navigate to this static text with object navigation or is review
cursor only way to access its text?

3. checkbox with text description;
4. button "OK".

The problem is that the static text label is not voiced by NVDA. Only 1, 3 and 4 elements are accessable.
The class of this window contains only two children: checkbox (3) and button (4).
Just to make sure - have you tested this with simple review mode
disabled?


If you could tell me please, how can I add another fake StaticText child to the class of this dialog?
Unless you need to make this static text show when using object nav it
should be sufficient to overwrite `getDialogText` on your dialog class
and return displaytext of the dialog there

--
HTH
Lukasz


Tony Malykh
 

In globalCommands.py there is script_speakForeground method that is bound to NVDA+B. I would check how it is implemented to see what methods in your class you can tweak to make it speak static text.
However, if you are just switching to that window, it is probably reacting to gainFocus event instead, which I believe triggersNVDAObject.reportFocus function, which might or might not be the same as previous function.
As for adding children programmatically, you can give it a try, but again, if you can see that static text with your review cursor, then most likely it is already a child of your window object. But if it's not, then you can probably add it by overriding _get_children() method of your class - when you are accessing children attribute it is actually just calling _get_children() method behind the scene.
--Tony

------ Original Message ------
From: "Lukasz Golonka via groups.io" <lukasz.golonka=mailbox.org@groups.io>
To: nvda-addons@nvda-addons.groups.io
Sent: 12/31/2020 3:21:22 AM
Subject: Re: [nvda-addons] How to add a fake IAccessible element to a dialog

Hello Oleksandr,

On Wed, 30 Dec 2020 15:23:50 -0800
"Oleksandr Gryshchenko" <kita.zup+groups@gmail.com> wrote:

Dialog box of one program is partially accessible to NVDA. I'm trying to fix this.

This dialog contains the following elements:
1. window title;
2. static text label;
Can you navigate to this static text with object navigation or is review
cursor only way to access its text?

3. checkbox with text description;
4. button "OK".

The problem is that the static text label is not voiced by NVDA. Only 1, 3 and 4 elements are accessable.
The class of this window contains only two children: checkbox (3) and button (4).
Just to make sure - have you tested this with simple review mode
disabled?


If you could tell me please, how can I add another fake StaticText child to the class of this dialog?
Unless you need to make this static text show when using object nav it
should be sufficient to overwrite `getDialogText` on your dialog class
and return displaytext of the dialog there

--
HTH
Lukasz






Oleksandr Gryshchenko
 

Hi friends,
Tony and Lukasz, I'm very grateful for your help!
Thanks to your tips, I have a better understanding of how NVDA works.
In this situation, I was helped by overriding the getDialogText() method and using the displayModel.DisplayModelTextInfo class.
Now all the dialogs of the program are voiced great, but there is still work to be done on the main window, which contains many problematic controls.

Thank you very much again for your help!
Happy New Year to all and I wish you happy holidays!
Oleksandr


وفيق طاهر
 

Please put the final code


Oleksandr Gryshchenko
 

Hi وفيق طاهر,

In this case, it was enough to override the getDialogText() method:

import appModuleHandler
from api import getForegroundObject
from NVDAObjects.behaviors import Dialog
from controlTypes import ROLE_DIALOG
from displayModel import DisplayModelTextInfo
from textInfos import POSITION_FIRST


class MyDialog(Dialog):

    def _get_role(self):
        return ROLE_DIALOG

    def getDialogText(self, *args, **kwargs):
        text = super(MyDialog, self).getDialogText(*args, **kwargs) or ''
        if not text or text.isspace():
            dModel = DisplayModelTextInfo(self, POSITION_FIRST)
            dModel.includeDescendantWindows=False
            text = dModel.text
        return text


class AppModule(appModuleHandler.AppModule):

    def chooseNVDAObjectOverlayClasses(self, obj, clsList):
        if obj.windowClassName == "TMessageForm" and obj.role==controlTypes.ROLE_PANE:
            clsList.insert(0, MyDialog)


Now when the specified dialog box appears, its title, StaticText message and CheckBox are voiced by NVDA.

Now I'm trying to redefine more complex window controls.
By the way, pay attention to the appModules folder in the NVDA source code. It contains many working modules to improve the accessibility of windows of various programs.

Good luck!
Oleksandr