Browse Source

Fix a11y for popup windows.

- Don't show when creating a popup window with a11y enabled
- Raise focus changed notification on element that got focus instead of the window
ui-automation-test
Steven Kirk 5 years ago
parent
commit
1553b89bd7
  1. 9
      native/Avalonia.Native/src/OSX/window.mm
  2. 44
      src/Avalonia.Native/WindowImplBase.cs

9
native/Avalonia.Native/src/OSX/window.mm

@ -520,7 +520,12 @@ public:
virtual void FocusChanged(IAvnAutomationPeer* peer) override
{
NSAccessibilityPostNotification(Window, NSAccessibilityFocusedUIElementChangedNotification);
auto element = GetAccessibilityElement(peer);
if (element != nullptr)
{
NSAccessibilityPostNotification(element, NSAccessibilityFocusedUIElementChangedNotification);
}
}
protected:
@ -2318,7 +2323,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
return [super accessibilityFocusedUIElement];
}
- (IAvnAutomationPeer* _Nonnull) getAutomationPeer
- (IAvnAutomationPeer*) getAutomationPeer
{
if (_automationPeer == nullptr)
_automationPeer = _parent->BaseEvents->AutomationStarted(_parent);

44
src/Avalonia.Native/WindowImplBase.cs

@ -63,6 +63,9 @@ namespace Avalonia.Native
private GlPlatformSurface _glSurface;
private NativeControlHostImpl _nativeControlHost;
private IGlContext _glContext;
private IAutomationNode _automationNode;
private AvnAutomationPeer _automationPeer;
private Func<IAutomationNode, AutomationPeer> _automationStarted;
internal WindowBaseImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
AvaloniaNativePlatformOpenGlInterface glFeature)
@ -209,7 +212,6 @@ namespace Avalonia.Native
return _parent.RawTextInputEvent(timeStamp, text).AsComBool();
}
void IAvnWindowBaseEvents.ScalingChanged(double scaling)
{
_parent._savedScaling = scaling;
@ -250,11 +252,7 @@ namespace Avalonia.Native
}
}
public IAvnAutomationPeer AutomationStarted(IAvnAutomationNode node)
{
var factory = AutomationNodeFactory.GetInstance(_parent._factory);
return new AvnAutomationPeer(_parent.AutomationStarted(new AutomationNode(factory, node)));
}
public IAvnAutomationPeer AutomationStarted(IAvnAutomationNode node) => _parent.HandleAutomationStarted(node);
}
public void Activate()
@ -477,6 +475,38 @@ namespace Avalonia.Native
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 0, 0);
public IPlatformHandle Handle { get; private set; }
public Func<IAutomationNode, AutomationPeer> AutomationStarted { get; set; }
public Func<IAutomationNode, AutomationPeer> AutomationStarted
{
get => _automationStarted;
set
{
_automationStarted = value;
// We've already received an AutomationStarted event, but the Window/PopupRoot wasn't initialized.
// Now it is, so notify it and store the automation peer for the next time the OS invokes an a11y
// query.
if (value is object && _automationNode is object)
_automationPeer = new AvnAutomationPeer(_automationStarted.Invoke(_automationNode));
}
}
private AvnAutomationPeer HandleAutomationStarted(IAvnAutomationNode node)
{
if (_automationPeer is object)
return _automationPeer;
var factory = AutomationNodeFactory.GetInstance(_factory);
_automationNode = new AutomationNode(factory, node);
// If automation is started during platform window creation we don't yet have a Window/PopupRoot
// control to notify. In this case we'll notify them when AutomationStarted gets set. We can safely
// return null here because the peer isn't actually needed at this point and will be re-queried the next
// time it's needed.
if (AutomationStarted is null)
return null;
return _automationPeer = new AvnAutomationPeer(AutomationStarted(_automationNode));
}
}
}

Loading…
Cancel
Save