Browse Source

Expose macOS ScrollViewer scroll bars to accessibility (#21596)

ScrollViewerAutomationPeer surfaces the template scroll bar peers, which the native peer returns as AXHorizontalScrollBar and AXVerticalScrollBar.
release/12.0
Jumar Macato 4 months ago
committed by Julien Lebosquain
parent
commit
c53bf6b6e7
  1. 14
      native/Avalonia.Native/src/OSX/automation.mm
  2. 6
      src/Avalonia.Controls/Automation/Peers/ScrollViewerAutomationPeer.cs
  3. 15
      src/Avalonia.Controls/ScrollViewer.cs
  4. 6
      src/Avalonia.Native/AvnAutomationPeer.cs
  5. 5
      src/Avalonia.Native/avn.idl

14
native/Avalonia.Native/src/OSX/automation.mm

@ -358,6 +358,20 @@
return [AvnAccessibilityElement acquire:rootPeer]; return [AvnAccessibilityElement acquire:rootPeer];
} }
- (id)accessibilityHorizontalScrollBar
{
if (_peer == nullptr)
return nil;
return [AvnAccessibilityElement acquire:_peer->ScrollProvider_GetHorizontalScrollBar()];
}
- (id)accessibilityVerticalScrollBar
{
if (_peer == nullptr)
return nil;
return [AvnAccessibilityElement acquire:_peer->ScrollProvider_GetVerticalScrollBar()];
}
- (BOOL)isAccessibilityExpanded - (BOOL)isAccessibilityExpanded
{ {
if (!_peer->IsExpandCollapseProvider()) if (!_peer->IsExpandCollapseProvider())

6
src/Avalonia.Controls/Automation/Peers/ScrollViewerAutomationPeer.cs

@ -14,6 +14,12 @@ namespace Avalonia.Automation.Peers
public new ScrollViewer Owner => (ScrollViewer)base.Owner; public new ScrollViewer Owner => (ScrollViewer)base.Owner;
internal AutomationPeer? GetHorizontalScrollBarPeer()
=> Owner.HorizontalScrollBar is { } scrollBar ? GetOrCreate(scrollBar) : null;
internal AutomationPeer? GetVerticalScrollBarPeer()
=> Owner.VerticalScrollBar is { } scrollBar ? GetOrCreate(scrollBar) : null;
public bool HorizontallyScrollable public bool HorizontallyScrollable
{ {
get => MathUtilities.GreaterThan(Owner.Extent.Width, Owner.Viewport.Width); get => MathUtilities.GreaterThan(Owner.Extent.Width, Owner.Viewport.Width);

15
src/Avalonia.Controls/ScrollViewer.cs

@ -169,6 +169,18 @@ namespace Avalonia.Controls
private Size _smallChange = new Size(DefaultSmallChange, DefaultSmallChange); private Size _smallChange = new Size(DefaultSmallChange, DefaultSmallChange);
private bool _isExpanded; private bool _isExpanded;
private IDisposable? _scrollBarExpandSubscription; private IDisposable? _scrollBarExpandSubscription;
private ScrollBar? _horizontalScrollBar;
private ScrollBar? _verticalScrollBar;
/// <summary>
/// Gets the horizontal scroll bar from the applied template, if any.
/// </summary>
internal ScrollBar? HorizontalScrollBar => _horizontalScrollBar;
/// <summary>
/// Gets the vertical scroll bar from the applied template, if any.
/// </summary>
internal ScrollBar? VerticalScrollBar => _verticalScrollBar;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ScrollViewer"/> class. /// Initializes a new instance of the <see cref="ScrollViewer"/> class.
@ -834,6 +846,9 @@ namespace Avalonia.Controls
var horizontalScrollBar = e.NameScope.Find<ScrollBar>("PART_HorizontalScrollBar"); var horizontalScrollBar = e.NameScope.Find<ScrollBar>("PART_HorizontalScrollBar");
var verticalScrollBar = e.NameScope.Find<ScrollBar>("PART_VerticalScrollBar"); var verticalScrollBar = e.NameScope.Find<ScrollBar>("PART_VerticalScrollBar");
_horizontalScrollBar = horizontalScrollBar;
_verticalScrollBar = verticalScrollBar;
var horizontalExpanded = GetExpandedObservable(horizontalScrollBar); var horizontalExpanded = GetExpandedObservable(horizontalScrollBar);
var verticalExpanded = GetExpandedObservable(verticalScrollBar); var verticalExpanded = GetExpandedObservable(verticalScrollBar);

6
src/Avalonia.Native/AvnAutomationPeer.cs

@ -182,6 +182,12 @@ namespace Avalonia.Native
public int IsSelectionItemProvider() => IsProvider<ISelectionItemProvider>(); public int IsSelectionItemProvider() => IsProvider<ISelectionItemProvider>();
public int SelectionItemProvider_IsSelected() => SelectionItemProvider.IsSelected.AsComBool(); public int SelectionItemProvider_IsSelected() => SelectionItemProvider.IsSelected.AsComBool();
public IAvnAutomationPeer? ScrollProvider_GetHorizontalScrollBar()
=> _inner is ScrollViewerAutomationPeer scrollViewer ? Wrap(scrollViewer.GetHorizontalScrollBarPeer()) : null;
public IAvnAutomationPeer? ScrollProvider_GetVerticalScrollBar()
=> _inner is ScrollViewerAutomationPeer scrollViewer ? Wrap(scrollViewer.GetVerticalScrollBarPeer()) : null;
public int IsToggleProvider() => IsProvider<IToggleProvider>(); public int IsToggleProvider() => IsProvider<IToggleProvider>();
public int ToggleProvider_GetToggleState() => (int)ToggleProvider.ToggleState; public int ToggleProvider_GetToggleState() => (int)ToggleProvider.ToggleState;

5
src/Avalonia.Native/avn.idl

@ -1317,7 +1317,10 @@ interface IAvnAutomationPeer : IUnknown
bool IsSelectionItemProvider(); bool IsSelectionItemProvider();
bool SelectionItemProvider_IsSelected(); bool SelectionItemProvider_IsSelected();
IAvnAutomationPeer* ScrollProvider_GetHorizontalScrollBar();
IAvnAutomationPeer* ScrollProvider_GetVerticalScrollBar();
bool IsToggleProvider(); bool IsToggleProvider();
int ToggleProvider_GetToggleState(); int ToggleProvider_GetToggleState();
void ToggleProvider_Toggle(); void ToggleProvider_Toggle();

Loading…
Cancel
Save