[Lazarus] LCL and Lazarus Accessibility - restarting the discussion

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

[Lazarus] LCL and Lazarus Accessibility - restarting the discussion

Free Pascal - Lazarus mailing list
Hello there!

My name is Marco, I am new to this list and new to Free Pascal and Lazarus. I have previously been involved with Delphi. I am, among other things, responsible for the accessibility implementation in TVirtualStringTree, which I made in 2007.

I am interested in restarting an effort to make the LCL components and Lazarus itself more accessible to screen reader users. There are a lot of things that work, but unfortunately a lot that don't yet, and some assumptions about current implementations/values aren't up to what accessibility actually requires. An example: The way AccessibleDescription is mapped on different platforms, is creative, but not always correct. :-)

I wanted to get started with this issue: https://bugs.freepascal.org/view.php?id=24135, TBitBtn not exposing its text as the Accessible Name. This is the primary information NVDA and other screen readers on Windows use to speak what a button does. In LCL, there is currently no equivalent, AccDescription and AccValue are being used interchangeably for some of the derived classes, but that is actually not so correct. For most standard controls, the Caption property maps, which is correct.

For TBitBtn, the attempt to set the window text failed because of text duplication. Question: Have you tried to set the text as the window title in the parameters in TWin32WSBitBtn.CreateHandle instead? I am blind myself, so cannot say if that would have any negative visual side effects, or if this is even supported.

If this does not work, which would be surprising since in Delphi, TBitBtn's caption does get exposed to screen readers by default, the only other option we have is to create a dynamic Accessibility Annotation through OLE COM. A simple example is here on the Microsoft Docs page: https://docs.microsoft.com/en-us/windows/win32/winauto/using-direct-annotation.
Only in our case, we would set the AccName property to the caption upon creation, or the text each time TWin32WSBitBtn.SetText is called. The way you draw the text is not being picked up by screen readers or the Microsoft accessibility proxy that gets created automatically. But with the above method, we could override this in a simple enough fashion without having to implement the whole IAccessible interface, or - God forbid - UI Automation, Microsoft's newer and much more complicated accessibility APIs.


Second: I then looked at this other issue about role inconsistencies: https://bugs.freepascal.org/view.php?id=26910. I currently do not yet understand how the LCLAccessibilityRoles are mapped to Win32 equivalents in the first place. I see some mappings for COCOA, QT4 and QT5, and others, but not Win32. For Win32, I see only empty class procedure definitions for the various properties, so I must assume all others are so far derived from the CreateWindow calls with the proper class names. What I do not see, as stated in that original report, is that everything is an ANIMATION role. So something must have changed already but not documented in that issue.

In any case, the above example by Microsoft provides a method to annotate custom drawn components to become accessible, too. There should be a default mapping for roles in place for Win32, the caption should be mapped to the name in most cases, and a hint, if present, or a tooltip, to AccDescription. For edits, as discussed somewhere on a forum, which have an associated TLabel or TStaticText, the AccName would have to be that TLabel's or TStaticText's caption. The association would have to be through TLabel's or TStaticText's FocusControl property, don't know if TEdit and similar support a reverse lookup yet, e. g. if they're being focus-controlled by some other component. But that would be the way forward.

For some components like list views or tree views, some of the more advanced mappings described here might have to take place: https://docs.microsoft.com/en-us/windows/win32/winauto/value-map-annotation.

In any case, this requires the use of COM. Don't know if that is standard in the LCL yet. The trigger is usually that an accessibility client sends a WM_GETOBJECT message to a control to get its accessible information. Some, like TBitBtn, already expose an accessible object, some, like the AutoComplete list in the Components List of the Lazarus IDE, do not. They appear as a generic window with plain text.

I would love to work on this, but would definitely need some guidance. For one: How are roles mapped on Win32, if at all yet?
And second: Is there any sample code yet that I could use to get up and running with COM quickly in the LCL?

Thank you for reading, and sorry for the long read!

Marco
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] LCL and Lazarus Accessibility - restarting the discussion

Free Pascal - Lazarus mailing list
Marco (and others)

I have been working on implementing Accessibility for Cocoa and Qt5.
Mostly I have been working in the lcl/interfaces/cocoa and
lcl/interfaces/qt5 directories creating the widget level plumbing needed
to interface with TLazAccessibleObject.

However, I have made a few fixes and changes to TLazAccessibleObject as
well.

I have fixed access to the child tree so that it is actually dataobject
sorted so that the search functions work.

And I have added a accessibilityName field to work with
accessibilityDescription, accessibilityRole, and accessibilityValue.  In
Cocoa this matches the accessibile Title and in qt it matches
accessibile Name.  Both Qt and Cocoa have an accessibleDescription field
but it does not map well to the laz accessibleDescription which is being
used the same way the Qt and Cocoa use the Name/Title field.

My Cocoa implementation is well developed and gives us access to all
parts of our app that isn't custom (though I am able to add our custom
objects as well - just haven't got all of them yet).

The Qt5 implementation is fairly basic yet.  It does all native controls
and also a base implemenation of TCustomTreeView.

I intend to clean up what I currently have and submit as a patch within
the next weeks.

David Jenkins

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] LCL and Lazarus Accessibility - restarting the discussion

Free Pascal - Lazarus mailing list
Hi David!

Wow, that sounds exciting! Look forward to your patch.

I did some digging, and found that on Windows, TTreeView does not create any handles at all yet. It would require at least some basics there, or even accessibility properties, but I am still hoping we can avoid what I had to do for TVirtualStringTree in 2007, implementing literally two IAccessible interfaces, one for tree, one for the focused tree item. That all was managed by a singleton class instance, and juggled quite a bit. Pretty unreliable, so I hope we can make it better in TTreeView for the LCL.

Right now, however, I don’t even know where to start yet to implement this. There is a unit in the Win32 folder, but nothing in there besides the comments. And from what it sounds like, it makes sense to wait for your patch so I, or we, can then build on that and make the Windows implementations better.

Marco

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] LCL and Lazarus Accessibility - restarting the discussion

Free Pascal - Lazarus mailing list


On 3/5/21 10:44 AM, Marco Zehe via lazarus wrote:

> Hi David!
>
> Wow, that sounds exciting! Look forward to your patch.
>
> I did some digging, and found that on Windows, TTreeView does not create any handles at all yet. It would require at least some basics there, or even accessibility properties, but I am still hoping we can avoid what I had to do for TVirtualStringTree in 2007, implementing literally two IAccessible interfaces, one for tree, one for the focused tree item. That all was managed by a singleton class instance, and juggled quite a bit. Pretty unreliable, so I hope we can make it better in TTreeView for the LCL.
>
> Right now, however, I don’t even know where to start yet to implement this. There is a unit in the Win32 folder, but nothing in there besides the comments. And from what it sounds like, it makes sense to wait for your patch so I, or we, can then build on that and make the Windows implementations better.
>
> Marco
>

For any tree type objects that I have dealt with (both LCL and custom) I
have created Ax objects for the tree and Ax objects for the items as
well.  And in cocoa I had to create an additional layer: Tree/Row/Item
in Row.

A couple of deficiencies that I have run across with the LCL
accessibility layer are

1) No notification capability

both Cocoa and Qt include functionality to send notifications to Ax
Clients to let them know of changes to the UI

2) TLazAccessibleObject handle creation doesn't sync well with
TLazAccessibleObject.Ownercontrol handle creation.

Both Cocoa and Qt include accessibilty support in their base widgets
that can be leveraged as TlazAccessibileObject handles.  But
TLazAccessibleObject will request a handle before the associated
TWinControl has handleallocated and doesn't know to retry for a handle
after the TWinControl get's its handle.

It would be good to include a path where TLazAccessibleObject handle is
requested after the TWinControl.Handle is created.


I will note that reading the comments surrounding the
TLazAccessibleObject code in Controls and control.inc are important.  I
made a couple of bad assumptions about how the code worked before I read
all the comments.

The first was that TLazAccessibleObject.Children objects are not meant
for TControl or TWinControl objects.  They are only for visual items
that don't have a TControl or TWinControl object.  E.g. row items in a
tree view.

And the difference in getting children by either using the iterator or
doing First / Next.  The iterator returns the objects in the child tree
only.  First / Next will get the objects from the child tree but also
any TControls that are in the ownercontrol.Controls() array.  The latter
allows code to find ALL the children - visual only and TControl objects.

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] LCL and Lazarus Accessibility - restarting the discussion

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
My accessiblity work for Cocoa/Qt5 has been submitted as a patch in
bugtracker 38603

On 3/5/21 10:44 AM, Marco Zehe via lazarus wrote:

> Hi David!
>
> Wow, that sounds exciting! Look forward to your patch.
>
> I did some digging, and found that on Windows, TTreeView does not create any handles at all yet. It would require at least some basics there, or even accessibility properties, but I am still hoping we can avoid what I had to do for TVirtualStringTree in 2007, implementing literally two IAccessible interfaces, one for tree, one for the focused tree item. That all was managed by a singleton class instance, and juggled quite a bit. Pretty unreliable, so I hope we can make it better in TTreeView for the LCL.
>
> Right now, however, I don’t even know where to start yet to implement this. There is a unit in the Win32 folder, but nothing in there besides the comments. And from what it sounds like, it makes sense to wait for your patch so I, or we, can then build on that and make the Windows implementations better.
>
> Marco
>

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus