Browse Source

Make OSX a11y work again.

Pretty major refactor of that code.
ui-automation-test
Steven Kirk 4 years ago
parent
commit
bc128676c4
  1. 2
      native/Avalonia.Native/src/OSX/AvnString.mm
  2. 10
      native/Avalonia.Native/src/OSX/automation.h
  3. 234
      native/Avalonia.Native/src/OSX/automation.mm
  4. 3
      native/Avalonia.Native/src/OSX/common.h
  5. 8
      native/Avalonia.Native/src/OSX/main.mm
  6. 130
      native/Avalonia.Native/src/OSX/window.mm
  7. 40
      src/Avalonia.Native/AutomationNode.cs
  8. 4
      src/Avalonia.Native/Avalonia.Native.csproj
  9. 47
      src/Avalonia.Native/AvnAutomationPeer.cs
  10. 11
      src/Avalonia.Native/WindowImplBase.cs
  11. 9
      src/Avalonia.Native/avn.idl

2
native/Avalonia.Native/src/OSX/AvnString.mm

@ -160,7 +160,7 @@ NSString* GetNSStringAndRelease(IAvnString* s)
{
char* p;
if (s->Pointer((void**)&p) == S_OK)
if (s->Pointer((void**)&p) == S_OK && p != nullptr)
{
return [NSString stringWithUTF8String:p];
}

10
native/Avalonia.Native/src/OSX/automation.h

@ -1,16 +1,12 @@
#import <Cocoa/Cocoa.h>
#include "window.h"
NS_ASSUME_NONNULL_BEGIN
class IAvnAutomationPeer;
@interface AvnAutomationNode : NSAccessibilityElement
- (AvnAutomationNode *)initWithPeer:(IAvnAutomationPeer *)peer;
@interface AvnAccessibilityElement : NSAccessibilityElement
+ (AvnAccessibilityElement *) acquire:(IAvnAutomationPeer *) peer;
@end
struct INSAccessibilityHolder
{
virtual NSObject* _Nonnull GetNSAccessibility () = 0;
};
NS_ASSUME_NONNULL_END

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

@ -1,66 +1,108 @@
#import "automation.h"
#include "common.h"
#include "automation.h"
#include "AvnString.h"
#include "window.h"
class AutomationNode : public ComSingleObject<IAvnAutomationNode, &IID_IAvnAutomationNode>,
public INSAccessibilityHolder
@interface AvnAccessibilityElement (Events)
- (void) raiseChildrenChanged;
@end
@interface AvnRootAccessibilityElement : AvnAccessibilityElement
- (AvnView *) ownerView;
- (AvnRootAccessibilityElement *) initWithPeer:(IAvnAutomationPeer *) peer owner:(AvnView*) owner;
- (void) raiseFocusChanged;
@end
class AutomationNode : public ComSingleObject<IAvnAutomationNode, &IID_IAvnAutomationNode>
{
private:
NSAccessibilityElement* _node;
public:
FORWARD_IUNKNOWN()
AutomationNode(NSAccessibilityElement* node)
AutomationNode(AvnAccessibilityElement* owner)
{
_node = node;
_owner = owner;
}
AutomationNode(IAvnAutomationPeer* peer)
AvnAccessibilityElement* GetOwner()
{
_node = [[AvnAutomationNode alloc] initWithPeer: peer];
return _owner;
}
virtual void ChildrenChanged() override
virtual void Dispose() override
{
NSAccessibilityPostNotification(_node, NSAccessibilityLayoutChangedNotification);
}
virtual void PropertyChanged(AvnAutomationProperty property) override
virtual void ChildrenChanged () override
{
switch (property) {
case RangeValueProvider_Value:
NSAccessibilityPostNotification(_node, NSAccessibilityValueChangedNotification);
break;
default:
break;
}
[_owner raiseChildrenChanged];
}
virtual void FocusChanged(IAvnAutomationPeer* peer) override
virtual void PropertyChanged (AvnAutomationProperty property) override
{
// Only implemented in top-level nodes, i.e. AvnWindow.
}
virtual NSObject* GetNSAccessibility() override
virtual void FocusChanged () override
{
return _node;
[(AvnRootAccessibilityElement*)_owner raiseFocusChanged];
}
private:
AvnAccessibilityElement* _owner;
};
@implementation AvnAutomationNode
@implementation AvnAccessibilityElement
{
IAvnAutomationPeer* _peer;
AutomationNode* _node;
NSMutableArray* _children;
}
- (AvnAutomationNode *)initWithPeer:(IAvnAutomationPeer *)peer
+ (AvnAccessibilityElement *)acquire:(IAvnAutomationPeer *)peer
{
if (peer == nullptr)
return nil;
auto instance = peer->GetNode();
if (instance != nullptr)
return dynamic_cast<AutomationNode*>(instance)->GetOwner();
if (peer->IsRootProvider())
{
auto window = peer->RootProvider_GetWindow();
auto holder = dynamic_cast<INSWindowHolder*>(window);
auto view = holder->GetNSView();
return [[AvnRootAccessibilityElement alloc] initWithPeer:peer owner:view];
}
else
{
return [[AvnAccessibilityElement alloc] initWithPeer:peer];
}
}
- (AvnAccessibilityElement *)initWithPeer:(IAvnAutomationPeer *)peer
{
self = [super init];
_peer = peer;
_node = new AutomationNode(self);
_peer->SetNode(_node);
return self;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ '%@' (%p)",
GetNSStringAndRelease(_peer->GetClassName()),
GetNSStringAndRelease(_peer->GetName()),
_peer];
}
- (IAvnAutomationPeer *)peer
{
return _peer;
}
- (BOOL)isAccessibilityElement
{
return _peer->IsControlElement();
@ -96,7 +138,7 @@ public:
case AutomationToolBar: return NSAccessibilityToolbarRole;
case AutomationToolTip: return NSAccessibilityPopoverRole;
case AutomationTree: return NSAccessibilityOutlineRole;
case AutomationTreeItem: return NSAccessibilityOutlineRowSubrole;
case AutomationTreeItem: return NSAccessibilityCellRole;
case AutomationCustom: return NSAccessibilityUnknownRole;
case AutomationGroup: return NSAccessibilityGroupRole;
case AutomationThumb: return NSAccessibilityHandleRole;
@ -110,8 +152,10 @@ public:
case AutomationHeaderItem: return NSAccessibilityButtonRole;
case AutomationTable: return NSAccessibilityTableRole;
case AutomationTitleBar: return NSAccessibilityGroupRole;
case AutomationSeparator: return NSAccessibilityUnknownRole;
default: return NSAccessibilityUnknownRole;
// Treat unknown roles as generic group container items. Returning
// NSAccessibilityUnknownRole is also possible but makes the screen
// reader focus on the item instead of passing focus to child items.
default: return NSAccessibilityGroupRole;
}
}
@ -177,6 +221,15 @@ public:
return [super accessibilityMaxValue];
}
- (BOOL)isAccessibilityEnabled
{
return _peer->IsEnabled();
}
- (BOOL)isAccessibilityFocused
{
return _peer->HasKeyboardFocus();
}
- (NSArray *)accessibilityChildren
{
@ -195,52 +248,55 @@ public:
if (childPeers->Get(i, &child) == S_OK)
{
NSObject* element = ::GetAccessibilityElement(child->GetNode());
auto element = [AvnAccessibilityElement acquire:child];
[_children addObject:element];
}
}
}
}
return _children;
}
- (NSRect)accessibilityFrame
{
auto view = [self getAvnView];
auto window = [self getAvnWindow];
id topLevel = [self accessibilityTopLevelUIElement];
auto result = NSZeroRect;
if (view != nullptr)
if ([topLevel isKindOfClass:[AvnRootAccessibilityElement class]])
{
auto bounds = ToNSRect(_peer->GetBoundingRectangle());
auto windowBounds = [view convertRect:bounds toView:nil];
auto screenBounds = [window convertRectToScreen:windowBounds];
return screenBounds;
auto root = (AvnRootAccessibilityElement*)topLevel;
auto view = [root ownerView];
if (view)
{
auto window = [view window];
auto bounds = ToNSRect(_peer->GetBoundingRectangle());
auto windowBounds = [view convertRect:bounds toView:nil];
auto screenBounds = [window convertRectToScreen:windowBounds];
result = screenBounds;
}
}
return NSRect();
return result;
}
- (id)accessibilityParent
{
auto parentPeer = _peer->GetParent();
if (parentPeer != nullptr)
{
return GetAccessibilityElement(parentPeer);
}
return [NSApplication sharedApplication];
return parentPeer ? [AvnAccessibilityElement acquire:parentPeer] : [NSApplication sharedApplication];
}
- (id)accessibilityTopLevelUIElement
{
return GetAccessibilityElement([self getRootNode]);
auto rootPeer = _peer->GetRootPeer();
return [AvnAccessibilityElement acquire:rootPeer];
}
- (id)accessibilityWindow
{
return [self accessibilityTopLevelUIElement];
id topLevel = [self accessibilityTopLevelUIElement];
return [topLevel isKindOfClass:[NSWindow class]] ? topLevel : nil;
}
- (BOOL)isAccessibilityExpanded
@ -326,58 +382,68 @@ public:
return [super isAccessibilitySelectorAllowed:selector];
}
- (IAvnAutomationNode*)getRootNode
- (void)raiseChildrenChanged
{
auto rootPeer = _peer->GetRootPeer();
return rootPeer != nullptr ? rootPeer->GetNode() : nullptr;
NSAccessibilityPostNotification(self, NSAccessibilityLayoutChangedNotification);
}
- (IAvnWindowBase*)getWindow
- (void)raisePropertyChanged
{
auto rootNode = [self getRootNode];
}
if (rootNode != nullptr)
{
IAvnWindowBase* window;
if (rootNode->QueryInterface(&IID_IAvnWindow, (void**)&window) == S_OK)
{
return window;
}
}
return nullptr;
- (void)setAccessibilityFocused:(BOOL)accessibilityFocused
{
if (accessibilityFocused)
_peer->SetFocus();
}
- (AvnWindow*) getAvnWindow
@end
@implementation AvnRootAccessibilityElement
{
auto window = [self getWindow];
return window != nullptr ? dynamic_cast<INSWindowHolder*>(window)->GetNSWindow() : nullptr;
AvnView* _owner;
}
- (AvnView*) getAvnView
- (AvnRootAccessibilityElement *)initWithPeer:(IAvnAutomationPeer *)peer owner:(AvnView *)owner
{
auto window = [self getWindow];
return window != nullptr ? dynamic_cast<INSWindowHolder*>(window)->GetNSView() : nullptr;
self = [super initWithPeer:peer];
_owner = owner;
return self;
}
@end
- (AvnView *)ownerView
{
return _owner;
}
extern IAvnAutomationNode* CreateAutomationNode(IAvnAutomationPeer* peer)
- (id)accessibilityFocusedUIElement
{
@autoreleasepool
{
return new AutomationNode(peer);
}
auto focusedPeer = [self peer]->RootProvider_GetFocus();
return [AvnAccessibilityElement acquire:focusedPeer];
}
extern NSObject* GetAccessibilityElement(IAvnAutomationPeer* peer)
- (id)accessibilityHitTest:(NSPoint)point
{
auto node = peer != nullptr ? peer->GetNode() : nullptr;
return GetAccessibilityElement(node);
auto clientPoint = [[_owner window] convertPointFromScreen:point];
auto localPoint = [_owner translateLocalPoint:ToAvnPoint(clientPoint)];
auto hit = [self peer]->RootProvider_GetPeerFromPoint(localPoint);
return [AvnAccessibilityElement acquire:hit];
}
extern NSObject* GetAccessibilityElement(IAvnAutomationNode* node)
- (id)accessibilityParent
{
auto holder = dynamic_cast<INSAccessibilityHolder*>(node);
return holder != nullptr ? holder->GetNSAccessibility() : nil;
return _owner;
}
- (void)raiseFocusChanged
{
id focused = [self accessibilityFocusedUIElement];
NSAccessibilityPostNotification(focused, NSAccessibilityFocusedUIElementChangedNotification);
}
- (void)accessibilityPerformAction:(NSAccessibilityActionName)action
{
[_owner accessibilityPerformAction:action];
}
@end

3
native/Avalonia.Native/src/OSX/common.h

@ -31,9 +31,6 @@ extern IAvnMenu* GetAppMenu ();
extern NSMenuItem* GetAppMenuItem ();
extern void SetAutoGenerateDefaultAppMenuItems (bool enabled);
extern bool GetAutoGenerateDefaultAppMenuItems ();
extern IAvnAutomationNode* CreateAutomationNode(IAvnAutomationPeer* peer);
extern NSObject* GetAccessibilityElement(IAvnAutomationPeer* peer);
extern NSObject* GetAccessibilityElement(IAvnAutomationNode* node);
extern void InitializeAvnApp(IAvnApplicationEvents* events);
extern NSApplicationActivationPolicy AvnDesiredActivationPolicy;

8
native/Avalonia.Native/src/OSX/main.mm

@ -347,13 +347,7 @@ public:
return S_OK;
}
}
virtual HRESULT CreateAutomationNode (IAvnAutomationPeer* peer, IAvnAutomationNode** ppv) override
{
*ppv = ::CreateAutomationNode(peer);
return S_OK;
}
virtual HRESULT SetAppMenu (IAvnMenu* appMenu) override
{
START_COM_CALL;

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

@ -10,9 +10,7 @@
class WindowBaseImpl : public virtual ComObject,
public virtual IAvnWindowBase,
public virtual IAvnAutomationNode,
public INSWindowHolder,
public INSAccessibilityHolder
public INSWindowHolder
{
private:
NSCursor* cursor;
@ -21,7 +19,6 @@ public:
FORWARD_IUNKNOWN()
BEGIN_INTERFACE_MAP()
INTERFACE_MAP_ENTRY(IAvnWindowBase, IID_IAvnWindowBase)
INTERFACE_MAP_ENTRY(IAvnAutomationNode, IID_IAvnAutomationNode)
END_INTERFACE_MAP()
virtual ~WindowBaseImpl()
@ -131,11 +128,6 @@ public:
return View;
}
virtual NSObject* GetNSAccessibility() override
{
return Window;
}
virtual HRESULT Show(bool activate, bool isDialog) override
{
START_COM_CALL;
@ -603,25 +595,6 @@ public:
return S_OK;
}
virtual void ChildrenChanged() override
{
NSAccessibilityPostNotification(Window, NSAccessibilityLayoutChangedNotification);
}
virtual void PropertyChanged(AvnAutomationProperty property) override
{
}
virtual void FocusChanged(IAvnAutomationPeer* peer) override
{
auto element = GetAccessibilityElement(peer);
if (element != nullptr)
{
NSAccessibilityPostNotification(element, NSAccessibilityFocusedUIElementChangedNotification);
}
}
virtual bool IsDialog()
{
return false;
@ -1432,6 +1405,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
AvnPixelSize _lastPixelSize;
NSObject<IRenderTarget>* _renderTarget;
AvnPlatformResizeReason _resizeReason;
AvnAccessibilityElement* _accessibilityChild;
}
- (void)onClosed
@ -2055,6 +2029,37 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
_resizeReason = reason;
}
- (AvnAccessibilityElement *) accessibilityChild
{
if (_accessibilityChild == nil)
{
auto peer = _parent->BaseEvents->GetAutomationPeer();
if (peer == nil)
return nil;
_accessibilityChild = [AvnAccessibilityElement acquire:peer];
}
return _accessibilityChild;
}
- (NSArray *)accessibilityChildren
{
auto child = [self accessibilityChild];
return NSAccessibilityUnignoredChildrenForOnlyChild(child);
}
- (id)accessibilityHitTest:(NSPoint)point
{
return [[self accessibilityChild] accessibilityHitTest:point];
}
- (id)accessibilityFocusedUIElement
{
return [[self accessibilityChild] accessibilityFocusedUIElement];
}
@end
@ -2466,75 +2471,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
}
}
- (BOOL)isAccessibilityElement
{
[self getAutomationPeer];
return YES;
}
- (NSString *)accessibilityIdentifier
{
auto peer = [self getAutomationPeer];
return GetNSStringAndRelease(peer->GetAutomationId());
}
- (NSArray *)accessibilityChildren
{
auto peer = [self getAutomationPeer];
if (_automationChildren == nullptr)
{
_automationChildren = (NSMutableArray*)[super accessibilityChildren];
auto childPeers = peer->GetChildren();
auto childCount = childPeers != nullptr ? childPeers->GetCount() : 0;
if (childCount > 0)
{
for (int i = 0; i < childCount; ++i)
{
IAvnAutomationPeer* child;
if (childPeers->Get(i, &child) == S_OK)
{
auto element = GetAccessibilityElement(child);
[_automationChildren addObject:element];
}
}
}
}
return _automationChildren;
}
- (id)accessibilityHitTest:(NSPoint)point
{
point = [self convertPointFromScreen:point];
auto p = [_parent->View translateLocalPoint:ToAvnPoint(point)];
auto peer = [self getAutomationPeer];
auto hit = peer->RootProvider_GetPeerFromPoint(p);
return GetAccessibilityElement(hit);
}
- (id)accessibilityFocusedUIElement
{
auto peer = [self getAutomationPeer];
if (peer->IsRootProvider())
{
return GetAccessibilityElement(peer->RootProvider_GetFocus());
}
return [super accessibilityFocusedUIElement];
}
- (IAvnAutomationPeer*) getAutomationPeer
{
if (_automationPeer == nullptr)
_automationPeer = _parent->BaseEvents->AutomationStarted(_parent);
return _automationPeer;
}
@end
class PopupImpl : public virtual WindowBaseImpl, public IAvnPopup

40
src/Avalonia.Native/AutomationNode.cs

@ -1,40 +0,0 @@
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Native.Interop;
#nullable enable
namespace Avalonia.Native
{
internal class AutomationNode
{
public AutomationNode(IAvnAutomationNode native)
{
Native = native;
}
public IAvnAutomationNode Native { get; }
public void ChildrenChanged() => Native.ChildrenChanged();
public void PropertyChanged(AutomationProperty property, object? oldValue, object? newValue)
{
AvnAutomationProperty p;
if (property == AutomationElementIdentifiers.BoundingRectangleProperty)
p = AvnAutomationProperty.AutomationPeer_BoundingRectangle;
else if (property == AutomationElementIdentifiers.ClassNameProperty)
p = AvnAutomationProperty.AutomationPeer_ClassName;
else if (property == AutomationElementIdentifiers.NameProperty)
p = AvnAutomationProperty.AutomationPeer_Name;
else if (property == RangeValuePatternIdentifiers.ValueProperty)
p = AvnAutomationProperty.RangeValueProvider_Value;
else
return;
Native.PropertyChanged(p);
}
public void FocusChanged(AutomationPeer? focus) => Native.FocusChanged(AvnAutomationPeer.Wrap(focus));
}
}

4
src/Avalonia.Native/Avalonia.Native.csproj

@ -16,6 +16,10 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />

47
src/Avalonia.Native/AvnAutomationPeer.cs

@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;
using Avalonia.Controls;
using Avalonia.Native.Interop;
#nullable enable
@ -12,11 +15,20 @@ namespace Avalonia.Native
{
internal class AvnAutomationPeer : CallbackBase, IAvnAutomationPeer
{
private static readonly ConditionalWeakTable<AutomationPeer, AvnAutomationPeer> s_wrappers = new();
private readonly AutomationPeer _inner;
public AvnAutomationPeer(AutomationPeer inner) => _inner = inner;
private AvnAutomationPeer(AutomationPeer inner)
{
_inner = inner;
_inner.ChildrenChanged += (_, _) => Node?.ChildrenChanged();
if (inner is WindowBaseAutomationPeer window)
window.FocusChanged += (_, _) => Node?.FocusChanged();
}
public IAvnAutomationNode Node => throw new NotImplementedException();
~AvnAutomationPeer() => Node?.Dispose();
public IAvnAutomationNode? Node { get; private set; }
public IAvnString? AcceleratorKey => _inner.GetAcceleratorKey().ToAvnString();
public IAvnString? AccessKey => _inner.GetAccessKey().ToAvnString();
public AvnAutomationControlType AutomationControlType => (AvnAutomationControlType)_inner.GetAutomationControlType();
@ -43,17 +55,31 @@ namespace Avalonia.Native
var peer = _inner;
var parent = peer.GetParent();
while (!(peer is IRootProvider) && parent is object)
while (peer is not IRootProvider && parent is not null)
{
peer = parent;
parent = peer.GetParent();
}
return new AvnAutomationPeer(peer);
return Wrap(peer);
}
}
public void SetNode(IAvnAutomationNode node)
{
if (Node is not null)
throw new InvalidOperationException("The AvnAutomationPeer already has a node.");
Node = node;
}
public int IsRootProvider() => (_inner is IRootProvider).AsComBool();
public IAvnWindowBase RootProvider_GetWindow()
{
var window = (WindowBase)((ControlAutomationPeer)_inner).Owner;
return ((WindowBaseImpl)window.PlatformImpl!).Native;
}
public IAvnAutomationPeer? RootProvider_GetFocus() => Wrap(((IRootProvider)_inner).GetFocus());
public IAvnAutomationPeer? RootProvider_GetPeerFromPoint(AvnPoint point)
@ -68,7 +94,7 @@ namespace Avalonia.Native
{
var parent = result.GetParent();
if (parent is object)
if (parent is not null)
result = parent;
else
break;
@ -108,9 +134,12 @@ namespace Avalonia.Native
public int IsValueProvider() => (_inner is IValueProvider).AsComBool();
public IAvnString ValueProvider_GetValue() => ((IValueProvider)_inner).Value.ToAvnString();
public void ValueProvider_SetValue(string value) => ((IValueProvider)_inner).SetValue(value);
public static AvnAutomationPeer? Wrap(AutomationPeer? peer) =>
peer != null ? new AvnAutomationPeer(peer) : null;
[return: NotNullIfNotNull("peer")]
public static AvnAutomationPeer? Wrap(AutomationPeer? peer)
{
return peer is null ? null : s_wrappers.GetValue(peer, x => new(peer));
}
}
internal class AvnAutomationPeerArray : CallbackBase, IAvnAutomationPeerArray
@ -119,7 +148,7 @@ namespace Avalonia.Native
public AvnAutomationPeerArray(IReadOnlyList<AutomationPeer> items)
{
_items = items.Select(x => new AvnAutomationPeer(x)).ToArray();
_items = items.Select(x => AvnAutomationPeer.Wrap(x)).ToArray();
}
public uint Count => (uint)_items.Length;

11
src/Avalonia.Native/WindowImplBase.cs

@ -62,7 +62,6 @@ namespace Avalonia.Native
private GlPlatformSurface _glSurface;
private NativeControlHostImpl _nativeControlHost;
private IGlContext _glContext;
private AvnAutomationPeer _automationPeer;
internal WindowBaseImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
AvaloniaNativePlatformOpenGlInterface glFeature)
@ -158,6 +157,11 @@ namespace Avalonia.Native
public IMouseDevice MouseDevice => _mouse;
public abstract IPopupImpl CreatePopup();
public AutomationPeer GetAutomationPeer()
{
return _inputRoot is Control c ? ControlAutomationPeer.CreatePeerForElement(c) : null;
}
protected unsafe class WindowBaseEvents : CallbackBase, IAvnWindowBaseEvents
{
private readonly WindowBaseImpl _parent;
@ -262,6 +266,11 @@ namespace Avalonia.Native
return (AvnDragDropEffects)args.Effects;
}
}
IAvnAutomationPeer IAvnWindowBaseEvents.AutomationPeer
{
get => AvnAutomationPeer.Wrap(_parent.GetAutomationPeer());
}
}
public void Activate()

9
src/Avalonia.Native/avn.idl

@ -419,6 +419,7 @@ enum AvnPlatformResizeReason
enum AvnAutomationControlType
{
AutomationNone,
AutomationButton,
AutomationCalendar,
AutomationCheckBox,
@ -480,7 +481,6 @@ interface IAvaloniaNativeFactory : IUnknown
HRESULT CreateMenuItem(IAvnMenuItem** ppv);
HRESULT CreateMenuItemSeparator(IAvnMenuItem** ppv);
HRESULT CreateTrayIcon(IAvnTrayIcon** ppv);
HRESULT CreateAutomationNode(IAvnAutomationPeer* peer, IAvnAutomationNode** ppv);
}
[uuid(233e094f-9b9f-44a3-9a6e-6948bbdd9fb1)]
@ -570,6 +570,7 @@ interface IAvnWindowBaseEvents : IUnknown
AvnDragDropEffects DragEvent(AvnDragEventType type, AvnPoint position,
AvnInputModifiers modifiers, AvnDragDropEffects effects,
IAvnClipboard* clipboard, [intptr]void* dataObjectHandle);
IAvnAutomationPeer* GetAutomationPeer();
}
[uuid(1ae178ee-1fcc-447f-b6dd-b7bb727f934c)]
@ -811,6 +812,8 @@ interface IAvnApplicationEvents : IUnknown
interface IAvnAutomationPeer : IUnknown
{
IAvnAutomationNode* GetNode();
void SetNode(IAvnAutomationNode* node);
IAvnString* GetAcceleratorKey();
IAvnString* GetAccessKey();
AvnAutomationControlType GetAutomationControlType();
@ -832,6 +835,7 @@ interface IAvnAutomationPeer : IUnknown
IAvnAutomationPeer* GetRootPeer();
bool IsRootProvider();
IAvnWindowBase* RootProvider_GetWindow();
IAvnAutomationPeer* RootProvider_GetFocus();
IAvnAutomationPeer* RootProvider_GetPeerFromPoint(AvnPoint point);
@ -871,7 +875,8 @@ interface IAvnAutomationPeerArray : IUnknown
[uuid(004dc40b-e435-49dc-bac5-6272ee35382a)]
interface IAvnAutomationNode : IUnknown
{
void Dispose();
void ChildrenChanged();
void PropertyChanged(AvnAutomationProperty property);
void FocusChanged(IAvnAutomationPeer* peer);
void FocusChanged();
}

Loading…
Cancel
Save