View Issue Details

IDProjectCategoryView StatusLast Update
0002947MMW v4Otherpublic2008-09-22 19:16
Reporterjiri Assigned To 
PriorityurgentSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version3.0 
Fixed in Version3.1 
Summary0002947: Make MM accessible to blind users
DescriptionSince the lists and trees we use in MM are based on non-standard component, these parts aren't prepared to be used by screen-readers or some other special applications. This should be resolved if possible.
TagsNo tags attached.
Fixed in build1186

Activities

jiri

2007-03-27 09:56

administrator   ~0008899

Marco Zehe [marco.zehe at googlemail.com] gave us a detailed description of how to implement this using his code. Here is a complete description from him:

Hi Jiri,
 
here are the steps:
1. In the interface uses clause, change the first line this way:
 
uses
Windows,
{$ifndef COMPILER_10_UP}
MSAAIntf, // MSAA support for Delphi up to 2005
{$else}
oleacc, // MSAA support in Delphi 2006 or higher
{$endif COMPILE_10_UP}
Messages, SysUtils, Classes, Graphics, Controls, Forms, ImgList, ActiveX, StdCtrls, Menus, Printers,
 
 
2. In TBaseVirtualTree, in the private section, right above the "// common events" line, add:
 
// MSAA support
FAccessible: IAccessible; // The IAccessible interface to the window itself.
FAccessibleItem: IAccessible; // The IAccessible to the item that currently has focus.
FAccessibleName: string; // The name the window is given for screen readers.
 
 
3. Further down, below the procedure WMGetDlgCode, insert:
 
procedure WMGetObject(var Message: TMessage); message WM_GETOBJECT;
 
4. Further down, in the public section, above the Property CheckImages, insert:
 
property Accessible: IAccessible read FAccessible write FAccessible;
property AccessibleItem: IAccessible read FAccessibleItem write FAccessibleItem;
property AccessibleName: string read FAccessibleName write FAccessibleName;
 
5. further down, in the class TVirtualSTringTree, in the published section, add:
 
property AccessibleName;
 
6. In the implementation section, add the unit
VTAccessibilityFactory
to the uses clause, right after StdActns.
 
7. Above the TBaseVirtualTree.WMHScroll method, insert the method implementation:
 
procedure TBaseVirtualTree.WMGetObject(var Message: TMessage);
 
begin
  // Create the IAccessibles for the tree view and tree view items, if necessary.
  if FAccessible = nil then
    FAccessible := GetAccessibilityFactory.CreateIAccessible(Self);
  if FAccessibleItem = nil then
    FAccessibleItem := GetAccessibilityFactory.CreateIAccessible(Self);
 
  if Cardinal(Message.LParam) = OBJID_CLIENT then
    if Assigned(Accessible) then
      Message.Result := LresultFromObject(IID_IAccessible, Message.WParam, FAccessible)
    else
      Message.Result := 0;
end;
 
//----------------------------------------------------------------------------------------------------------------------
 
8. Now, we need to add a few NotifyWinEvent calls to some of the Doxxx-Functions for certain events. They are always inserted at the very bottom of the method, right above the closing end;:
 
a) TBaseVirtualTree.DoChecked,
NotifyWinEvent(EVENT_OBJECT_STATECHANGE, Handle, OBJID_CLIENT, CHILDID_SELF);
 
b) TBaseVirtualTre.DoCollapsed:
NotifyWinEvent(EVENT_OBJECT_STATECHANGE, Handle, OBJID_CLIENT, CHILDID_SELF);
 
c) TBaseVirtualTree.DoExpanded:
NotifyWinEvent(EVENT_OBJECT_STATECHANGE, Handle, OBJID_CLIENT, CHILDID_SELF);
 
d) TBaseVirtualTree.DoFocusChange:
NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, Handle, OBJID_CLIENT, CHILDID_SELF);
NotifyWinEvent(EVENT_OBJECT_NAMECHANGE, Handle, OBJID_CLIENT, CHILDID_SELF);
NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, Handle, OBJID_CLIENT, CHILDID_SELF);
NotifyWinEvent(EVENT_OBJECT_STATECHANGE, Handle, OBJID_CLIENT, CHILDID_SELF);
NotifyWinEvent(EVENT_OBJECT_SELECTION, Handle, OBJID_CLIENT, CHILDID_SELF);
NotifyWinEvent(EVENT_OBJECT_FOCUS, Handle, OBJID_CLIENT, CHILDID_SELF);
 
e) TBaseVirtualTree.MainColumnChanged:
NotifyWinEvent(EVENT_OBJECT_NAMECHANGE, Handle, OBJID_CLIENT, CHILDID_SELF);
 
f) TCustomVirtualStringTree.DoNewText:
NotifyWinEvent(EVENT_OBJECT_NAMECHANGE, Handle, OBJID_CLIENT, CHILDID_SELF);
NotifyWinEvent(EVENT_OBJECT_FOCUS, Handle, OBJID_CLIENT, CHILDID_SELF);
 
9. Optionally, you can add the following to VirtualTreesReg.pas, to make the AccessibleName property show up in Object Inspector:
Change line:
'Hint*', 'On*Hint*', 'On*Help*']);
to
 ['AccessibleName', 'Hint*', 'On*Hint*', 'On*Help*']);
 
That's it!
 
I'm attaching three units:
1. VTAccessibilityFactory.pas - is used by VirtualTrees.pas after the above changes and manages all IAccessibles and provides the right one for each instance.
2. VTAccessibility.pas - Provides IAccessibles for the tree itself (where AccessibleName is given to tell the screen reader what tree this is), AccessibleItem for single nodes, AccessibleMultiColumnItem for multi-column nodes. This should cover most usage scenarios out of the box already. If I understood you correctly, the only place you actually use images is for denoting whether an item in the main navigation pane is an album, artist etc. Since the nodes are already categorized usually, this is a piece of information not essential.
So the first step should be to integrate the above changes and the VTAccessibility unit in the project and see how it goes.
 
3. I also include the MSAAIntf.pas if you're using a version of Delphi earlier than 2006. I tested it with Delphi 5, and it works great.
 
I hope this makes it clear what would be needed!
 
Let me know how it goes!
 
Regards,
Marco

jiri

2007-03-27 10:01

administrator   ~0008900

The files mentioned by Marco are uploaded to FTP. Additionally, some more things should be done when we implement this:

A. AccessibleName property has been added to give each tree a meaningful name. We should fill them in, preferrably reusing some existing strings whenever possible (or use some common strings in some cases, like 'list' or 'tree'). These should be also localized, but .po tools should take care of this automatically.

B. ImageIndexes is exactly what you guessed: Within any particular tree, provide me with the index numbers and their meanings, and I'll adjust a case statement. This would be in the unit to include in your project.
  I.e. we probably provide Marco with a list of icons in the main tree, for other VT instances it shouldn't be necessary.

jiri

2007-03-27 10:15

administrator   ~0008902

Btw, I assigned this issue Urgent priority, but I don't consider it _that_ urgent, in case some problems will arise, just let me know and we can discuss deferring this issue.

petr

2008-09-22 19:16

developer   ~0014634

Will be in 1186