Browse Source

More OSX accessibility implementation.

ui-automation-test
Steven Kirk 5 years ago
parent
commit
7bbbfa414f
  1. 74
      native/Avalonia.Native/src/OSX/automation.mm
  2. 4
      native/Avalonia.Native/src/OSX/window.mm
  3. 3
      src/Avalonia.Controls/Automation/Peers/RangeBaseAutomationPeer.cs
  4. 12
      src/Avalonia.Controls/Automation/Provider/IRangeValueProvider.cs
  5. 15
      src/Avalonia.Native/AutomationNode.cs
  6. 15
      src/Avalonia.Native/AvnAutomationPeer.cs
  7. 23
      src/Avalonia.Native/avn.idl

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

@ -26,6 +26,17 @@ public:
NSAccessibilityPostNotification(_node, NSAccessibilityLayoutChangedNotification);
}
virtual void PropertyChanged(AvnAutomationProperty property) override
{
switch (property) {
case RangeValueProvider_Value:
NSAccessibilityPostNotification(_node, NSAccessibilityValueChangedNotification);
break;
default:
break;
}
}
virtual NSObject* GetNSAccessibility() override
{
return _node;
@ -75,7 +86,7 @@ public:
case AutomationStatusBar: return NSAccessibilityTableRole;
case AutomationTab: return NSAccessibilityTabGroupRole;
case AutomationTabItem: return NSAccessibilityRadioButtonRole;
case AutomationText: return NSAccessibilityTextFieldRole;
case AutomationText: return NSAccessibilityStaticTextRole;
case AutomationToolBar: return NSAccessibilityToolbarRole;
case AutomationToolTip: return NSAccessibilityPopoverRole;
case AutomationTree: return NSAccessibilityOutlineRole;
@ -105,7 +116,39 @@ public:
- (NSString *)accessibilityTitle
{
return GetNSStringAndRelease(_peer->GetName());
// StaticText exposes its text via the value property.
if (_peer->GetAutomationControlType() != AutomationText)
{
return GetNSStringAndRelease(_peer->GetName());
}
return [super accessibilityTitle];
}
- (id)accessibilityValue
{
if (_peer->IsRangeValueProvider())
{
return [NSNumber numberWithDouble:_peer->RangeValueProvider_GetValue()];
}
else if (_peer->IsToggleProvider())
{
switch (_peer->ToggleProvider_GetToggleState()) {
case 0: return [NSNumber numberWithBool:NO];
case 1: return [NSNumber numberWithBool:YES];
default: return [NSNumber numberWithInt:-1];
}
}
else if (_peer->IsValueProvider())
{
return GetNSStringAndRelease(_peer->ValueProvider_GetValue());
}
else if (_peer->GetAutomationControlType() == AutomationText)
{
return GetNSStringAndRelease(_peer->GetName());
}
return [super accessibilityValue];
}
- (NSArray *)accessibilityChildren
@ -175,16 +218,43 @@ public:
- (BOOL)accessibilityPerformPress
{
if (!_peer->IsInvokeProvider())
return NO;
_peer->InvokeProvider_Invoke();
return YES;
}
- (BOOL)accessibilityPerformIncrement
{
if (!_peer->IsRangeValueProvider())
return NO;
auto value = _peer->RangeValueProvider_GetValue();
value += _peer->RangeValueProvider_GetSmallChange();
_peer->RangeValueProvider_SetValue(value);
return YES;
}
- (BOOL)accessibilityPerformDecrement
{
if (!_peer->IsRangeValueProvider())
return NO;
auto value = _peer->RangeValueProvider_GetValue();
value -= _peer->RangeValueProvider_GetSmallChange();
_peer->RangeValueProvider_SetValue(value);
return YES;
}
- (BOOL)isAccessibilitySelectorAllowed:(SEL)selector
{
if (selector == @selector(accessibilityPerformPress))
{
return _peer->IsInvokeProvider();
}
else if (selector == @selector(accessibilityPerformIncrement) ||
selector == @selector(accessibilityPerformDecrement))
{
return _peer->IsRangeValueProvider();
}
return [super isAccessibilitySelectorAllowed:selector];
}

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

@ -514,6 +514,10 @@ public:
NSAccessibilityPostNotification(Window, NSAccessibilityLayoutChangedNotification);
}
virtual void PropertyChanged(AvnAutomationProperty property) override
{
}
protected:
virtual NSWindowStyleMask GetStyle()
{

3
src/Avalonia.Controls/Automation/Peers/RangeBaseAutomationPeer.cs

@ -19,6 +19,9 @@ namespace Avalonia.Automation.Peers
public double Maximum => Owner.Maximum;
public double Minimum => Owner.Minimum;
public double Value => Owner.Value;
public double SmallChange => Owner.SmallChange;
public double LargeChange => Owner.LargeChange;
public void SetValue(double value) => Owner.Value = value;
protected virtual void OwnerPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)

12
src/Avalonia.Controls/Automation/Provider/IRangeValueProvider.cs

@ -28,6 +28,18 @@ namespace Avalonia.Automation.Provider
/// </summary>
double Value { get; }
/// <summary>
/// Gets the value that is added to or subtracted from the Value property when a large
/// change is made, such as with the PAGE DOWN key.
/// </summary>
double LargeChange { get; }
/// <summary>
/// Gets the value that is added to or subtracted from the Value property when a small
/// change is made, such as with an arrow key.
/// </summary>
double SmallChange { get; }
/// <summary>
/// Sets the value of the control.
/// </summary>

15
src/Avalonia.Native/AutomationNode.cs

@ -22,7 +22,20 @@ namespace Avalonia.Native
public void PropertyChanged(AutomationProperty property, object? oldValue, object? newValue)
{
// TODO
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)

15
src/Avalonia.Native/AvnAutomationPeer.cs

@ -75,8 +75,21 @@ namespace Avalonia.Native
}
public int IsInvokeProvider() => (_inner is IInvokeProvider).AsComBool();
public void InvokeProvider_Invoke() => ((IInvokeProvider)_inner).Invoke();
public int IsRangeValueProvider() => (_inner is IRangeValueProvider).AsComBool();
public double RangeValueProvider_GetValue() => ((IRangeValueProvider)_inner).Value;
public double RangeValueProvider_GetSmallChange() => ((IRangeValueProvider)_inner).SmallChange;
public double RangeValueProvider_GetLargeChange() => ((IRangeValueProvider)_inner).LargeChange;
public void RangeValueProvider_SetValue(double value) => ((IRangeValueProvider)_inner).SetValue(value);
public int IsToggleProvider() => (_inner is IToggleProvider).AsComBool();
public int ToggleProvider_GetToggleState() => (int)((IToggleProvider)_inner).ToggleState;
public void ToggleProvider_Toggle() => ((IToggleProvider)_inner).Toggle();
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;

23
src/Avalonia.Native/avn.idl

@ -218,6 +218,14 @@ enum SystemDecorations {
SystemDecorationsFull = 2,
}
enum AvnAutomationProperty
{
AutomationPeer_BoundingRectangle,
AutomationPeer_ClassName,
AutomationPeer_Name,
RangeValueProvider_Value,
}
struct AvnSize
{
double Width, Height;
@ -808,6 +816,20 @@ interface IAvnAutomationPeer : IUnknown
bool IsInvokeProvider();
void InvokeProvider_Invoke();
bool IsRangeValueProvider();
double RangeValueProvider_GetValue();
double RangeValueProvider_GetSmallChange();
double RangeValueProvider_GetLargeChange();
void RangeValueProvider_SetValue(double value);
bool IsToggleProvider();
int ToggleProvider_GetToggleState();
void ToggleProvider_Toggle();
bool IsValueProvider();
IAvnString* ValueProvider_GetValue();
void ValueProvider_SetValue(char* value);
}
[uuid(b00af5da-78af-4b33-bfff-4ce13a6239a9)]
@ -821,4 +843,5 @@ interface IAvnAutomationPeerArray : IUnknown
interface IAvnAutomationNode : IUnknown
{
void ChildrenChanged();
void PropertyChanged(AvnAutomationProperty property);
}

Loading…
Cancel
Save