Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add NSAccessibilityElement to an existing NSView

I want to use MacOS accessibility feature with my application which renders its own custom UI (i.e. not using Cocoa). For this I implement a tree of subclassed NSAccessibilityElements associated with each widget I draw. The root UI container is hosted inside an NSView provided to my application externally (my application is a plugin). Now I need to attach my tree of NSAccessibilityElements to the existing NSView provided by the host.

Apple documentation recommends two ways to achieve this:

  • Reimplement parent's accessibilityChildren property to include custom elements (Qt uses this method for example). Unfortunately I do not create the parent NSView myself, it gets injected externally.
  • Call accessibilityAddChildElement convenience method. But when I call it on provided NSView object, I get an exception that it does not respond to this method.

What would be the right way to attach a tree of NSAccessibilityElements to an exiting NSView?

like image 863
Archie Avatar asked Dec 20 '25 04:12

Archie


1 Answers

So I ended up subclassing NSView to capture the top level NSAccessibilityElement. Overridden - (NSArray*) accessibilityChildren method returns that captured accessibility element as one of its children:

@interface AccessibilityRootView : NSView
- (instancetype)initWithAccessibilityElement: (NSAccessibilityElement*)anElement;
@end

@implementation AccessibilityRootView
{
    NSAccessibilityElement* element;
}

- (instancetype) initWithAccessibilityElement: (NSAccessibilityElement*)anElement
{
    self = [super init];

    if (self)
        element = anElement;

    return self;
}

- (NSArray*) accessibilityChildren
{
    NSArray<NSAccessibilityElement*> *children = [super accessibilityChildren];

    int numKids = (int)[children count] + 1;
    NSMutableArray<NSAccessibilityElement*> *kids = [NSMutableArray<NSAccessibilityElement*> arrayWithCapacity:numKids];

    for (id object in children)
        [kids addObject:object];

    [kids addObject: element];

    return NSAccessibilityUnignoredChildren (kids);
}
@end

I then attach this subclassed view of zero size to the parent NSView provided by the host:

NSView* hostView = /* host-provided NSView */;
AccessibilityRootView* accessibilityRootView = [[AccessibilityRootView alloc] initWithAccessibilityElement:(NSAccessibilityElement*)topLevelAccessibilityElement];
[hostView addSubview:accessibilityRootView];
[accessibilityRootView release];

At this point all my NSAccessibilityElements are attached to that zero-size view that lives in the host-provided view, and MacOS can successfully query the items.

Additionally each NSAccessibilityElement had to implement correctly its - (NSRect)accessibilityFrame and - (id) accessibilityHitTest:(NSPoint)point to match the screen position of my custom drawn UI widgets.

like image 189
Archie Avatar answered Dec 21 '25 18:12

Archie



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!