View Issue Details

IDProjectCategoryView StatusLast Update
0038604LazarusLCLpublic2021-05-03 15:06
ReporterDavid Jenkins Assigned ToZeljan Rikalo  
PrioritynormalSeverityminorReproducibilityhave not tried
Status assignedResolutionopen 
Summary0038604: Implement extend LCL TLazAccessibleObject accessibility functionality for Qt5 widgetsets.
Descriptionaccessiblity_qt5.patch.

Like Cocoa, Qt5 has existing accessiblity implementations for the native Qt5 widgets. However, unlike Cocoa, the functionality isn't part of the widget itself but is done through interfaces attached to the widget. You can query the widget for it's accessiblity interface but cannot directly set it through the widget (must be done through a factory). Also the Qt/LCL interface is such that functions cannot be directly overridden like they can in Cocoa.

I have added new code to the cbindings for cocoa and Qt56.pas that provides access to the base accessiblity interfaces. And creates a new qt object qlclaccessiblitywidget which is an interface that allows hooking most of the accessiblity functions.

Backing is provided to TLazAccessibleObject by way of a TQtAccessibleObject(TObject) which points to a qlclaccessibilitywidget.

Like cocoa accessiblity is enabled in qt5 and code has been added to respond to TLazAccessibleObject.GetHandle requests.

I haven't had the time to do as much work on the Qt5 implementation as the Cocoa. There is no QT5_ACCESSIBLITY_ENABLE define to turn on and off accessibility. And the TQtAccessibleObject code has been placed in qtwidgets.pas instead of being separated out into it's own qtaccessibility.pas unit.
TagsNo tags attached.
Fixed in Revision64920
LazTarget-
WidgetsetQT5
Attached Files

Relationships

parent of 0038603 resolvedDmitry Boyarintsev Fix/extend LCL TLazAccessibleObject 

Activities

Dmitry Boyarintsev

2021-03-08 23:05

developer   ~0129517

accessibility_qt5.patch (42,446 bytes)   
Index: lcl/interfaces/qt5/cbindings/src/chandles.h
===================================================================
--- lcl/interfaces/qt5/cbindings/src/chandles.h	(revision 64768)
+++ lcl/interfaces/qt5/cbindings/src/chandles.h	(working copy)
@@ -519,4 +519,9 @@
 typedef struct QCalendarWidget__ { PTRINT dummy; } *QCalendarWidgetH;
 typedef struct QFileSystemWatcher_hook__ { PTRINT dummy; } *QFileSystemWatcher_hookH;
 typedef struct QInputMethodQueryEvent__ { PTRINT dummy; } *QInputMethodQueryEventH;
+
+typedef struct QAccessibleEvent__ { PTRINT dummy; } *QAccessibleEventH;
+typedef struct QAccessibleInterface__ { PTRINT dummy; } *QAccessibleInterfaceH;
+typedef struct QAccessibleWidget__ { PTRINT dummy; }  *QAccessibleWidgetH;
+typedef struct QLCLAccessibleWidget__ { PTRINT dummy; }  *QLCLAccessibleWidgetH;
 #endif
Index: lcl/interfaces/qt5/qt56.pas
===================================================================
--- lcl/interfaces/qt5/qt56.pas	(revision 64768)
+++ lcl/interfaces/qt5/qt56.pas	(working copy)
@@ -153,6 +153,10 @@
   Q_PID = type int64;
 {$ENDIF}
 
+QAccessibleEventH = class(TObject) end;
+QAccessibleInterfaceH = class(TObject) end;
+  QAccessibleWidgetH = class(QAccessibleInterfaceH) end;
+    QLCLAccessibleWidgetH = class(QAccessibleWidgetH) end;
 QAbstractNativeEventFilterH = class(TObject) end;
 QAuthenticatorH = class(TObject) end;
 QBackingStoreH = class(TObject) end;
@@ -14704,7 +14708,298 @@
 function QAuthenticator_isNull(handle: QAuthenticatorH): Boolean; cdecl; external Qt5PasLib name 'QAuthenticator_isNull';
 procedure QAuthenticator_detach(handle: QAuthenticatorH); cdecl; external Qt5PasLib name 'QAuthenticator_detach';
 
+type
+  QAccessibleEvent = ( // QAccessible::Event
+    QAccessibleSoundPlayed          = $0001,
+    QAccessibleAlert                = $0002,
+    QAccessibleForegroundChanged    = $0003,
+    QAccessibleMenuStart            = $0004,
+    QAccessibleMenuEnd              = $0005,
+    QAccessiblePopupMenuStart       = $0006,
+    QAccessiblePopupMenuEnd         = $0007,
+    QAccessibleContextHelpStart     = $000C,
+    QAccessibleContextHelpEnd       = $000D,
+    QAccessibleDragDropStart        = $000E,
+    QAccessibleDragDropEnd          = $000F,
+    QAccessibleDialogStart          = $0010,
+    QAccessibleDialogEnd            = $0011,
+    QAccessibleScrollingStart       = $0012,
+    QAccessibleScrollingEnd         = $0013,
 
+    QAccessibleMenuCommand          = $0018,
+
+    // Values from IAccessible2
+    QAccessibleActionChanged                    = $0101,
+    QAccessibleActiveDescendantChanged          = $0102,
+    QAccessibleAttributeChanged                 = $0103,
+    QAccessibleDocumentContentChanged           = $0104,
+    QAccessibleDocumentLoadComplete             = $0105,
+    QAccessibleDocumentLoadStopped              = $0106,
+    QAccessibleDocumentReload                   = $0107,
+    QAccessibleHyperlinkEndIndexChanged         = $0108,
+    QAccessibleHyperlinkNumberOfAnchorsChanged  = $0109,
+    QAccessibleHyperlinkSelectedLinkChanged     = $010A,
+    QAccessibleHypertextLinkActivated           = $010B,
+    QAccessibleHypertextLinkSelected            = $010C,
+    QAccessibleHyperlinkStartIndexChanged       = $010D,
+    QAccessibleHypertextChanged                 = $010E,
+    QAccessibleHypertextNLinksChanged           = $010F,
+    QAccessibleObjectAttributeChanged           = $0110,
+    QAccessiblePageChanged                      = $0111,
+    QAccessibleSectionChanged                   = $0112,
+    QAccessibleTableCaptionChanged              = $0113,
+    QAccessibleTableColumnDescriptionChanged    = $0114,
+    QAccessibleTableColumnHeaderChanged         = $0115,
+    QAccessibleTableModelChanged                = $0116,
+    QAccessibleTableRowDescriptionChanged       = $0117,
+    QAccessibleTableRowHeaderChanged            = $0118,
+    QAccessibleTableSummaryChanged              = $0119,
+    QAccessibleTextAttributeChanged             = $011A,
+    QAccessibleTextCaretMoved                   = $011B,
+    // TextChanged = $011C, is deprecated in IA2, use TextUpdated
+    QAccessibleTextColumnChanged                = $011D,
+    QAccessibleTextInserted                     = $011E,
+    QAccessibleTextRemoved                      = $011F,
+    QAccessibleTextUpdated                      = $0120,
+    QAccessibleTextSelectionChanged             = $0121,
+    QAccessibleVisibleDataChanged               = $0122,
+
+    QAccessibleObjectCreated        = $8000,
+    QAccessibleObjectDestroyed      = $8001,
+    QAccessibleObjectShow           = $8002,
+    QAccessibleObjectHide           = $8003,
+    QAccessibleObjectReorder        = $8004,
+    QAccessibleFocus                = $8005,
+    QAccessibleSelection            = $8006,
+    QAccessibleSelectionAdd         = $8007,
+    QAccessibleSelectionRemove      = $8008,
+    QAccessibleSelectionWithin      = $8009,
+    QAccessibleStateChanged         = $800A,
+    QAccessibleLocationChanged      = $800B,
+    QAccessibleNameChanged          = $800C,
+    QAccessibleDescriptionChanged   = $800D,
+    QAccessibleValueChanged         = $800E,
+    QAccessibleParentChanged        = $800F,
+    QAccessibleHelpChanged          = $80A0,
+    QAccessibleDefaultActionChanged = $80B0,
+    QAccessibleAcceleratorChanged   = $80C0 );
+
+type
+  QAccessibleState = Int64; // QAccessible::State
+const
+  QAccessibledisabled        = $0000000000000001; // used to be Unavailable
+  QAccessibleselected        = $0000000000000002;
+  QAccessiblefocusable       = $0000000000000004;
+  QAccessiblefocused         = $0000000000000008;
+  QAccessiblepressed         = $0000000000000010;
+  QAccessiblecheckable       = $0000000000000020;
+  QAccessiblechecked         = $0000000000000040;
+  QAccessiblecheckStateMixed = $0000000000000080; // used to be Mixed
+  QAccessiblereadOnly        = $0000000000000100;
+  QAccessiblehotTracked      = $0000000000000200;
+  QAccessibledefaultButton   = $0000000000000400;
+  QAccessibleexpanded        = $0000000000000800;
+  QAccessiblecollapsed       = $0000000000001000;
+  QAccessiblebusy            = $0000000000002000;
+  QAccessibleexpandable      = $0000000000004000;
+  QAccessiblemarqueed        = $0000000000008000;
+  QAccessibleanimated        = $0000000000010000;
+  QAccessibleinvisible       = $0000000000020000;
+  QAccessibleoffscreen       = $0000000000040000;
+  QAccessiblesizeable        = $0000000000080000;
+  QAccessiblemovable         = $0000000000100000;
+  QAccessibleselfVoicing     = $0000000000200000;
+  QAccessibleselectable      = $0000000000400000;
+  QAccessiblelinked          = $0000000000800000;
+  QAccessibletraversed       = $0000000001000000;
+  QAccessiblemultiSelectable = $0000000002000000;
+  QAccessibleextSelectable   = $0000000004000000;
+  QAccessiblepasswordEdit    = $0000000008000000; // used to be Protected
+  QAccessiblehasPopup        = $0000000010000000;
+  QAccessiblemodal           = $0000000020000000;
+  QAccessibleactive          = $0000000040000000;
+  QAccessibleinvalid         = $0000000080000000; // = defunct
+  QAccessibleeditable        = $0000000100000000;
+  QAccessiblemultiLine       = $0000000200000000;
+  QAccessibleselectableText  = $0000000400000000;
+  QAccessiblesupportsAutoCompletion = $00000008000000000;
+  QAccessiblesearchEdit      = $0000001000000000;
+
+type
+  QAccessibleRole = ( // QAccessible::Role
+    QAccessibleNoRole         = $00000000,
+    QAccessibleTitleBar       = $00000001,
+    QAccessibleMenuBar        = $00000002,
+    QAccessibleScrollBar      = $00000003,
+    QAccessibleGrip           = $00000004,
+    QAccessibleSound          = $00000005,
+    QAccessibleCursor         = $00000006,
+    QAccessibleCaret          = $00000007,
+    QAccessibleAlertMessage   = $00000008,
+    QAccessibleWindow         = $00000009,
+    QAccessibleClient         = $0000000A,
+    QAccessiblePopupMenu      = $0000000B,
+    QAccessibleMenuItem       = $0000000C,
+    QAccessibleToolTip        = $0000000D,
+    QAccessibleApplication    = $0000000E,
+    QAccessibleDocument       = $0000000F,
+    QAccessiblePane           = $00000010,
+    QAccessibleChart          = $00000011,
+    QAccessibleDialog         = $00000012,
+    QAccessibleBorder         = $00000013,
+    QAccessibleGrouping       = $00000014,
+    QAccessibleSeparator      = $00000015,
+    QAccessibleToolBar        = $00000016,
+    QAccessibleStatusBar      = $00000017,
+    QAccessibleTable          = $00000018,
+    QAccessibleColumnHeader   = $00000019,
+    QAccessibleRowHeader      = $0000001A,
+    QAccessibleColumn         = $0000001B,
+    QAccessibleRow            = $0000001C,
+    QAccessibleCell           = $0000001D,
+    QAccessibleLink           = $0000001E,
+    QAccessibleHelpBalloon    = $0000001F,
+    QAccessibleAssistant      = $00000020,
+    QAccessibleList           = $00000021,
+    QAccessibleListItem       = $00000022,
+    QAccessibleTree           = $00000023,
+    QAccessibleTreeItem       = $00000024,
+    QAccessiblePageTab        = $00000025,
+    QAccessiblePropertyPage   = $00000026,
+    QAccessibleIndicator      = $00000027,
+    QAccessibleGraphic        = $00000028,
+    QAccessibleStaticText     = $00000029,
+    QAccessibleEditableText   = $0000002A,  // Editable, selectable, etc.
+    QAccessibleButton         = $0000002B,
+    QAccessibleCheckBox       = $0000002C,
+    QAccessibleRadioButton    = $0000002D,
+    QAccessibleComboBox       = $0000002E,
+    QAccessibleProgressBar    = $00000030,
+    QAccessibleDial           = $00000031,
+    QAccessibleHotkeyField    = $00000032,
+    QAccessibleSlider         = $00000033,
+    QAccessibleSpinBox        = $00000034,
+    QAccessibleCanvas         = $00000035, // Diagram for MSAA
+    QAccessibleAnimation      = $00000036,
+    QAccessibleEquation       = $00000037,
+    QAccessibleButtonDropDown = $00000038, // The object represents a button that expands a grid.
+    QAccessibleButtonMenu     = $00000039,
+    QAccessibleButtonDropGrid = $0000003A,
+    QAccessibleWhitespace     = $0000003B, // The object represents blank space between other objects.
+    QAccessiblePageTabList    = $0000003C,
+    QAccessibleClock          = $0000003D,
+    QAccessibleSplitter       = $0000003E,
+    QAccessibleLayeredPane    = $00000080,
+    QAccessibleTerminal       = $00000081,
+    QAccessibleDesktop        = $00000082,
+    QAccessibleParagraph      = $00000083,
+    QAccessibleWebDocument    = $00000084,
+    QAccessibleSection        = $00000085,
+    QAccessibleColorChooser   = $00000404,
+    QAccessibleFooter         = $0000040E,
+    QAccessibleForm           = $00000410,
+    QAccessibleHeading        = $00000414,
+    QAccessibleNote           = $0000041B,
+    QAccessibleComplementaryContent = $0000042C,
+    QAccessibleUserRole       = $0000ffff );
+
+  
+  QAccessibleText =  (// QAccessible::Text
+    QAccessibleName         = 0,
+    QAccessibleDescription,
+    QAccessibleValue,
+    QAccessibleHelp,
+    QAccessibleAccelerator,
+    QAccessibleDebugDescription,
+    QAccessibleUserText     = $0000ffff );
+
+type
+  QAccessibleFlag = cardinal; // QAccessible::Flag
+const
+  QAccessibleLabel         = $00000001;
+  QAccessibleLabelled      = $00000002;
+  QAccessibleController    = $00000004;
+  QAccessibleControlled    = $00000008;
+  QAccessibleAllRelations  = $ffffffff;
+
+type
+  QAccessibleInterfaceType = ( // QAccessible::InterfaceType
+    QAccessibleTextInterface,
+    QAccessibleEditableTextInterface,
+    QAccessibleValueInterface,
+    QAccessibleActionInterface,
+    QAccessibleImageInterface,
+    QAccessibleTableInterface,
+    QAccessibleTableCellInterface );
+
+  QAccessibleTextBoundaryType = ( // QAccessible::TextBoundaryType
+    QAccessibleCharBoundary,
+    QAccessibleWordBoundary,
+    QAccessibleSentenceBoundary,
+    QAccessibleParagraphBoundary,
+    QAccessibleLineBoundary,
+    QAccessibleNoBoundary );
+
+QAccessibleId = cardinal;
+TInterfaceFactory = function(key: QStringH; obj: QObjectH): QAccessibleInterfaceH cdecl;
+
+// actionNames_Override returns a single string with comma separated action names
+QLCLAccessibleWidget_actionNames_Override = procedure (names: PWideString) of object cdecl;
+QLCLAccessibleWidget_child_Override = procedure (index: integer; out child: QAccessibleInterfaceH) of object cdecl;
+QLCLAccessibleWidget_childAt_Override = procedure (x: integer; y: integer; out child: QAccessibleInterfaceH) of object cdecl;
+QLCLAccessibleWidget_childCount_Override = procedure (count: PInteger) of object cdecl;
+QLCLAccessibleWidget_doAction_Override = procedure (actionName: PWideString) of object cdecl;
+QLCLAccessibleWidget_indexOfChild_Override = procedure (child: QAccessibleInterfaceH; index: PInteger) of object cdecl;
+QLCLAccessibleWidget_parent_Override = procedure (out parent: QAccessibleInterfaceH) of object cdecl;
+QLCLAccessibleWidget_rect_Override = procedure (left, top, width, height: PInteger) of object cdecl;
+QLCLAccessibleWidget_role_Override = procedure (out role: QAccessibleRole) of object cdecl;
+QLCLAccessibleWidget_state_Override = procedure (out state: QAccessibleState) of object cdecl;
+QLCLAccessibleWidget_text_Override = procedure (text: QAccessibleText; result: PWideString) of object cdecl;
+
+function QAccessible_accessibleInterface(uniqueId: QAccessibleId): QAccessibleInterfaceH; cdecl; external Qt5PasLib name 'QAccessible_accessibleInterface';
+procedure QAccessible_deleteAccessibleInterface(uniqueId: QAccessibleId); cdecl; external Qt5PasLib name 'QAccessible_deleteAccessibleInterface';
+procedure QAccessible_installFactory(factory: TInterfaceFactory); cdecl; external Qt5PasLib name 'QAccessible_installFactory';
+function QAccessible_isActive(): boolean; cdecl; external Qt5PasLib name 'QAccessible_isActive';
+function QAccessible_queryAccessibleInterface(object_: QObjectH): QAccessibleInterfaceH; cdecl; external Qt5PasLib name 'QAccessible_queryAccessibleInterface';
+function QAccessible_registerAccessibleInterface(iface: QAccessibleInterfaceH): QAccessibleId; cdecl; external Qt5PasLib name 'QAccessible_registerAccessibleInterface';
+procedure QAccessible_removeFactory(factory: TInterfaceFactory); cdecl; external Qt5PasLib name 'QAccessible_removeFactory';
+procedure QAccessible_setRootObject(object_: QObjectH); cdecl; external Qt5PasLib name 'QAccessible_setRootObject';
+function QAccessible_uniqueId(iface: QAccessibleInterfaceH): QAccessibleId; cdecl; external Qt5PasLib name 'QAccessible_uniqueId';
+procedure QAccessible_updateAccessibility(event: QAccessibleEvent); cdecl; external Qt5PasLib name 'QAccessible_updateAccessibility';
+
+function QAccessibleWidget_Create(o: QWidgetH; r: QAccessibleRole = QAccessibleClient; name: PWideString = nil): QAccessibleWidgetH; cdecl; external Qt5PasLib name 'QAccessibleWidget_Create';
+procedure QAccessibleWidget_Destroy(handle: QAccessibleWidgetH); cdecl; external Qt5PasLib name 'QAccessibleWidget_Destroy';
+function QAccessibleWidget_isValid(handle: QAccessibleWidgetH): boolean; cdecl; external Qt5PasLib name 'QAccessibleWidget_isValid';
+function QAccessibleWidget_window(handle: QAccessibleWidgetH): QWindowH; cdecl; external Qt5PasLib name 'QAccessibleWidget_window';
+function QAccessibleWidget_childCount(handle: QAccessibleWidgetH): integer; cdecl; external Qt5PasLib name 'QAccessibleWidget_childCount';
+function QAccessibleWidget_indexOfChild(handle: QAccessibleWidgetH; child: QAccessibleInterfaceH): integer; cdecl; external Qt5PasLib name 'QAccessibleWidget_indexOfChild';
+function QAccessibleWidget_focusChild(handle: QAccessibleWidgetH): QAccessibleInterfaceH; cdecl; external Qt5PasLib name 'QAccessibleWidget_focusChild';
+procedure QAccessibleWidget_rect(handle: QAccessibleWidgetH; retval: PRect); cdecl; external Qt5PasLib name 'QAccessibleWidget_rect';
+function QAccessibleWidget_parent(handle: QAccessibleWidgetH): QAccessibleInterfaceH; cdecl; external Qt5PasLib name 'QAccessibleWidget_parent';
+function QAccessibleWidget_child(handle: QAccessibleWidgetH; index: integer): QAccessibleInterfaceH; cdecl; external Qt5PasLib name 'QAccessibleWidget_child';
+procedure QAccessibleWidget_text(handle: QAccessibleWidgetH; retval: PWideString; t: QAccessibleText); cdecl; external Qt5PasLib name 'QAccessibleWidget_text';
+function QAccessibleWidget_role(handle: QAccessibleWidgetH): QAccessibleRole; cdecl; external Qt5PasLib name 'QAccessibleWidget_role';
+function QAccessibleWidget_state(handle: QAccessibleWidgetH): QAccessibleState; cdecl; external Qt5PasLib name 'QAccessibleWidget_state';
+procedure QAccessibleWidget_actionNames(handle: QAccessibleWidgetH; retval: QStringListH); cdecl; external Qt5PasLib name 'QAccessibleWidget_actionNames';
+procedure QAccessibleWidget_doAction(handle: QAccessibleWidgetH; actionName: PWideString); cdecl; external Qt5PasLib name 'QAccessibleWidget_doAction';
+function QAccessibleWidget_widget(handle: QAccessibleWidgetH): QWidgetH; cdecl; external Qt5PasLib name 'QAccessibleWidget_widget';
+function QAccessibleWidget_parentObject(handle: QAccessibleWidgetH): QObjectH; cdecl; external Qt5PasLib name 'QAccessibleWidget_parentObject';
+
+function QLCLAccessibleWidget_Create(o: QWidgetH; r: QAccessibleRole; name: PWideString): QLCLAccessibleWidgetH; cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_Create';
+procedure QLCLAccessibleWidget_Destroy(handle: QLCLAccessibleWidgetH); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_Destroy';
+procedure QLCLAccessibleWidget_override_actionNames(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_actionNames_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_actionNames';
+procedure QLCLAccessibleWidget_override_child(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_child_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_child';
+procedure QLCLAccessibleWidget_override_childAt(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_childAt_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_childAt';
+procedure QLCLAccessibleWidget_override_childCount(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_childCount_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_childCount';
+procedure QLCLAccessibleWidget_override_doAction(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_doAction_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_doAction';
+procedure QLCLAccessibleWidget_override_indexOfChild(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_indexOfChild_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_child';
+procedure QLCLAccessibleWidget_override_parent(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_parent_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_parent';
+procedure QLCLAccessibleWidget_override_rect(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_rect_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_rect';
+procedure QLCLAccessibleWidget_override_role(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_role_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_role';
+procedure QLCLAccessibleWidget_override_state(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_state_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_state';
+procedure QLCLAccessibleWidget_override_text(handle: QLCLAccessibleWidgetH; hook: QLCLAccessibleWidget_text_Override); cdecl; external Qt5PasLib name 'QLCLAccessibleWidget_override_text';
+   
+
 function QCoreApplication_hook_Create(handle: QObjectH): QCoreApplication_hookH; cdecl; external Qt5PasLib name 'QCoreApplication_hook_Create';
 procedure QCoreApplication_hook_Destroy(handle: QCoreApplication_hookH); cdecl; external Qt5PasLib name 'QCoreApplication_hook_Destroy'; 
 procedure QCoreApplication_hook_hook_aboutToQuit(handle: QCoreApplication_hookH; hook: QCoreApplication_aboutToQuit_Event); cdecl; external Qt5PasLib name 'QCoreApplication_hook_hook_aboutToQuit';
Index: lcl/interfaces/qt5/qtobject.inc
===================================================================
--- lcl/interfaces/qt5/qtobject.inc	(revision 64768)
+++ lcl/interfaces/qt5/qtobject.inc	(working copy)
@@ -1284,6 +1284,7 @@
     lcTextHint: Result := LCL_CAPABILITY_YES;
     lcNativeTaskDialog: Result := {$ifdef MSWINDOWS} LCL_CAPABILITY_NO {$else} LCL_CAPABILITY_YES {$endif};
     lcAllowChildControlsInNativeControls: Result := LCL_CAPABILITY_YES;
+    lcAccessibilitySupport: Result := LCL_CAPABILITY_YES
   else
     Result := inherited GetLCLCapability(ACapability);
   end;
Index: lcl/interfaces/qt5/qtwidgets.pas
===================================================================
--- lcl/interfaces/qt5/qtwidgets.pas	(revision 64768)
+++ lcl/interfaces/qt5/qtwidgets.pas	(working copy)
@@ -167,6 +167,7 @@
   public
     constructor Create(const AWinControl: TWinControl; const AParams: TCreateParams); virtual; overload;
     constructor CreateFrom(const AWinControl: TWinControl; AWidget: QWidgetH); virtual;
+    procedure InitializeAccessibility; virtual;
     procedure InitializeWidget; virtual;
     procedure DeInitializeWidget; virtual;
     procedure RecreateWidget;
@@ -433,6 +434,7 @@
     function getViewOrigin: TPoint;
     function viewportWidget: QWidgetH;
     function horizontalScrollBar: TQtScrollBar;
+    procedure InitializeAccessibility; override;
     function verticalScrollBar: TQtScrollBar;
     procedure setFocusPolicy(const APolicy: QtFocusPolicy); override;
     procedure setHorizontalScrollBar(AScrollBar: TQtScrollBar);
@@ -465,6 +467,7 @@
   public
     function CanAdjustClientRectOnResize: Boolean; override;
     function cornerWidget: TQtWidget;
+    procedure InitializeAccessibility; override;
     function MapToGlobal(APt: TPoint; const AWithScrollOffset: Boolean = False): TPoint; override;
     function MapFromGlobal(APt: TPoint; const AWithScrollOffset: Boolean = False): TPoint; override;
     function viewport: TQtViewPort;
@@ -1956,6 +1959,68 @@
 
   QtCheckStateRole = Ord(QtUserRole) + 1;
   QtListViewOwnerDataRole = Ord(QtUserRole) + 2;
+
+const
+  QtAXObjectName           = 'AxObject';
+  axActionNamePress        = 'Press';
+  axActionNameIncrease     = 'Increase';
+  axActionNameDecrease     = 'Decrease';
+  axActionNameShowMenu     = 'ShowMenu';
+  axActionNameSetFocus     = 'SetFocus';
+  axActionNameToggle       = 'Toggle';
+  axActionNameScrolLeft    = 'Scroll Left';
+  axActionNameScrollRight  = 'Scroll Right';
+  axActionNameScrollUp     = 'Scroll Up';
+  axActionNameScrollDown   = 'Scroll Down';
+  axActionNamePreviousPage = 'Previous Page';
+  axActionNameNextPage     = 'Next Page';
+
+function LazRoleToQtRole(ALazRole: TLazAccessibilityRole): QAccessibleRole;
+function CreateAccessibleName(AObject: TLazAccessibleObject): String;
+function QtAxFactory(name: QStringH; obj: QObjectH): QAccessibleInterfaceH; cdecl;
+
+type
+  TQtAccessibleObject = class(TObject)
+  private
+    FLazAxObject: TLazAccessibleObject;
+    FAxWidget: QWidgetH;
+  public
+    constructor Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH);
+    destructor Destroy; override;
+    procedure actionNamesOverride(names: PWideString) cdecl; virtual; abstract;
+    procedure childOverride(index: integer; out child:  QAccessibleInterfaceH) cdecl; virtual;
+    procedure childAtOverride(x: integer; y: integer; out child: QAccessibleInterfaceH) cdecl; virtual; abstract;
+    procedure childCountOverride(count: PInteger) cdecl; virtual;
+    procedure doActionOverride(name: PWideString) cdecl; virtual; abstract;
+    procedure indexOfChildOverride() cdecl; virtual; abstract;
+    procedure parentOverride(out parent: QAccessibleInterfaceH) cdecl; virtual; abstract;
+    procedure rectOverride(left, top, width, height: PInteger) cdecl; virtual; abstract;
+    procedure roleOverride(out role: QAccessibleRole) cdecl; virtual;
+    procedure stateOverride(out state: QAccessibleState) cdecl; virtual; abstract;
+    procedure textOverride(text: QAccessibleText; retval: PWideString) cdecl; virtual;
+    function isVisible: Boolean; virtual;
+  end;
+
+  TQtAccessibleTree = class(TQtAccessibleObject)
+  public
+    constructor Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH);
+    procedure childOverride(index: integer; out child:  QAccessibleInterfaceH) cdecl; virtual;
+    procedure childCountOverride(count: PInteger) cdecl; virtual;
+  end;
+
+  TQtAccessibleTreeRow = class(TQtAccessibleObject)
+  public
+    constructor Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH);
+    procedure actionNamesOverride(names: PWideString)cdecl; override;
+    procedure childCountOverride(count: PInteger)cdecl; override;
+    procedure doActionOverride(name: PWideString)cdecl; override;
+    procedure parentOverride(out parent: QAccessibleInterfaceH)cdecl; override;
+    procedure rectOverride(left, top, width, height: PInteger) cdecl; override;
+    procedure roleOverride(out role: QAccessibleRole)cdecl; override;
+    procedure textOverride(text: QAccessibleText; retval: PWideString) cdecl; override;
+    function isVisible: Boolean; override;
+  end;
+
 implementation
 
 uses
@@ -2003,6 +2068,7 @@
 
   FParams := AParams;
   InitializeWidget;
+  InitializeAccessibility;
 end;
 
 constructor TQtWidget.CreateFrom(const AWinControl: TWinControl;
@@ -2037,8 +2103,30 @@
 
   // Set mouse move messages policy
   QWidget_setMouseTracking(Widget, True);
+
+  InitializeAccessibility;
 end;
 
+procedure TQtWidget.InitializeAccessibility;
+var
+  WStr: WideString;
+  LCLAxObject: TLazAccessibleObject;
+begin
+  if Assigned(LCLObject) then begin
+    LCLAxObject := LCLObject.GetAccessibleObject;
+    if (LCLAxObject <> nil) then begin
+      WStr := GetUtf8String(CreateAccessibleName(LCLAxObject));
+      QWidget_setAccessibleName(Widget, @WStr);
+      WStr := GetUtf8String(LCLAxObject.AccessibleDescription);
+      QWidget_setAccessibleDescription(Widget, @WStr);
+     end;
+  end
+  else begin
+    WStr := GetUtf8String(ClassName);
+    QWidget_setAccessibleName(Widget, @WStr);
+  end;
+end;
+
 procedure TQtWidget.InitializeWidget;
 begin
   FInResizeEvent := False;
@@ -2201,6 +2289,7 @@
   FParams.WndParent := HwndFromWidgetH(Parent);
   DeinitializeWidget;
   InitializeWidget;
+  InitializeAccessibility;
 end;
 
 procedure TQtWidget.DestroyNotify(AWidget: TQtWidget);
@@ -16278,6 +16367,7 @@
   Palette.ForceColor := False;
   setVisible(FVisible);
   QtWidgetSet.AddHandle(Self);
+  InitializeAccessibility;
 end;
 
 {$IFNDEF DARWIN}
@@ -17110,6 +17200,15 @@
   Result := FHScrollBar;
 end;
 
+procedure TQtAbstractScrollArea.InitializeAccessibility;
+var
+  WStr: WideString;
+begin
+  inherited InitializeAccessibility;
+  WStr := GetUtf8String(ClassName+':ViewPort');
+  QWidget_setAccessibleName(viewPortWidget, @WStr);
+end;
+
 {------------------------------------------------------------------------------
   Function: TQtAbstractScrollArea.verticalScrollbar
   Params:  None
@@ -17480,6 +17579,23 @@
   Result := inherited MapFromGlobal(APt);
 end;
 
+procedure TQtCustomControl.InitializeAccessibility;
+var
+  LCLAxObject: TLazAccessibleObject;
+begin
+  inherited InitializeAccessibility;
+  if (LCLObject <> nil) then begin
+    // TWinControl.Handle is still not set so can't do handle creation through LCLAxObject.CreateHandle
+    LCLAxObject :=  LCLObject.GetAccessibleObject;
+      if LCLAxObject.AccessibleRole = larTreeView then
+        LCLAxObject.Handle :=
+          HWND(TQtAccessibleTree.Create(LCLAxObject, Widget))
+      else
+        LCLAxObject.Handle :=
+          HWND(TQtAccessibleObject.Create(LCLAxObject, Widget));
+  end;
+end;
+
 {------------------------------------------------------------------------------
   Function: TQtCustomControl.setCornerWidget
   Params:  TQtWidget
@@ -19800,4 +19916,349 @@
   end;
 end;
 
+
+
+function LazRoleToQtRole(ALazRole: TLazAccessibilityRole): QAccessibleRole;
+begin
+  case ALazRole of
+    larIgnore: Result := QAccessibleClient;  // Qt follows ATSPI roles and doesn't have an ignore
+    larAnimation: Result := QAccessibleAnimation;
+    larButton: Result := QAccessibleButton;
+    larCell: Result := QAccessibleCell;
+    larChart: Result := QAccessibleChart;
+    larCheckBox: Result := QAccessibleCheckBox;
+    larClock: Result := QAccessibleClock;
+    larColorPicker: Result := QAccessibleColorChooser;
+    larColumn: Result := QAccessibleColumn;
+    larComboBox: Result := QAccessibleComboBox;
+    larDateField: Result := QAccessibleStaticText;
+    larGrid: Result := QAccessibleTable;
+    larGroup: Result := QAccessibleGrouping;
+    larImage: Result := QAccessibleGraphic;
+    larLabel: Result := QAccessibleStaticText;
+    larListBox: Result := QAccessibleList;
+    larListItem: Result := QAccessibleListItem;
+    larMenuBar: Result := QAccessibleMenuBar;
+    larMenuItem: Result := QAccessibleMenuItem;
+    larProgressIndicator: Result := QAccessibleProgressBar;
+    larRadioButton: Result := QAccessibleRadioButton;
+    larResizeGrip: Result := QAccessibleGrip;
+    larRow: Result := QAccessibleRow;
+    larScrollBar: Result := QAccessibleScrollBar;
+    larSpinner: Result := QAccessibleSpinBox;
+    larTabControl: Result := QAccessiblePageTab;
+    larText: Result := QAccessibleSTaticText;
+    larTextEditorMultiline: Result := QAccessibleEditableText;
+    larTextEditorSingleline: Result := QAccessibleEditableText;
+    larToolBar: Result := QAccessibleToolBar;
+    larToolBarButton: Result := QAccessibleButton;
+    larTrackBar: Result := QAccessibleSlider;
+    larTreeView: Result := QAccessibleTree;
+    larTreeItem: Result := QAccessibleTreeItem;
+    larWindow: Result := QAccessibleWindow;
+  else
+    // including larIgnore, larUnknown
+    Result := QAccessibleNoRole;
+  end;
+end;
+
+function CreateAccessibleName(AObject: TLazAccessibleObject): String;
+var
+  TargControl: TControl;
+  S: String;
+begin
+  S := '';
+  if Assigned(AObject) then begin
+    if AObject.AccessibleName <> '' then
+      S := AObject.AccessibleName;
+    if (S = '') and (AObject.OwnerControl <> nil) then begin
+      TargControl := AObject.OwnerControl;
+      S := TargControl.Caption;
+      if S = '' then
+        S := TargControl.Name;
+      if S = '' then
+        S := TargControl.ClassName;
+    end;
+  end;
+  Result := S;
+end;
+
+function LCLControlRectToQtScreenRect(ARect: TRect; AControl: TControl): TRect;
+var
+  Pt: TPoint;
+begin
+  Pt := AControl.ClientToScreen(ARect.TopLeft);
+  Result := Rect(Pt.X, Pt.Y, Pt.X + ARect.Width, Pt.Y + ARect.Height);
+end;
+
+function QtScreenPointToLCLControlPoint(APoint: TPoint; AControl: TControl): TPoint;
+begin
+  Result := AControl.ScreenToClient(APoint);
+end;
+
+function QtAxFactory(name: QStringH; obj: QObjectH): QAccessibleInterfaceH; cdecl;
+var
+  CreateLCLAccessibleInterface: Boolean;
+  H: HWND;
+  QtObj: TQtObject;
+  objName: string;
+  WStr: WideString;
+begin
+  Result := nil;
+  CreateLCLAccessibleInterface := False;
+  if QObject_isWidgetType(obj) then begin
+    QObject_objectName(obj, @WStr);
+    objName := UTF16ToUTF8(WStr);
+    if (objName = QtAXObjectName) then
+      CreateLCLAccessibleInterface := True
+    else begin
+      H := HwndFromWidgetH(QWidgeth(obj));
+      if (H <> 0) then begin
+        QtObj := TQtObject(H);
+        if (QtObj is TQtCustomControl) then
+          CreateLCLAccessibleInterface := True;
+      end
+    end
+  end;
+
+  if CreateLCLAccessibleInterface then begin
+    Result := QLCLAccessibleWidget_Create(QWidgetH(obj), QAccessibleClient, nil);
+  end
+  else
+    Result := nil;
+end;
+
+constructor TQtAccessibleObject.Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH);
+var
+  WStr: WideString;
+  AxInterface: QLCLAccessibleWidgetH;
+begin
+  inherited Create;
+  FLazAxObject := ALazAxObject;
+  if (AWidget = QWidgetH(0)) then begin
+    FAxWidget := QWidget_Create();
+    WStr := GetUtf8String(QtAXObjectName);
+    QObject_setObjectName(FAxWidget, @WStr);
+  end
+  else
+    FAxWidget := AWidget;
+
+  AxInterface := QLCLAccessibleWidgetH(QAccessible_queryAccessibleInterface(FAxWidget));
+  QLCLAccessibleWidget_override_child(AxInterface, @childOverride);
+  QLCLAccessibleWidget_override_childCount(AxInterface, @childCountOverride);
+  QLCLAccessibleWidget_override_role(AxInterface, @roleOverride);
+  QLCLAccessibleWidget_override_text(AxInterface, @textOverride);
+end;
+
+destructor TQtAccessibleObject.Destroy;
+var
+  WStr: WideString;
+  objName: string;
+begin
+  QObject_objectName(FAxWidget, @WStr);
+  objName := UTF16ToUTF8(WStr);
+  if (objName = QtAXObjectName) then
+    QObject_Destroy(FAxWidget);
+
+  inherited Destroy;
+end;
+
+procedure TQtAccessibleObject.childOverride(index: integer; out child:  QAccessibleInterfaceH) cdecl;
+var
+  childCount: Integer;
+  lclAxChild: TLazAccessibleObject;
+  qtAxObject: TQtAccessibleObject;
+begin
+  child := QAccessibleInterfaceH(0);
+  childCount := 0;
+  lclAxChild := FLazAxObject.GetFirstChildAccessibleObject;
+  while Assigned(lclAxChild) and (childCount < index) do begin
+    inc(ChildCount);
+    lclAxChild := FLazAxObject.GetNextChildAccessibleObject;
+  end;
+  if Assigned(lclAxChild) and (lclAxChild.Handle <> 0) then begin
+    qtAxObject := TQtAccessibleObject(lclAxChild.Handle);
+    child := QAccessible_queryAccessibleInterface(qtAxObject.FAxWidget);
+  end;
+end;
+
+procedure TQtAccessibleObject.childCountOverride(count: PInteger) cdecl;
+var
+  childCount: Integer;
+  lclAxChild: TLazAccessibleObject;
+begin
+  childCount := 0;
+  lclAxChild := FLazAxObject.GetFirstChildAccessibleObject;
+  while Assigned(lclAxChild) do begin
+    inc(ChildCount);
+    lclAxChild := FLazAxObject.GetNextChildAccessibleObject;
+  end;
+  count^ := childCount;
+end;
+
+procedure TQtAccessibleObject.roleOverride(out role: QAccessibleRole) cdecl;
+begin
+  if (FLazAxObject <> nil) then
+    role := LazRoleToQtRole(FLazAxObject.AccessibleRole)
+  else
+    role := QAccessibleNoRole;
+end;
+
+procedure TQtAccessibleObject.textOverride(text: QAccessibleText; retval: PWideString) cdecl;
+begin
+  case text of
+  QAccessibleName:
+      retval^ := GetUtf8String(CreateAccessibleName(FLazAxObject));
+  QAccessibleDescription:
+    retval^ := GetUtf8String(FLazAxObject.AccessibleDescription);
+  QAccessibleValue:
+    retval^ := GetUtf8String(FLazAxObject.AccessibleValue);
+  else
+   retval^ := GetUtf8String('');
+  end;
+end;
+
+function TQtAccessibleObject.isVisible: Boolean;
+begin
+  Result := FLazAxObject.OwnerControl.Visible;
+end;
+
+constructor TQtAccessibleTree.Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH);
+var
+  AxInterface: QLCLAccessibleWidgetH;
+begin
+  inherited Create(ALazAxObject, AWidget);
+
+  AxInterface := QLCLAccessibleWidgetH(QAccessible_queryAccessibleInterface(FAxWidget));
+  QLCLAccessibleWidget_override_child(AxInterface, @childOverride);
+  QLCLAccessibleWidget_override_childCount(AxInterface, @childCountOverride);
+end;
+
+procedure TQtAccessibleTree.childOverride(index: integer; out child:  QAccessibleInterfaceH); cdecl;
+var
+  ChildIndex: Integer;
+  LCLAxChild: TLazAccessibleObject;
+  RowAxObject: TQtAccessibleTreeRow;
+begin
+  child := QAccessibleInterfaceH(0);
+  ChildIndex := 0;
+  for LCLAxChild in FLazAxObject do begin
+    RowAxObject := TQtAccessibleTreeRow(LCLAxChild.Handle);
+    if RowAxObject.isVisible then begin
+      if ChildIndex = index then begin
+        child := QAccessible_queryAccessibleInterface(RowAxObject.FAxWidget);
+        Exit;
+      end;
+      Inc(ChildIndex);
+    end;
+  end;
+end;
+
+procedure TQtAccessibleTree.childCountOverride(count: PInteger); cdecl;
+var
+  Tree: TCustomTreeView;
+  TreeNode: TTreeNode;
+  ChildCount: Integer;
+begin
+  Tree := TCustomTreeView(FLazAxObject.OwnerControl);
+  ChildCount := 0;
+  TreeNode := Tree.Items.GetFirstVisibleNode;
+  while (TreeNode <> nil) do begin
+    Inc(ChildCount);
+    TreeNode := TreeNode.GetNextVisible;
+  end;
+  count^ := ChildCount;
+end;
+
+
+constructor TQtAccessibleTreeRow.Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH);
+var
+  AxInterface: QLCLAccessibleWidgetH;
+begin
+  inherited Create(ALazAxObject, AWidget);
+
+  AxInterface := QLCLAccessibleWidgetH(QAccessible_queryAccessibleInterface(FAxWidget));
+  QLCLAccessibleWidget_override_actionNames(AxInterface, @actionNamesOverride);
+  QLCLAccessibleWidget_override_child(AxInterface, nil);
+  QLCLAccessibleWidget_override_childAt(AxInterface, nil);
+  QLCLAccessibleWidget_override_childCount(AxInterface, @childCountOverride);
+  QLCLAccessibleWidget_override_doAction(AxInterface, @doActionOverride);
+  QLCLAccessibleWidget_override_parent(AxInterface, @parentOVerride);
+  QLCLAccessibleWidget_override_rect(AxInterface, @rectOverride);
+  QLCLAccessibleWidget_override_role(AxInterface, @roleOverride);
+  QLCLAccessibleWidget_override_text(AxInterface, @textOverride);
+end;
+
+procedure TQtAccessibleTreeRow.actionNamesOverride(names: PWideString)cdecl;
+begin
+  names^ := GetUtf8String(axActionNamePress); // Takes a comma separated string of actions
+end;
+
+procedure TQtAccessibleTreeRow.doActionOverride(name: PWideString)cdecl;
+var s: string;
+  TreeNode: TTreeNode;
+begin
+  s := UTF16ToUTF8(name^);
+  if s = axActionNamePress then begin
+    TreeNode := TTreeNode(FLazAxObject.DataObject);
+    TreeNode.TreeView.Select(TreeNode);
+  end;
+end;
+
+procedure TQtAccessibleTreeRow.childCountOverride(count: PInteger)cdecl;
+begin
+  count^ := 0;
+end;
+
+procedure TQtAccessibleTreeRow.parentOverride(out parent: QAccessibleInterfaceH)cdecl;
+begin
+  parent := QLCLAccessibleWidgetH(QAccessible_queryAccessibleInterface(
+     TQtAccessibleObject(FLazAxObject.Parent.Handle).FAxWidget));
+end;
+
+procedure TQtAccessibleTreeRow.rectOverride(left, top, width, height: PInteger)cdecl;
+var
+  TreeNode: TTreeNode;
+  NodeR: TRect;
+  R: TRect;
+begin
+  TreeNode := TTreeNode(FLazAxObject.DataObject);
+  NodeR := TreeNode.DisplayRect(False);
+  R := LCLControlRectToQtScreenRect(NodeR, TreeNode.TreeView);
+  left^ := R.Left;
+  top^ := R.Top;
+  width^ := R.Width;
+  height^ := R.Height;
+end;
+
+procedure TQtAccessibleTreeRow.roleOverride(out role: QAccessibleRole)cdecl;
+begin
+  role := QAccessibleTreeItem;
+end;
+
+procedure TQtAccessibleTreeRow.textOverride(text: QAccessibleText; retval: PWideString) cdecl;
+var
+  TreeNode: TTreeNode;
+begin
+  TreeNode := TTreeNode(FLazAxObject.DataObject);
+  case text of
+    QAccessibleName, QAccessibleDescription, QAccessibleValue:
+      retval^ := GetUtf8String(TreeNode.Text);
+    else
+     retval^ := GetUtf8String('');
+    end;
+end;
+
+function TQtAccessibleTreeRow.isVisible:Boolean;
+var
+  TreeNode: TTreeNode;
+begin
+  TreeNode := TTreeNode(FLazAxObject.DataObject);
+  Result := TreeNode.IsVisible;
+end;
+
+
+
+
+
 end.
Index: lcl/interfaces/qt5/qtwscontrols.pp
===================================================================
--- lcl/interfaces/qt5/qtwscontrols.pp	(revision 64768)
+++ lcl/interfaces/qt5/qtwscontrols.pp	(working copy)
@@ -45,6 +45,15 @@
       ALockedWindow: HWND; X, Y: Integer; DoLock: Boolean): Boolean; override;
   end;
 
+  { TQtWSLazAccessibleObject }
+
+  TQtWSLazAccessibleObject = class(TWSLazAccessibleObject)
+  public
+    class function CreateHandle(const AObject: TLazAccessibleObject): HWND; override;
+    class procedure DestroyHandle(const AObject: TLazAccessibleObject); override;
+    class procedure SetAccessibleRole(const AObject: TLazAccessibleObject; const ARole: TLazAccessibilityRole); override;
+  end;
+
   { TQtWSControl }
 
   TQtWSControl = class(TWSControl)
@@ -154,6 +163,45 @@
   {$endif}
 end;
 
+class function TQtWSLazAccessibleObject.CreateHandle(const AObject: TLazAccessibleObject): HWND;
+var
+  widget: QWidgetH;
+  WinControl: TWinControl;
+  H: TQtWidget;
+begin
+  QAccessible_installFactory(@QtAxFactory);
+  Result := 0;
+  if (AObject.OwnerControl <> nil) and (AObject.OwnerControl is TWinControl) and
+     (AObject.OwnerControl.GetAccessibleObject() = AObject) then begin
+    { Need to improve handling here.  Problem is that we hit here before TWinControl
+      has handle allocated but nothing will send us back here once handle is allocated
+      thus code in TQtCustomControl.initializeAccessibility that does
+      TLazAccessibleObject.handle assignment when TWinControl.Handle created}
+    //if TQtWidget(TWinControl(AObject.OwnerControl).HandleAllocated then begin
+    //  widget := QWidgetH(TQtWidget(TWinControl(AObject.OwnerControl).Handle).Widget);
+    //  Result := HWND(TQtAccessibleObject.Create(AObject, widget));
+    // end;
+  end
+  else begin
+    if AObject.AccessibleRole = larTreeItem then
+      Result := HWND(TQtAccessibleTreeRow.Create(AObject, QWidgetH(0)))
+    else
+      Result := HWND(TQtAccessibleObject.Create(AObject, QWidgetH(0)));
+  end;
+end;
+
+class procedure TQtWSLazAccessibleObject.DestroyHandle(const AObject: TLazAccessibleObject);
+begin
+  TQtAccessibleObject(AObject.Handle).Free;
+end;
+
+class procedure TQtWSLazAccessibleObject.SetAccessibleRole(const AObject: TLazAccessibleObject; const ARole: TLazAccessibilityRole);
+begin
+  {Need to improve this to do something similar to Cocoa where handle is recreated
+   if accessibleRole has changed}
+  CreateHandle(AObject);
+end;
+
 {------------------------------------------------------------------------------
   Function: TQtWSWinControl.CanFocus
   Params:  TWinControl
Index: lcl/interfaces/qt5/qtwsfactory.pas
===================================================================
--- lcl/interfaces/qt5/qtwsfactory.pas	(revision 64768)
+++ lcl/interfaces/qt5/qtwsfactory.pas	(working copy)
@@ -132,9 +132,8 @@
 
 function RegisterLazAccessibleObject: Boolean; alias : 'WSRegisterLazAccessibleObject';
 begin
-//      RegisterWSLazAccessibleObject(TGtk2WSLazAccessibleObject);
-//      Result := True;
-  Result := False;
+  RegisterWSLazAccessibleObject(TQtWSLazAccessibleObject);
+  Result := True;
 end;
 
 function RegisterControl: Boolean; alias : 'WSRegisterControl';

accessibility_qt5.patch (42,446 bytes)   

Juha Manninen

2021-03-09 14:15

developer   ~0129527

I get linker errors. See below. Do I need a new version of the QT5Pas library?

(9015) Linking ../lazarus
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/units/x86_64-linux/qt5/qtwidgets.o: in function `QTAXFACTORY':
/home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20025: undefined reference to `QLCLAccessibleWidget_Create'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/units/x86_64-linux/qt5/qtwidgets.o: in function `CREATE':
/home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20046: undefined reference to `QAccessible_queryAccessibleInterface'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20047: undefined reference to `QLCLAccessibleWidget_override_child'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20048: undefined reference to `QLCLAccessibleWidget_override_childCount'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20049: undefined reference to `QLCLAccessibleWidget_override_role'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20050: undefined reference to `QLCLAccessibleWidget_override_text'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/units/x86_64-linux/qt5/qtwidgets.o: in function `CHILDOVERRIDE':
/home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20081: undefined reference to `QAccessible_queryAccessibleInterface'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/units/x86_64-linux/qt5/qtwidgets.o: in function `CREATE':
/home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20132: undefined reference to `QAccessible_queryAccessibleInterface'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20133: undefined reference to `QLCLAccessibleWidget_override_child'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20134: undefined reference to `QLCLAccessibleWidget_override_childCount'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/units/x86_64-linux/qt5/qtwidgets.o: in function `CHILDOVERRIDE':
/home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20149: undefined reference to `QAccessible_queryAccessibleInterface'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/units/x86_64-linux/qt5/qtwidgets.o: in function `CREATE':
/home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20180: undefined reference to `QAccessible_queryAccessibleInterface'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20181: undefined reference to `QLCLAccessibleWidget_override_actionNames'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20182: undefined reference to `QLCLAccessibleWidget_override_child'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20183: undefined reference to `QLCLAccessibleWidget_override_childAt'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20184: undefined reference to `QLCLAccessibleWidget_override_childCount'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20185: undefined reference to `QLCLAccessibleWidget_override_doAction'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20186: undefined reference to `QLCLAccessibleWidget_override_parent'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20187: undefined reference to `QLCLAccessibleWidget_override_rect'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20188: undefined reference to `QLCLAccessibleWidget_override_role'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20189: undefined reference to `QLCLAccessibleWidget_override_text'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/units/x86_64-linux/qt5/qtwidgets.o: in function `PARENTOVERRIDE':
/home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwidgets.pas:20215: undefined reference to `QAccessible_queryAccessibleInterface'
/usr/bin/ld: /home/juha/SW/lazarus_trunk/lcl/units/x86_64-linux/qt5/qtwscontrols.o: in function `CREATEHANDLE':
/home/juha/SW/lazarus_trunk/lcl/interfaces//qt5/qtwscontrols.pp:172: undefined reference to `QAccessible_installFactory'
make[2]: *** [Makefile:4667: lazarus] Error 1
make[1]: *** [Makefile:5105: idepkg] Error 2
make: *** [Makefile:3685: idepkg] Error 2
/home/juha/SW/lazarus_trunk/ide/lazarus.pp(167,1) Error: (9013) Error while linking
/home/juha/SW/lazarus_trunk/ide/lazarus.pp(167,1) Fatal: (10026) There were 1 errors compiling module, stopping
Fatal: (1018) Compilation aborted
Error: /usr/bin/ppcx64 returned an error exitcode
make[2]: Leaving directory '/home/juha/SW/lazarus_trunk/ide'
make[1]: Leaving directory '/home/juha/SW/lazarus_trunk/ide'
make: Leaving directory '/home/juha/SW/lazarus_trunk'

David Jenkins

2021-03-09 18:52

reporter   ~0129534

The Qt5 implementation does require changes in the cbindings directory and to qt56.pas. So libQt5pas.lib does need to be rebuilt.

Zeljan Rikalo

2021-03-10 12:14

developer   ~0129542

@Juha, please, I'll take care about it. Pls see issue https://bugs.freepascal.org/view.php?id=37576 and return back some feedback. Now it looks ok visually, I must only fix mouse button click x,y and then it'll work correct.

David Jenkins

2021-03-10 18:02

reporter   ~0129551

Apologies. I did not get the additional files needed in cbindings src into the patch. Here they are:
qaccessible_c.cpp (1,795 bytes)   
//******************************************************************************
//  Copyright (c) 2005-2013 by Jan Van hijfte
//
//  See the included file COPYING.TXT for details about the copyright.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//******************************************************************************


#include "qaccessible_c.h"

QAccessibleInterfaceH QAccessible_accessibleInterface(QAccessibleId uniqueId)
{
 	return (QAccessibleInterfaceH) QAccessible::accessibleInterface(uniqueId);
}

void QAccessible_deleteAccessibleInterface(QAccessibleId uniqueId)
{
	QAccessible::deleteAccessibleInterface(uniqueId);
}

void QAccessible_installFactory(InterfaceFactory factory)
{
	QAccessible::installFactory(factory);
}

bool QAccessible_isActive()
{
	return QAccessible::isActive();
}

QAccessibleInterfaceH QAccessible_queryAccessibleInterface(QObjectH object_)
{
	return (QAccessibleInterfaceH) QAccessible::queryAccessibleInterface((QObject *)object_);
}

QAccessibleId QAccessible_registerAccessibleInterface(QAccessibleInterfaceH iface)
{
	return (QAccessibleId) QAccessible::registerAccessibleInterface((QAccessibleInterface *)iface);
}

void QAccessible_removeFactory(InterfaceFactory factory)
{
	QAccessible::removeFactory(factory);
}

void QAccessible_setRootObject(QObjectH object_)
{
	QAccessible::setRootObject((QObject *)object_);
}

QAccessibleId QAccessible_uniqueId(QAccessibleInterfaceH iface)
{
	return (QAccessibleId) QAccessible::uniqueId((QAccessibleInterface *)iface);
}

void QAccessible_updateAccessibility(QAccessibleEventH event)
{
	QAccessible::updateAccessibility((QAccessibleEvent *)event);
}

qaccessible_c.cpp (1,795 bytes)   
qaccessible_c.h (1,417 bytes)   
//******************************************************************************
//  Copyright (c) 2005-2013 by Jan Van hijfte
//
//  See the included file COPYING.TXT for details about the copyright.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//******************************************************************************


#ifndef QACCESSIBLE_C_H
#define QACCESSIBLE_C_H

#include <QtWidgets>
#include "pascalbind.h"

typedef unsigned QAccessibleId;
typedef QAccessibleInterface*(*InterfaceFactory)(const QString &key, QObject*);

C_EXPORT QAccessibleInterfaceH QAccessible_accessibleInterface(QAccessibleId uniqueId);
C_EXPORT void QAccessible_deleteAccessibleInterface(QAccessibleId uniqueId);
C_EXPORT void QAccessible_installFactory(InterfaceFactory factory);
C_EXPORT bool QAccessible_isActive();
C_EXPORT QAccessibleInterfaceH QAccessible_queryAccessibleInterface(QObjectH object_);
C_EXPORT QAccessibleId QAccessible_registerAccessibleInterface(QAccessibleInterfaceH iface);
C_EXPORT void QAccessible_removeFactory(InterfaceFactory  factory);
C_EXPORT void QAccessible_setRootObject(QObjectH object_);
C_EXPORT QAccessibleId QAccessible_uniqueId(QAccessibleInterfaceH iface);
C_EXPORT void QAccessible_updateAccessibility(QAccessibleEvent event);
#endif
qaccessible_c.h (1,417 bytes)   
qaccessiblewidget_c.cpp (2,847 bytes)   
//******************************************************************************
//  Copyright (c) 2005-2013 by Jan Van hijfte
//
//  See the included file COPYING.TXT for details about the copyright.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//******************************************************************************


#include "qaccessiblewidget_c.h"



QAccessibleWidgetH QAccessibleWidget_Create(QWidgetH o, QAccessible::Role r, PWideString name)
{
	QString t_name;
	copyPWideStringToQString(name, t_name);
	return (QAccessibleWidgetH) new QAccessibleWidget((QWidget*)o, r, t_name);
}

bool QAccessibleWidget_isValid(QAccessibleWidgetH handle)
{
	return (bool) ((QAccessibleWidget *)handle)->isValid();
}

QWindowH QAccessibleWidget_window(QAccessibleWidgetH handle)
{
	return (QWindowH) ((QAccessibleWidget *)handle)->window();
}

int QAccessibleWidget_childCount(QAccessibleWidgetH handle)
{
	return (int) ((QAccessibleWidget *)handle)->childCount();
}

int QAccessibleWidget_indexOfChild(QAccessibleWidgetH handle, const QAccessibleInterfaceH child)
{
	return (int) ((QAccessibleWidget *)handle)->indexOfChild((QAccessibleInterface*)child);
}

QAccessibleInterfaceH QAccessibleWidget_focusChild(QAccessibleWidgetH handle)
{
	return (QAccessibleInterfaceH) ((QAccessibleWidget *)handle)->focusChild();
}

void QAccessibleWidget_rect(QAccessibleWidgetH handle, PRect retval)
{
	QRect t_retval;
	t_retval = ((QAccessibleWidget *)handle)->rect();
	copyQRectToPRect(t_retval, retval);
}

QAccessibleInterfaceH QAccessibleWidget_parent(QAccessibleWidgetH handle)
{
	return (QAccessibleInterfaceH) ((QAccessibleWidget *)handle)->parent();
}

QAccessibleInterfaceH QAccessibleWidget_child(QAccessibleWidgetH handle, int index)
{
	return (QAccessibleInterfaceH) ((QAccessibleWidget *)handle)->child(index);
}

void QAccessibleWidget_text(QAccessibleWidgetH handle, PWideString retval, QAccessible::Text t)
{
	QString t_retval;
	t_retval = ((QAccessibleWidget *)handle)->text(t);
	copyQStringToPWideString(t_retval, retval);
}

QAccessible::Role QAccessibleWidget_role(QAccessibleWidgetH handle)
{
	return (QAccessible::Role) ((QAccessibleWidget *)handle)->role();
}

QAccessible::State QAccessibleWidget_state(QAccessibleWidgetH handle)
{
	return (QAccessible::State) ((QAccessibleWidget *)handle)->state();
}

void QAccessibleWidget_actionNames(QAccessibleWidgetH handle, QStringListH retval)
{
	*(QStringList *)retval = ((QAccessibleWidget *)handle)->actionNames();
}

void QAccessibleWidget_doAction(QAccessibleWidgetH handle, PWideString actionName)
{
	QString t_actionName;
	copyPWideStringToQString(actionName, t_actionName);
	((QAccessibleWidget *)handle)->doAction(t_actionName);
}
qaccessiblewidget_c.cpp (2,847 bytes)   
qaccessiblewidget_c.h (1,894 bytes)   
//******************************************************************************
//  Copyright (c) 2005-2013 by Jan Van hijfte
//
//  See the included file COPYING.TXT for details about the copyright.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//******************************************************************************


#ifndef QACCESSIBLEWIDGET_C_H
#define QACCESSIBLEWIDGET_C_H

// QAccessible::Role
// - 
// QAccessible::State
// - 
// QAccessible::Text
// - 

#include <QtWidgets>
#include "pascalbind.h"

C_EXPORT QAccessibleWidgetH QAccessibleWidget_Create(QWidgetH o, QAccessible::Role r, PWideString name);
C_EXPORT bool QAccessibleWidget_isValid(QAccessibleWidgetH handle);
C_EXPORT QWindowH QAccessibleWidget_window(QAccessibleWidgetH handle);
C_EXPORT int QAccessibleWidget_childCount(QAccessibleWidgetH handle);
C_EXPORT int QAccessibleWidget_indexOfChild(QAccessibleWidgetH handle, const QAccessibleInterfaceH child);
C_EXPORT QAccessibleInterfaceH QAccessibleWidget_focusChild(QAccessibleWidgetH handle);
C_EXPORT void QAccessibleWidget_rect(QAccessibleWidgetH handle, PRect retval);
C_EXPORT QAccessibleInterfaceH QAccessibleWidget_parent(QAccessibleWidgetH handle);
C_EXPORT QAccessibleInterfaceH QAccessibleWidget_child(QAccessibleWidgetH handle, int index);
C_EXPORT void QAccessibleWidget_text(QAccessibleWidgetH handle, PWideString retval, QAccessible::Text t);
C_EXPORT QAccessible::Role QAccessibleWidget_role(QAccessibleWidgetH handle);
C_EXPORT QAccessible::State QAccessibleWidget_state(QAccessibleWidgetH handle);
C_EXPORT void QAccessibleWidget_actionNames(QAccessibleWidgetH handle, QStringListH retval);
C_EXPORT void QAccessibleWidget_doAction(QAccessibleWidgetH handle, PWideString actionName);


#endif
qaccessiblewidget_c.h (1,894 bytes)   
qlclaccessiblewidget_c.cpp (2,720 bytes)   
//******************************************************************************
//  Copyright (c) 2005-2013 by Jan Van hijfte
//
//  See the included file COPYING.TXT for details about the copyright.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//******************************************************************************


#include "qlclaccessiblewidget_c.h"


QLCLAccessibleWidgetH QLCLAccessibleWidget_Create(QWidgetH o, QAccessible::Role r, PWideString name)
{
	QString t_name;
	copyPWideStringToQString(name, t_name);
	// const QString& name = QString()
	return (QLCLAccessibleWidgetH) new QLCLAccessibleWidget((QWidget *) o, (QAccessible::Role)r, t_name);
}

void QLCLAccessibleWidget_Destroy(QLCLAccessibleWidgetH handle)
{
	delete (QLCLAccessibleWidget *)handle;
}

void QLCLAccessibleWidget_override_actionNames(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_actionNames(hook);
}


void QLCLAccessibleWidget_override_child(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_child(hook);
}

void QLCLAccessibleWidget_override_childAt(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_childAt(hook);
}

void QLCLAccessibleWidget_override_childCount(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_childCount(hook);
}

void QLCLAccessibleWidget_override_doAction(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_doAction(hook);
}

void QLCLAccessibleWidget_override_indexOfChild(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_indexOfChild(hook);
}

void QLCLAccessibleWidget_override_parent(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_parent(hook);
}

void QLCLAccessibleWidget_override_rect(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_rect(hook);
}

void QLCLAccessibleWidget_override_role(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_role(hook);
}

void QLCLAccessibleWidget_override_state(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_state(hook);
}

void QLCLAccessibleWidget_override_text(QLCLAccessibleWidgetH handle, const QOverrideHook hook)
{
	((QLCLAccessibleWidget *)handle)->override_text(hook);
}
qlclaccessiblewidget_c.cpp (2,720 bytes)   
qlclaccessiblewidget.h (7,904 bytes)   
#ifndef QLCLACCESSIBLEWIDGET_H
#define QLCLACCESSIBLEWIDGET_H

#include <QAccessibleWidget>
#include "pascalbind.h"

class QLCLAccessibleWidget : public QAccessibleWidget {

public:

  //====================================================================================
  QLCLAccessibleWidget(QWidget *o, QAccessible::Role r = QAccessible::Client, const QString& name = QString()) :  QAccessibleWidget (o, r, name) {
    actionNamesOverride.func = NULL;
	childOverride.func = NULL;
    childAtOverride.func = NULL;
    childCountOverride.func = NULL;
    doActionOverride.func = NULL;
    indexOfChildOverride.func = NULL;
    parentOverride.func = NULL;
    rectOverride.func = NULL;
    roleOverride.func = NULL;
    stateOverride.func = NULL;
    textOverride.func = NULL;
  }

  //==================================================================================== 
  void override_actionNames(const QOverrideHook hook) {
    actionNamesOverride = hook;
  }

  void override_child(const QOverrideHook hook) {
    childOverride = hook; 
  }

  //==================================================================================== 
  void override_childAt(const QOverrideHook hook) {
    childAtOverride = hook; 
  }

  void override_childCount(const QOverrideHook hook) {
    childCountOverride = hook; 
  }

  void override_doAction(const QOverrideHook hook) {
    doActionOverride = hook;
  }

  void override_indexOfChild(const QOverrideHook hook) {
    indexOfChildOverride = hook;
  }

  void override_parent(const QOverrideHook hook) {
    parentOverride = hook; 
  }

  void override_rect(const QOverrideHook hook) {
    rectOverride = hook; 
  }

  void override_role(const QOverrideHook hook) {
    roleOverride = hook; 
  }

  void override_state(const QOverrideHook hook) {
    stateOverride = hook; 
  }

  void override_text(const QOverrideHook hook) {
    textOverride = hook; 
  }

private:

  //==================================================================================== 
  QOverrideHook actionNamesOverride;
  QOverrideHook childOverride;
  QOverrideHook childAtOverride;
  QOverrideHook childCountOverride;
  QOverrideHook doActionOverride;
  QOverrideHook indexOfChildOverride;
  QOverrideHook parentOverride;
  QOverrideHook rectOverride;
  QOverrideHook roleOverride;
  QOverrideHook stateOverride;
  QOverrideHook textOverride;

  //====================================================================================
  QStringList actionNames() const {

    QStringList names;

    if (actionNamesOverride.func) {

      typedef void (*func_type)(void *data, PWideString pwstr);
      PWideString t_str;
	  QString str;
      initializePWideString(t_str);
      (*(func_type)actionNamesOverride.func)(actionNamesOverride.data, t_str);
      copyPWideStringToQString(t_str, str);
	  names = str.split(',');

      }
      else {
        names = QAccessibleWidget::actionNames();
      }

    return names;

  };

  //====================================================================================
  QAccessibleInterface *child(int index) const {

    QAccessibleInterface *childInterface = 0;

    if (childOverride.func) {

      typedef void (*func_type)(void *data, int index, QAccessibleInterface *child);
      (*(func_type)childOverride.func)(childOverride.data, index, (QAccessibleInterface *)&childInterface);

      }
      else {
        childInterface = QAccessibleWidget::child(index); 
      }

    return childInterface;

  };

  //==================================================================================== 
  QAccessibleInterface *childAt(int x, int y) const {

    QAccessibleInterface *childInterface = 0;

    if (childAtOverride.func) {

      typedef void (*func_type)(void *data, int x, int y, QAccessibleInterface *child);
      (*(func_type)childAtOverride.func)(childAtOverride.data, x, y, (QAccessibleInterface *)&childInterface);

      }
      else
        childInterface = QAccessibleWidget::childAt(x, y); 

    return childInterface;

  };


  //==================================================================================== 
  int childCount() const {

    int result = 0;

    if (childCountOverride.func) {

      typedef void (*func_type)(void *data, int *result);
      (*(func_type)childCountOverride.func)(childCountOverride.data, (int *)&result);

      }
      else
        result = QAccessibleWidget::childCount(); 

    return result;

  };

  //==================================================================================== 
  int indexOfChild(QAccessibleInterface *child) const {

    int index;

    if (indexOfChildOverride.func) {

      typedef void (*func_type)(void *data, QAccessibleInterface *child, int *index);
      (*(func_type)indexOfChildOverride.func)(indexOfChildOverride.data, child, (int *)&index);

      }
      else {
        index = QAccessibleWidget::indexOfChild(child); 
      }

    return index;

  };

  //====================================================================================
  void doAction(const QString &actionName) {

    if (doActionOverride.func) {
      PWideString t_actionName;
	  initializePWideString(t_actionName);
	  copyQStringToPWideString(actionName, t_actionName);

      typedef void (*func_type)(void *data, PWideString name);
      (*(func_type)doActionOverride.func)(doActionOverride.data, (PWideString) t_actionName);

      }
      else {
        QAccessibleWidget::doAction(actionName);
      }

  };

  //====================================================================================
  QAccessibleInterface *parent() const {

    QAccessibleInterface *parent = 0;

      if (parentOverride.func) {

        typedef void (*func_type)(void *data, QAccessibleInterface *parent);
        (*(func_type)parentOverride.func)(parentOverride.data, (QAccessibleInterface *)&parent);

        }
        else
          parent = QAccessibleWidget::parent(); 

      return parent;

  };

  //==================================================================================== 
  QRect rect() const {

    int left, top, width, height;

    if (rectOverride.func) {

      typedef void (*func_type)(void *data, int *left, int *right, int *width, int *height);
      (*(func_type)rectOverride.func)(rectOverride.data, (int *)&left, (int *)&top, (int *)&width, (int *)&height);
      return QRect(left, top, width, height);
      }
      else
        return QAccessibleWidget::rect();
  };

  //==================================================================================== 
  QAccessible::Role role() const {

    QAccessible::Role result = QAccessible::Client;

    if (roleOverride.func) {

      typedef void (*func_type)(void *data, QAccessible::Role *result);
      (*(func_type)roleOverride.func)(roleOverride.data, (QAccessible::Role *)&result);

      }
      else
        result = QAccessibleWidget::role(); 

    return result;
  };

  //==================================================================================== 
  QAccessible::State state() const {

    QAccessible::State result;

    if (stateOverride.func) {

      typedef void (*func_type)(void *data, QAccessible::State *result);
      (*(func_type)stateOverride.func)(stateOverride.data, (QAccessible::State *)&result);

      }
      else
        result = QAccessibleWidget::state();

    return result;

  };

  //==================================================================================== 
  QString text(QAccessible::Text t) const {

    QString str;

    if (textOverride.func) {

      typedef void (*func_type)(void *data, QAccessible::Text t,  PWideString pwstr);
      PWideString t_str;
      initializePWideString(t_str);
      (*(func_type)textOverride.func)(textOverride.data, t, t_str);
      copyPWideStringToQString(t_str, str);

      }
      else
        str = QAccessibleWidget::text(t); 

    return str;

  };
};

#endif
qlclaccessiblewidget.h (7,904 bytes)   
qlclaccessiblewidget_c.h (1,996 bytes)   
//******************************************************************************
//  Copyright (c) 2005-2013 by Jan Van hijfte
//
//  See the included file COPYING.TXT for details about the copyright.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//******************************************************************************


#ifndef QLCLACCESSIBLEWIDGET_C_H
#define QLCLACCESSIBLEWIDGET_C_H

#include "qlclaccessiblewidget.h"
#include "pascalbind.h"

C_EXPORT QLCLAccessibleWidgetH QLCLAccessibleWidget_Create(QWidgetH o, QAccessible::Role r, PWideString name);
C_EXPORT void QLCLAccessibleWidget_Destroy(QLCLAccessibleWidgetH handle);
C_EXPORT void QLCLAccessibleWidget_override_actionNames(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_child(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_childAt(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_childCount(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_doAction(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_indexOfChild(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_parent(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_rect(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_role(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_state(QLCLAccessibleWidgetH handle, const QOverrideHook hook);
C_EXPORT void QLCLAccessibleWidget_override_text(QLCLAccessibleWidgetH handle, const QOverrideHook hook);

#endif
qlclaccessiblewidget_c.h (1,996 bytes)   

David Jenkins

2021-03-10 18:56

reporter   ~0129555

And the Qt5Pas.pro diff
qt5pas_pro.diff (837 bytes)   
Index: Qt5Pas.pro
===================================================================
--- Qt5Pas.pro	(revision 24995)
+++ Qt5Pas.pro	(revision 25497)
@@ -223,6 +223,9 @@
            qabstractscrollarea_c.h \
            qabstractscrollarea_hook.h \
            qlclabstractscrollarea_c.h \
+           qaccessible_c.h \
+           qaccessiblewidget_c.h \
+           qlclaccessiblewidget_c.h \
            qabstractslider_c.h \
            qabstractslider_hook.h \
            qscrollbar_c.h \
@@ -562,6 +565,9 @@
            qstackedwidget_c.cpp \
            qabstractscrollarea_c.cpp \
            qlclabstractscrollarea_c.cpp \
+           qaccessible_c.cpp \
+           qaccessiblewidget_c.cpp \
+           qlclaccessiblewidget_c.cpp \
            qabstractslider_c.cpp \
            qscrollbar_c.cpp \
            qmenu_c.cpp \
qt5pas_pro.diff (837 bytes)   

Zeljan Rikalo

2021-04-04 14:43

developer   ~0130076

Please test and close if ok.

Zeljan Rikalo

2021-04-12 13:45

developer   ~0130307

Since r64977 Qt accessibility for Qt5 is disabled by QTACCESSIBILITY define in qtdefines.inc.
Reason: Many crashes (IDE, apps) and many memleaks with accessible objects.
Please, test and change accessibility code so it does not crash ide or create memleaks.
As I can see memleaks comes from CreateHandle() for accessible object (so it's not freed properly),
also crashes comes from QWidget_sizeHint() and QComboBox_sizeHint() inside Qt library.

David Jenkins

2021-04-28 18:35

reporter   ~0130644

Last edited: 2021-04-28 18:44

View 3 revisions

Patch to fix memleaks and crashes in laz ide when QTACCESSIBILITY is enabled.

I built the laz ide from trunk version 65059. Memleak checking was enabled by adding 'gh' to the compile line. I ran the ide without the qt accessibility environment enabled and with it enabled (QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1). I used the 'accersiser' app to exercise the a11y interface.

With this patch applied I saw no crashes and heapTrc reported no memleaks.

Note that qlclaccessiblewidget.h has a change so the Qt5Pas library files will need to be rebuilt as well.
Qt5A11yFixes.patch (6,335 bytes)   
Index: lcl/interfaces/qt5/qtwsfactory.pas
===================================================================
--- lcl/interfaces/qt5/qtwsfactory.pas	(revision 65059)
+++ lcl/interfaces/qt5/qtwsfactory.pas	(working copy)
@@ -3,6 +3,9 @@
 {$mode objfpc}{$H+}
 
 interface
+
+{$I qtdefines.inc}
+
 uses
   Classes, Controls, ComCtrls, Calendar, StdCtrls, Spin, Grids,
   Dialogs, ExtCtrls, Buttons, CheckLst, Forms, Menus, RubberBand, PairSplitter,
Index: lcl/interfaces/qt5/qtwscontrols.pp
===================================================================
--- lcl/interfaces/qt5/qtwscontrols.pp	(revision 65059)
+++ lcl/interfaces/qt5/qtwscontrols.pp	(working copy)
@@ -189,19 +189,27 @@
       Result := HWND(TQtAccessibleTreeRow.Create(AObject, QWidgetH(0)))
     else
       Result := HWND(TQtAccessibleObject.Create(AObject, QWidgetH(0)));
+    TQtAccessibleObject(Result).RoleAtCreation := AObject.AccessibleRole;
   end;
 end;
 
 class procedure TQtWSLazAccessibleObject.DestroyHandle(const AObject: TLazAccessibleObject);
 begin
-  TQtAccessibleObject(AObject.Handle).Free;
+  if (AObject <> nil) and AObject.HandleAllocated then begin
+    TQtAccessibleObject(AObject.Handle).Free;
+    AObject.Handle := 0;
+  end;
 end;
 
 class procedure TQtWSLazAccessibleObject.SetAccessibleRole(const AObject: TLazAccessibleObject; const ARole: TLazAccessibilityRole);
 begin
-  {Need to improve this to do something similar to Cocoa where handle is recreated
-   if accessibleRole has changed}
-  CreateHandle(AObject);
+  if AObject.HandleAllocated then begin
+    if (TQtAccessibleObject(AObject.Handle).RoleAtCreation = ARole) then
+      Exit
+    else
+      DestroyHandle(AObject)
+  end;
+  AObject.Handle := CreateHandle(AObject);
 end;
 {$ENDIF}
 
Index: lcl/interfaces/qt5/qtdefines.inc
===================================================================
--- lcl/interfaces/qt5/qtdefines.inc	(revision 65059)
+++ lcl/interfaces/qt5/qtdefines.inc	(working copy)
@@ -9,7 +9,7 @@
   {$DEFINE QTCOCOA}
   {$ENDIF}
   {$DEFINE QTSCROLLABLEFORMS}
-  {.$DEFINE QTACCESSIBILITY}
+  {$DEFINE QTACCESSIBILITY}
   {Qt must use native event loop at least under MacOSX cocoa 64}
   {$IFNDEF HASX11}
   {$DEFINE QtUseNativeEventLoop}
Index: lcl/interfaces/qt5/qtwidgets.pas
===================================================================
--- lcl/interfaces/qt5/qtwidgets.pas	(revision 65059)
+++ lcl/interfaces/qt5/qtwidgets.pas	(working copy)
@@ -1984,8 +1984,9 @@
   private
     FLazAxObject: TLazAccessibleObject;
     FAxWidget: QWidgetH;
+    FRoleAtCreation: TLazAccessibilityRole;
   public
-    constructor Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH);
+    constructor Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH); virtual;
     destructor Destroy; override;
     procedure actionNamesOverride(names: PWideString) cdecl; virtual; abstract;
     procedure childOverride(index: integer; out child:  QAccessibleInterfaceH) cdecl; virtual;
@@ -1999,11 +2000,12 @@
     procedure stateOverride(out state: QAccessibleState) cdecl; virtual; abstract;
     procedure textOverride(text: QAccessibleText; retval: PWideString) cdecl; virtual;
     function isVisible: Boolean; virtual;
+    property RoleAtCreation: TLazAccessibilityRole read FRoleAtCreation write FRoleAtCreation;
   end;
 
   TQtAccessibleTree = class(TQtAccessibleObject)
   public
-    constructor Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH);
+    constructor Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH); override;
     procedure childOverride(index: integer; out child:  QAccessibleInterfaceH) cdecl; virtual;
     procedure childCountOverride(count: PInteger) cdecl; virtual;
   end;
@@ -2010,7 +2012,7 @@
 
   TQtAccessibleTreeRow = class(TQtAccessibleObject)
   public
-    constructor Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH);
+    constructor Create(ALazAxObject: TLazAccessibleObject; AWidget: QWidgetH); override;
     procedure actionNamesOverride(names: PWideString)cdecl; override;
     procedure childCountOverride(count: PInteger)cdecl; override;
     procedure doActionOverride(name: PWideString)cdecl; override;
@@ -2116,6 +2118,7 @@
 {$ENDIF}
 begin
   {$IFDEF QTACCESSIBILITY}
+  QAccessible_installFactory(@QtAxFactory);
   if Assigned(LCLObject) then begin
     LCLAxObject := LCLObject.GetAccessibleObject;
     if (LCLAxObject <> nil) then begin
@@ -17569,6 +17572,7 @@
 {$IFDEF QTACCESSIBILITY}
 var
   LCLAxObject: TLazAccessibleObject;
+  Handle: HWND;
 {$ENDIF}
 begin
   inherited InitializeAccessibility;
@@ -17576,12 +17580,16 @@
   if (LCLObject <> nil) then begin
     // TWinControl.Handle is still not set so can't do handle creation through LCLAxObject.CreateHandle
     LCLAxObject :=  LCLObject.GetAccessibleObject;
-      if LCLAxObject.AccessibleRole = larTreeView then
-        LCLAxObject.Handle :=
-          HWND(TQtAccessibleTree.Create(LCLAxObject, Widget))
-      else
-        LCLAxObject.Handle :=
-          HWND(TQtAccessibleObject.Create(LCLAxObject, Widget));
+      if (LCLAxObject <> nil) and not LCLAxObject.HandleAllocated then begin
+        if LCLAxObject.AccessibleRole = larTreeView then
+          Handle :=
+            HWND(TQtAccessibleTree.Create(LCLAxObject, Widget))
+        else
+          Handle :=
+            HWND(TQtAccessibleObject.Create(LCLAxObject, Widget));
+          TQtAccessibleObject(Handle).RoleAtCreation := LCLAxObject.AccessibleRole;
+          LCLAxObject.Handle := Handle;
+      end
   end;
   {$ENDIF}
 end;
@@ -19960,7 +19968,7 @@
   S: String;
 begin
   S := '';
-  if Assigned(AObject) then begin
+  if (AObject <> nil) then begin
     if AObject.AccessibleName <> '' then
       S := AObject.AccessibleName;
     if (S = '') and (AObject.OwnerControl <> nil) then begin
Index: lcl/interfaces/qt5/cbindings/src/qlclaccessiblewidget.h
===================================================================
--- lcl/interfaces/qt5/cbindings/src/qlclaccessiblewidget.h	(revision 65059)
+++ lcl/interfaces/qt5/cbindings/src/qlclaccessiblewidget.h	(working copy)
@@ -281,6 +281,7 @@
       initializePWideString(t_str);
       (*(func_type)textOverride.func)(textOverride.data, t, t_str);
       copyPWideStringToQString(t_str, str);
+      finalizePWideString(t_str);
 
       }
       else
Qt5A11yFixes.patch (6,335 bytes)   

David

2021-05-03 15:06

reporter   ~0130738

The new patch turns on accessibility by default. But all our Linux distributions are still shipping the old libqt5pas library. That will mean that trunk users will make binaries that cannot be run on unmodified systems. Thats not going to work and there will (hopefully) be concern about it appearing in release version of Lazarus. In the mean time, the distributions will not use trunk versions of the library, they take only the release version.

Better to have Lazarus Release contain the accessibility pascal code defaulting to off, but libqt5pas have the new accessibility code. That way, the distributions will pick up the library, developers who want and understand the accessibility issues can get it to work and everyone will be able to continue to use Qt5.

The distributions will start to pick up the libqt5pas code after it hits Release and eventually, the pascal code default can be turned on, everyone is happy.
 
Davo

Issue History

Date Modified Username Field Change
2021-03-08 23:00 Dmitry Boyarintsev New Issue
2021-03-08 23:00 Dmitry Boyarintsev Relationship added child of 0038603
2021-03-08 23:02 Dmitry Boyarintsev Description Updated View Revisions
2021-03-08 23:02 Dmitry Boyarintsev LazTarget => -
2021-03-08 23:02 Dmitry Boyarintsev Widgetset QT5 => QT5
2021-03-08 23:05 Dmitry Boyarintsev Note Added: 0129517
2021-03-08 23:05 Dmitry Boyarintsev File Added: accessibility_qt5.patch
2021-03-09 14:15 Juha Manninen Note Added: 0129527
2021-03-09 14:44 Dmitry Boyarintsev Reporter Dmitry Boyarintsev => David Jenkins
2021-03-09 14:44 Dmitry Boyarintsev Widgetset QT5 => QT5
2021-03-09 14:44 Dmitry Boyarintsev Assigned To => Dmitry Boyarintsev
2021-03-09 14:44 Dmitry Boyarintsev Status new => feedback
2021-03-09 14:44 Dmitry Boyarintsev Assigned To Dmitry Boyarintsev =>
2021-03-09 18:52 David Jenkins Note Added: 0129534
2021-03-09 18:52 David Jenkins Status feedback => new
2021-03-10 12:14 Zeljan Rikalo Assigned To => Zeljan Rikalo
2021-03-10 12:14 Zeljan Rikalo Status new => assigned
2021-03-10 12:14 Zeljan Rikalo Note Added: 0129542
2021-03-10 18:02 David Jenkins Note Added: 0129551
2021-03-10 18:02 David Jenkins File Added: qaccessible_c.cpp
2021-03-10 18:02 David Jenkins File Added: qaccessible_c.h
2021-03-10 18:02 David Jenkins File Added: qaccessiblewidget_c.cpp
2021-03-10 18:02 David Jenkins File Added: qaccessiblewidget_c.h
2021-03-10 18:02 David Jenkins File Added: qlclaccessiblewidget_c.cpp
2021-03-10 18:02 David Jenkins File Added: qlclaccessiblewidget_c.h
2021-03-10 18:02 David Jenkins File Added: qlclaccessiblewidget.h
2021-03-10 18:56 David Jenkins Note Added: 0129555
2021-03-10 18:56 David Jenkins File Added: qt5pas_pro.diff
2021-03-18 03:50 Dmitry Boyarintsev Relationship replaced parent of 0038603
2021-04-04 14:43 Zeljan Rikalo Status assigned => resolved
2021-04-04 14:43 Zeljan Rikalo Resolution open => fixed
2021-04-04 14:43 Zeljan Rikalo Fixed in Revision => 64920
2021-04-04 14:43 Zeljan Rikalo Widgetset QT5 => QT5
2021-04-04 14:43 Zeljan Rikalo Note Added: 0130076
2021-04-12 13:45 Zeljan Rikalo Status resolved => feedback
2021-04-12 13:45 Zeljan Rikalo Resolution fixed => open
2021-04-12 13:45 Zeljan Rikalo Note Added: 0130307
2021-04-28 18:35 David Jenkins Note Added: 0130644
2021-04-28 18:35 David Jenkins File Added: Qt5A11yFixes.patch
2021-04-28 18:35 David Jenkins Status feedback => assigned
2021-04-28 18:43 David Jenkins Note Edited: 0130644 View Revisions
2021-04-28 18:44 David Jenkins Note Edited: 0130644 View Revisions
2021-05-03 15:06 David Note Added: 0130738