Browse Source

More OSX accessibility implementation.

ui-automation-test
Steven Kirk 6 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); NSAccessibilityPostNotification(_node, NSAccessibilityLayoutChangedNotification);
} }
virtual void PropertyChanged(AvnAutomationProperty property) override
{
switch (property) {
case RangeValueProvider_Value:
NSAccessibilityPostNotification(_node, NSAccessibilityValueChangedNotification);
break;
default:
break;
}
}
virtual NSObject* GetNSAccessibility() override virtual NSObject* GetNSAccessibility() override
{ {
return _node; return _node;
@ -75,7 +86,7 @@ public:
case AutomationStatusBar: return NSAccessibilityTableRole; case AutomationStatusBar: return NSAccessibilityTableRole;
case AutomationTab: return NSAccessibilityTabGroupRole; case AutomationTab: return NSAccessibilityTabGroupRole;
case AutomationTabItem: return NSAccessibilityRadioButtonRole; case AutomationTabItem: return NSAccessibilityRadioButtonRole;
case AutomationText: return NSAccessibilityTextFieldRole; case AutomationText: return NSAccessibilityStaticTextRole;
case AutomationToolBar: return NSAccessibilityToolbarRole; case AutomationToolBar: return NSAccessibilityToolbarRole;
case AutomationToolTip: return NSAccessibilityPopoverRole; case AutomationToolTip: return NSAccessibilityPopoverRole;
case AutomationTree: return NSAccessibilityOutlineRole; case AutomationTree: return NSAccessibilityOutlineRole;
@ -105,7 +116,39 @@ public:
- (NSString *)accessibilityTitle - (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 - (NSArray *)accessibilityChildren
@ -175,16 +218,43 @@ public:
- (BOOL)accessibilityPerformPress - (BOOL)accessibilityPerformPress
{ {
if (!_peer->IsInvokeProvider())
return NO;
_peer->InvokeProvider_Invoke(); _peer->InvokeProvider_Invoke();
return YES; 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 - (BOOL)isAccessibilitySelectorAllowed:(SEL)selector
{ {
if (selector == @selector(accessibilityPerformPress)) if (selector == @selector(accessibilityPerformPress))
{ {
return _peer->IsInvokeProvider(); return _peer->IsInvokeProvider();
} }
else if (selector == @selector(accessibilityPerformIncrement) ||
selector == @selector(accessibilityPerformDecrement))
{
return _peer->IsRangeValueProvider();
}
return [super isAccessibilitySelectorAllowed:selector]; return [super isAccessibilitySelectorAllowed:selector];
} }

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

@ -514,6 +514,10 @@ public:
NSAccessibilityPostNotification(Window, NSAccessibilityLayoutChangedNotification); NSAccessibilityPostNotification(Window, NSAccessibilityLayoutChangedNotification);
} }
virtual void PropertyChanged(AvnAutomationProperty property) override
{
}
protected: protected:
virtual NSWindowStyleMask GetStyle() 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 Maximum => Owner.Maximum;
public double Minimum => Owner.Minimum; public double Minimum => Owner.Minimum;
public double Value => Owner.Value; public double Value => Owner.Value;
public double SmallChange => Owner.SmallChange;
public double LargeChange => Owner.LargeChange;
public void SetValue(double value) => Owner.Value = value; public void SetValue(double value) => Owner.Value = value;
protected virtual void OwnerPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) 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> /// </summary>
double Value { get; } 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> /// <summary>
/// Sets the value of the control. /// Sets the value of the control.
/// </summary> /// </summary>

15
src/Avalonia.Native/AutomationNode.cs

@ -22,7 +22,20 @@ namespace Avalonia.Native
public void PropertyChanged(AutomationProperty property, object? oldValue, object? newValue) 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) 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 int IsInvokeProvider() => (_inner is IInvokeProvider).AsComBool();
public void InvokeProvider_Invoke() => ((IInvokeProvider)_inner).Invoke(); 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) => public static AvnAutomationPeer? Wrap(AutomationPeer? peer) =>
peer != null ? new AvnAutomationPeer(peer) : null; peer != null ? new AvnAutomationPeer(peer) : null;

23
src/Avalonia.Native/avn.idl

@ -218,6 +218,14 @@ enum SystemDecorations {
SystemDecorationsFull = 2, SystemDecorationsFull = 2,
} }
enum AvnAutomationProperty
{
AutomationPeer_BoundingRectangle,
AutomationPeer_ClassName,
AutomationPeer_Name,
RangeValueProvider_Value,
}
struct AvnSize struct AvnSize
{ {
double Width, Height; double Width, Height;
@ -808,6 +816,20 @@ interface IAvnAutomationPeer : IUnknown
bool IsInvokeProvider(); bool IsInvokeProvider();
void InvokeProvider_Invoke(); 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)] [uuid(b00af5da-78af-4b33-bfff-4ce13a6239a9)]
@ -821,4 +843,5 @@ interface IAvnAutomationPeerArray : IUnknown
interface IAvnAutomationNode : IUnknown interface IAvnAutomationNode : IUnknown
{ {
void ChildrenChanged(); void ChildrenChanged();
void PropertyChanged(AvnAutomationProperty property);
} }

Loading…
Cancel
Save