From 0ab5e4dbfecc424397c27fbcca8683c7d4a949ea Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 27 Mar 2021 14:40:59 +0100 Subject: [PATCH] Implemented a11y focus on OSX. --- native/Avalonia.Native/src/OSX/automation.mm | 7 ++++++- native/Avalonia.Native/src/OSX/window.mm | 17 +++++++++++++++++ src/Avalonia.Native/AutomationNode.cs | 5 +---- src/Avalonia.Native/AvnAutomationPeer.cs | 1 + src/Avalonia.Native/avn.idl | 2 ++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/automation.mm b/native/Avalonia.Native/src/OSX/automation.mm index b400785a13..ff72cc2a20 100644 --- a/native/Avalonia.Native/src/OSX/automation.mm +++ b/native/Avalonia.Native/src/OSX/automation.mm @@ -36,7 +36,12 @@ public: break; } } - + + virtual void FocusChanged(IAvnAutomationPeer* peer) override + { + // Only implemented in top-level nodes, i.e. AvnWindow. + } + virtual NSObject* GetNSAccessibility() override { return _node; diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 5d69fc8e75..62ca8e32df 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -518,6 +518,11 @@ public: { } + virtual void FocusChanged(IAvnAutomationPeer* peer) override + { + NSAccessibilityPostNotification(Window, NSAccessibilityFocusedUIElementChangedNotification); + } + protected: virtual NSWindowStyleMask GetStyle() { @@ -2301,6 +2306,18 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent return GetAccessibilityElement(hit); } +- (id)accessibilityFocusedUIElement +{ + auto peer = [self getAutomationPeer]; + + if (peer->IsRootProvider()) + { + return GetAccessibilityElement(peer->RootProvider_GetFocus()); + } + + return [super accessibilityFocusedUIElement]; +} + - (IAvnAutomationPeer* _Nonnull) getAutomationPeer { if (_automationPeer == nullptr) diff --git a/src/Avalonia.Native/AutomationNode.cs b/src/Avalonia.Native/AutomationNode.cs index 2601b2f239..f85813a6fb 100644 --- a/src/Avalonia.Native/AutomationNode.cs +++ b/src/Avalonia.Native/AutomationNode.cs @@ -38,9 +38,6 @@ namespace Avalonia.Native Native.PropertyChanged(p); } - public void FocusChanged(AutomationPeer? focus) - { - // TODO - } + public void FocusChanged(AutomationPeer? focus) => Native.FocusChanged(AvnAutomationPeer.Wrap(focus)); } } diff --git a/src/Avalonia.Native/AvnAutomationPeer.cs b/src/Avalonia.Native/AvnAutomationPeer.cs index 0c4ad58b9d..fb3759b77e 100644 --- a/src/Avalonia.Native/AvnAutomationPeer.cs +++ b/src/Avalonia.Native/AvnAutomationPeer.cs @@ -52,6 +52,7 @@ namespace Avalonia.Native } public int IsRootProvider() => (_inner is IRootProvider).AsComBool(); + public IAvnAutomationPeer? RootProvider_GetFocus() => Wrap(((IRootProvider)_inner).GetFocus()); public IAvnAutomationPeer? RootProvider_GetPeerFromPoint(AvnPoint point) { diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl index 88c9225419..369031b72c 100644 --- a/src/Avalonia.Native/avn.idl +++ b/src/Avalonia.Native/avn.idl @@ -812,6 +812,7 @@ interface IAvnAutomationPeer : IUnknown IAvnAutomationPeer* GetRootPeer(); bool IsRootProvider(); + IAvnAutomationPeer* RootProvider_GetFocus(); IAvnAutomationPeer* RootProvider_GetPeerFromPoint(AvnPoint point); bool IsInvokeProvider(); @@ -844,4 +845,5 @@ interface IAvnAutomationNode : IUnknown { void ChildrenChanged(); void PropertyChanged(AvnAutomationProperty property); + void FocusChanged(IAvnAutomationPeer* peer); }