From 8ded356614b6bef5d1c69a00da978efbacd795b1 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 30 Mar 2021 14:59:54 +0200 Subject: [PATCH] More work on ComboBox OSX a11y. Implement "Show Menu" and "Perform Press" actions. --- native/Avalonia.Native/src/OSX/automation.mm | 48 +++++++++++++++++-- .../Peers/ComboBoxAutomationPeer.cs | 1 + .../Provider/IExpandCollapseProvider.cs | 9 ++++ src/Avalonia.Native/AvnAutomationPeer.cs | 14 ++++++ src/Avalonia.Native/avn.idl | 6 +++ 5 files changed, 73 insertions(+), 5 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/automation.mm b/native/Avalonia.Native/src/OSX/automation.mm index cff142a912..c3ca182b91 100644 --- a/native/Avalonia.Native/src/OSX/automation.mm +++ b/native/Avalonia.Native/src/OSX/automation.mm @@ -222,11 +222,33 @@ public: return [self accessibilityTopLevelUIElement]; } -- (BOOL)accessibilityPerformPress +- (BOOL)isAccessibilityExpanded { - if (!_peer->IsInvokeProvider()) + if (!_peer->IsExpandCollapseProvider()) return NO; - _peer->InvokeProvider_Invoke(); + return _peer->ExpandCollapseProvider_IsExpanded(); +} + +- (void)setAccessibilityExpanded:(BOOL)accessibilityExpanded +{ + if (!_peer->IsExpandCollapseProvider()) + return; + if (accessibilityExpanded) + _peer->ExpandCollapseProvider_Expand(); + else + _peer->ExpandCollapseProvider_Collapse(); +} + +- (BOOL)accessibilityPerformPress +{ + if (_peer->IsInvokeProvider()) + { + _peer->InvokeProvider_Invoke(); + } + else if (_peer->IsExpandCollapseProvider()) + { + _peer->ExpandCollapseProvider_Expand(); + } return YES; } @@ -250,11 +272,27 @@ public: return YES; } +- (BOOL)accessibilityPerformShowMenu +{ + if (!_peer->IsExpandCollapseProvider()) + return NO; + _peer->ExpandCollapseProvider_Expand(); + return YES; +} + - (BOOL)isAccessibilitySelectorAllowed:(SEL)selector { - if (selector == @selector(accessibilityPerformPress)) + if (selector == @selector(accessibilityPerformShowMenu)) + { + return _peer->IsExpandCollapseProvider() && _peer->ExpandCollapseProvider_ShowsMenu(); + } + else if (selector == @selector(isAccessibilityExpanded)) + { + return _peer->IsExpandCollapseProvider(); + } + else if (selector == @selector(accessibilityPerformPress)) { - return _peer->IsInvokeProvider(); + return _peer->IsInvokeProvider() || _peer->IsExpandCollapseProvider(); } else if (selector == @selector(accessibilityPerformIncrement) || selector == @selector(accessibilityPerformDecrement)) diff --git a/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs index d11946b27e..d8225dbc40 100644 --- a/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/ComboBoxAutomationPeer.cs @@ -20,6 +20,7 @@ namespace Avalonia.Automation.Peers public new ComboBox Owner => (ComboBox)base.Owner; public ExpandCollapseState ExpandCollapseState => ToState(Owner.IsDropDownOpen); + public bool ShowsMenu => true; public void Collapse() => Owner.IsDropDownOpen = false; public void Expand() => Owner.IsDropDownOpen = true; diff --git a/src/Avalonia.Controls/Automation/Provider/IExpandCollapseProvider.cs b/src/Avalonia.Controls/Automation/Provider/IExpandCollapseProvider.cs index f0308c226b..a4691180a3 100644 --- a/src/Avalonia.Controls/Automation/Provider/IExpandCollapseProvider.cs +++ b/src/Avalonia.Controls/Automation/Provider/IExpandCollapseProvider.cs @@ -11,6 +11,15 @@ /// ExpandCollapseState ExpandCollapseState { get; } + /// + /// Gets a value indicating whether expanding the element shows a menu of items to the user, + /// such as drop-down list. + /// + /// + /// Used in OSX to enable the "Show Menu" action on the element. + /// + bool ShowsMenu { get; } + /// /// Displays all child nodes, controls, or content of the control. /// diff --git a/src/Avalonia.Native/AvnAutomationPeer.cs b/src/Avalonia.Native/AvnAutomationPeer.cs index fb3759b77e..81ed94bda9 100644 --- a/src/Avalonia.Native/AvnAutomationPeer.cs +++ b/src/Avalonia.Native/AvnAutomationPeer.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Avalonia.Automation; using Avalonia.Automation.Peers; using Avalonia.Automation.Provider; using Avalonia.Native.Interop; @@ -75,6 +76,19 @@ namespace Avalonia.Native return Wrap(result); } + public int IsExpandCollapseProvider() => (_inner is IExpandCollapseProvider).AsComBool(); + + public int ExpandCollapseProvider_IsExpanded() => ((IExpandCollapseProvider)_inner).ExpandCollapseState switch + { + ExpandCollapseState.Expanded => 1, + ExpandCollapseState.PartiallyExpanded => 1, + _ => 0, + }; + + public int ExpandCollapseProvider_ShowsMenu() => ((IExpandCollapseProvider)_inner).ShowsMenu.AsComBool(); + public void ExpandCollapseProvider_Expand() => ((IExpandCollapseProvider)_inner).Expand(); + public void ExpandCollapseProvider_Collapse() => ((IExpandCollapseProvider)_inner).Collapse(); + public int IsInvokeProvider() => (_inner is IInvokeProvider).AsComBool(); public void InvokeProvider_Invoke() => ((IInvokeProvider)_inner).Invoke(); diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl index 9b74eef6e2..8585ee63f2 100644 --- a/src/Avalonia.Native/avn.idl +++ b/src/Avalonia.Native/avn.idl @@ -816,6 +816,12 @@ interface IAvnAutomationPeer : IUnknown IAvnAutomationPeer* RootProvider_GetFocus(); IAvnAutomationPeer* RootProvider_GetPeerFromPoint(AvnPoint point); + bool IsExpandCollapseProvider(); + bool ExpandCollapseProvider_IsExpanded(); + bool ExpandCollapseProvider_ShowsMenu(); + void ExpandCollapseProvider_Expand(); + void ExpandCollapseProvider_Collapse(); + bool IsInvokeProvider(); void InvokeProvider_Invoke();