Browse Source
Follows WPF/UWP API as closely as possible. Limited to win32 right now. Broken in many places.ui-automation-test
111 changed files with 4649 additions and 33 deletions
@ -0,0 +1,28 @@ |
|||||
|
using Avalonia.Automation.Peers; |
||||
|
|
||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains values used as automation property identifiers by UI Automation providers.
|
||||
|
/// </summary>
|
||||
|
public static class AutomationElementIdentifiers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Identifies the bounding rectangle automation property. The bounding rectangle property
|
||||
|
/// value is returned by the <see cref="AutomationPeer.GetBoundingRectangle"/> method.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty BoundingRectangleProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the class name automation property. The class name property value is returned
|
||||
|
/// by the <see cref="AutomationPeer.GetClassName"/> method.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty ClassNameProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the name automation property. The class name property value is returned
|
||||
|
/// by the <see cref="AutomationPeer.GetName"/> method.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty NameProperty { get; } = new(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Describes the notification characteristics of a particular live region
|
||||
|
/// </summary>
|
||||
|
public enum AutomationLiveSetting |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The element does not send notifications if the content of the live region has changed.
|
||||
|
/// </summary>
|
||||
|
Off = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The element sends non-interruptive notifications if the content of the live region has
|
||||
|
/// changed. With this setting, UI Automation clients and assistive technologies are expected
|
||||
|
/// to not interrupt the user to inform of changes to the live region.
|
||||
|
/// </summary>
|
||||
|
Polite = 1, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The element sends interruptive notifications if the content of the live region has changed.
|
||||
|
/// With this setting, UI Automation clients and assistive technologies are expected to interrupt
|
||||
|
/// the user to inform of changes to the live region.
|
||||
|
/// </summary>
|
||||
|
Assertive = 2, |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,539 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
public static class AutomationProperties |
||||
|
{ |
||||
|
internal const int AutomationPositionInSetDefault = -1; |
||||
|
internal const int AutomationSizeOfSetDefault = -1; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.AcceleratorKey attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<string> AcceleratorKeyProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, string>( |
||||
|
"AcceleratorKey", |
||||
|
typeof(AutomationProperties)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.AccessKey attached property
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<string> AccessKeyProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, string>( |
||||
|
"AccessKey", |
||||
|
typeof(AutomationProperties)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.AutomationId attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<string> AutomationIdProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, string>( |
||||
|
"AutomationId", |
||||
|
typeof(AutomationProperties)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.HelpText attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<string> HelpTextProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, string>( |
||||
|
"HelpText", |
||||
|
typeof(AutomationProperties)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.IsColumnHeader attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<bool> IsColumnHeaderProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, bool>( |
||||
|
"IsColumnHeader", |
||||
|
typeof(AutomationProperties), |
||||
|
false); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.IsRequiredForForm attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<bool> IsRequiredForFormProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, bool>( |
||||
|
"IsRequiredForForm", |
||||
|
typeof(AutomationProperties), |
||||
|
false); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.IsRowHeader attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<bool> IsRowHeaderProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, bool>( |
||||
|
"IsRowHeader", |
||||
|
typeof(AutomationProperties), |
||||
|
false); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.IsOffscreenBehavior attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<IsOffscreenBehavior> IsOffscreenBehaviorProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, IsOffscreenBehavior>( |
||||
|
"IsOffscreenBehavior", |
||||
|
typeof(AutomationProperties), |
||||
|
IsOffscreenBehavior.Default); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.ItemStatus attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<string> ItemStatusProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, string>( |
||||
|
"ItemStatus", |
||||
|
typeof(AutomationProperties)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.ItemType attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<string> ItemTypeProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, string>( |
||||
|
"ItemType", |
||||
|
typeof(AutomationProperties)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.LabeledBy attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<IControl> LabeledByProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, IControl>( |
||||
|
"LabeledBy", |
||||
|
typeof(AutomationProperties)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.LiveSetting attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<AutomationLiveSetting> LiveSettingProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, AutomationLiveSetting>( |
||||
|
"LiveSetting", |
||||
|
typeof(AutomationProperties), |
||||
|
AutomationLiveSetting.Off); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.Name attached attached property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<string> NameProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, string>( |
||||
|
"Name", |
||||
|
typeof(AutomationProperties)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.PositionInSet attached property.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// The PositionInSet property describes the ordinal location of the element within a set
|
||||
|
/// of elements which are considered to be siblings. PositionInSet works in coordination
|
||||
|
/// with the SizeOfSet property to describe the ordinal location in the set.
|
||||
|
/// </remarks>
|
||||
|
public static readonly AttachedProperty<int> PositionInSetProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, int>( |
||||
|
"PositionInSet", |
||||
|
typeof(AutomationProperties), |
||||
|
AutomationPositionInSetDefault); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the AutomationProperties.SizeOfSet attached property.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// The SizeOfSet property describes the count of automation elements in a group or set
|
||||
|
/// that are considered to be siblings. SizeOfSet works in coordination with the PositionInSet
|
||||
|
/// property to describe the count of items in the set.
|
||||
|
/// </remarks>
|
||||
|
public static readonly AttachedProperty<int> SizeOfSetProperty = |
||||
|
AvaloniaProperty.RegisterAttached<StyledElement, int>( |
||||
|
"SizeOfSet", |
||||
|
typeof(AutomationProperties), |
||||
|
AutomationSizeOfSetDefault); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting AcceleratorKey property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetAcceleratorKey(StyledElement element, string value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(AcceleratorKeyProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading AcceleratorKey property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static string GetAcceleratorKey(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((string)element.GetValue(AcceleratorKeyProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting AccessKey property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetAccessKey(StyledElement element, string value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(AccessKeyProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading AccessKey property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static string GetAccessKey(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((string)element.GetValue(AccessKeyProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting AutomationId property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetAutomationId(StyledElement element, string value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(AutomationIdProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading AutomationId property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static string GetAutomationId(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return element.GetValue(AutomationIdProperty); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting HelpText property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetHelpText(StyledElement element, string value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(HelpTextProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading HelpText property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static string GetHelpText(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((string)element.GetValue(HelpTextProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting IsColumnHeader property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetIsColumnHeader(StyledElement element, bool value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(IsColumnHeaderProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading IsColumnHeader property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static bool GetIsColumnHeader(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((bool)element.GetValue(IsColumnHeaderProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting IsRequiredForForm property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetIsRequiredForForm(StyledElement element, bool value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(IsRequiredForFormProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading IsRequiredForForm property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static bool GetIsRequiredForForm(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((bool)element.GetValue(IsRequiredForFormProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading IsRowHeader property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static bool GetIsRowHeader(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((bool)element.GetValue(IsRowHeaderProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting IsRowHeader property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetIsRowHeader(StyledElement element, bool value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(IsRowHeaderProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting IsOffscreenBehavior property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetIsOffscreenBehavior(StyledElement element, IsOffscreenBehavior value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(IsOffscreenBehaviorProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading IsOffscreenBehavior property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static IsOffscreenBehavior GetIsOffscreenBehavior(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((IsOffscreenBehavior)element.GetValue(IsOffscreenBehaviorProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting ItemStatus property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetItemStatus(StyledElement element, string value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(ItemStatusProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading ItemStatus property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static string GetItemStatus(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((string)element.GetValue(ItemStatusProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting ItemType property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetItemType(StyledElement element, string value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(ItemTypeProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading ItemType property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static string GetItemType(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((string)element.GetValue(ItemTypeProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting LabeledBy property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetLabeledBy(StyledElement element, IControl value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(LabeledByProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading LabeledBy property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static IControl GetLabeledBy(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return element.GetValue(LabeledByProperty); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting LiveSetting property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetLiveSetting(StyledElement element, AutomationLiveSetting value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(LiveSettingProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading LiveSetting property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static AutomationLiveSetting GetLiveSetting(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((AutomationLiveSetting)element.GetValue(LiveSettingProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting Name property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetName(StyledElement element, string value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(NameProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading Name property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static string GetName(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((string)element.GetValue(NameProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting PositionInSet property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetPositionInSet(StyledElement element, int value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(PositionInSetProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading PositionInSet property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static int GetPositionInSet(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((int)element.GetValue(PositionInSetProperty)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for setting SizeOfSet property on a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static void SetSizeOfSet(StyledElement element, int value) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
element.SetValue(SizeOfSetProperty, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Helper for reading SizeOfSet property from a StyledElement.
|
||||
|
/// </summary>
|
||||
|
public static int GetSizeOfSet(StyledElement element) |
||||
|
{ |
||||
|
if (element == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(element)); |
||||
|
} |
||||
|
|
||||
|
return ((int)element.GetValue(SizeOfSetProperty)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,11 @@ |
|||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Identifies a property of <see cref="AutomationElementIdentifiers"/> or of a specific
|
||||
|
/// control pattern.
|
||||
|
/// </summary>
|
||||
|
public sealed class AutomationProperty |
||||
|
{ |
||||
|
internal AutomationProperty() { } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
public class ElementNotEnabledException : Exception |
||||
|
{ |
||||
|
public ElementNotEnabledException() : base("Element not enabled.") { } |
||||
|
public ElementNotEnabledException(string message) : base(message) { } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Avalonia.Automation.Provider; |
||||
|
|
||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains values used as identifiers by <see cref="IExpandCollapseProvider"/>.
|
||||
|
/// </summary>
|
||||
|
public static class ExpandCollapsePatternIdentifiers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IExpandCollapseProvider.ExpandCollapseState"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty ExpandCollapseStateProperty { get; } = new(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains values that specify the <see cref="ExpandCollapseState"/> of a UI Automation element.
|
||||
|
/// </summary>
|
||||
|
public enum ExpandCollapseState |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// No child nodes, controls, or content of the UI Automation element are displayed.
|
||||
|
/// </summary>
|
||||
|
Collapsed, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// All child nodes, controls or content of the UI Automation element are displayed.
|
||||
|
/// </summary>
|
||||
|
Expanded, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The UI Automation element has no child nodes, controls, or content to display.
|
||||
|
/// </summary>
|
||||
|
LeafNode, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Some, but not all, child nodes, controls, or content of the UI Automation element are
|
||||
|
/// displayed.
|
||||
|
/// </summary>
|
||||
|
PartiallyExpanded |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This enum offers different ways of evaluating the IsOffscreen AutomationProperty
|
||||
|
/// </summary>
|
||||
|
public enum IsOffscreenBehavior |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The AutomationProperty IsOffscreen is calculated based on IsVisible.
|
||||
|
/// </summary>
|
||||
|
Default, |
||||
|
/// <summary>
|
||||
|
/// The AutomationProperty IsOffscreen is false.
|
||||
|
/// </summary>
|
||||
|
Onscreen, |
||||
|
/// <summary>
|
||||
|
/// The AutomationProperty IsOffscreen if true.
|
||||
|
/// </summary>
|
||||
|
Offscreen, |
||||
|
/// <summary>
|
||||
|
/// The AutomationProperty IsOffscreen is calculated based on clip regions.
|
||||
|
/// </summary>
|
||||
|
FromClip, |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,227 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public enum AutomationControlType |
||||
|
{ |
||||
|
Button, |
||||
|
Calendar, |
||||
|
CheckBox, |
||||
|
ComboBox, |
||||
|
Edit, |
||||
|
Hyperlink, |
||||
|
Image, |
||||
|
ListItem, |
||||
|
List, |
||||
|
Menu, |
||||
|
MenuBar, |
||||
|
MenuItem, |
||||
|
ProgressBar, |
||||
|
RadioButton, |
||||
|
ScrollBar, |
||||
|
Slider, |
||||
|
Spinner, |
||||
|
StatusBar, |
||||
|
Tab, |
||||
|
TabItem, |
||||
|
Text, |
||||
|
ToolBar, |
||||
|
ToolTip, |
||||
|
Tree, |
||||
|
TreeItem, |
||||
|
Custom, |
||||
|
Group, |
||||
|
Thumb, |
||||
|
DataGrid, |
||||
|
DataItem, |
||||
|
Document, |
||||
|
SplitButton, |
||||
|
Window, |
||||
|
Pane, |
||||
|
Header, |
||||
|
HeaderItem, |
||||
|
Table, |
||||
|
TitleBar, |
||||
|
Separator, |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides a base class that exposes an element to UI Automation.
|
||||
|
/// </summary>
|
||||
|
public abstract class AutomationPeer |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="AutomationPeer"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="factory">
|
||||
|
/// The factory to use to create the platform automation node.
|
||||
|
/// </param>
|
||||
|
protected AutomationPeer(IAutomationNodeFactory factory) |
||||
|
{ |
||||
|
Node = factory.CreateNode(this); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the related node in the platform UI Automation tree.
|
||||
|
/// </summary>
|
||||
|
public IAutomationNode Node { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Attempts to bring the element associated with the automation peer into view.
|
||||
|
/// </summary>
|
||||
|
public void BringIntoView() => BringIntoViewCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the control type for the element that is associated with the UI Automation peer.
|
||||
|
/// </summary>
|
||||
|
public AutomationControlType GetAutomationControlType() => GetAutomationControlTypeCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the automation ID of the element that is associated with the UI Automation peer.
|
||||
|
/// </summary>
|
||||
|
public string? GetAutomationId() => GetAutomationIdCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the bounding rectangle of the element that is associated with the automation peer
|
||||
|
/// in top-level coordinates.
|
||||
|
/// </summary>
|
||||
|
public Rect GetBoundingRectangle() => GetBoundingRectangleCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the child automation peers.
|
||||
|
/// </summary>
|
||||
|
public IReadOnlyList<AutomationPeer> GetChildren() => GetOrCreateChildrenCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a string that describes the class of the element.
|
||||
|
/// </summary>
|
||||
|
public string GetClassName() => GetClassNameCore() ?? string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a human-readable localized string that represents the type of the control that is
|
||||
|
/// associated with this automation peer.
|
||||
|
/// </summary>
|
||||
|
public string GetLocalizedControlType() => GetLocalizedControlTypeCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets text that describes the element that is associated with this automation peer.
|
||||
|
/// </summary>
|
||||
|
public string GetName() => GetNameCore() ?? string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the <see cref="AutomationPeer"/> that is the parent of this <see cref="AutomationPeer"/>.
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public AutomationPeer? GetParent() => GetParentCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the element that is associated with this automation
|
||||
|
/// peer currently has keyboard focus.
|
||||
|
/// </summary>
|
||||
|
public bool HasKeyboardFocus() => HasKeyboardFocusCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the element that is associated with this automation
|
||||
|
/// peer contains data that is presented to the user.
|
||||
|
/// </summary>
|
||||
|
public bool IsContentElement() => IsControlElement() && IsContentElementCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the element is understood by the user as
|
||||
|
/// interactive or as contributing to the logical structure of the control in the GUI.
|
||||
|
/// </summary>
|
||||
|
public bool IsControlElement() => IsControlElementCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a value indicating whether the control is enabled for user interaction.
|
||||
|
/// </summary>
|
||||
|
public bool IsEnabled() => IsEnabledCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the element can accept keyboard focus.
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public bool IsKeyboardFocusable() => IsKeyboardFocusableCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the keyboard focus on the element that is associated with this automation peer.
|
||||
|
/// </summary>
|
||||
|
public void SetFocus() => SetFocusCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Shows the context menu for the element that is associated with this automation peer.
|
||||
|
/// </summary>
|
||||
|
/// <returns>true if a context menu is present for the element; otherwise false.</returns>
|
||||
|
public bool ShowContextMenu() => ShowContextMenuCore(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Raises an event to notify the automation client of a changed property value.
|
||||
|
/// </summary>
|
||||
|
/// <param name="automationProperty">The property that changed.</param>
|
||||
|
/// <param name="oldValue">The previous value of the property.</param>
|
||||
|
/// <param name="newValue">The new value of the property.</param>
|
||||
|
public void RaisePropertyChangedEvent( |
||||
|
AutomationProperty automationProperty, |
||||
|
object? oldValue, |
||||
|
object? newValue) |
||||
|
{ |
||||
|
Node.PropertyChanged(automationProperty, oldValue, newValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetLocalizedControlTypeCore() |
||||
|
{ |
||||
|
var controlType = GetAutomationControlType(); |
||||
|
|
||||
|
return controlType switch |
||||
|
{ |
||||
|
AutomationControlType.CheckBox => "check box", |
||||
|
AutomationControlType.ComboBox => "combo box", |
||||
|
AutomationControlType.ListItem => "list item", |
||||
|
AutomationControlType.MenuBar => "menu bar", |
||||
|
AutomationControlType.MenuItem => "menu item", |
||||
|
AutomationControlType.ProgressBar => "progress bar", |
||||
|
AutomationControlType.RadioButton => "radio button", |
||||
|
AutomationControlType.ScrollBar => "scroll bar", |
||||
|
AutomationControlType.StatusBar => "status bar", |
||||
|
AutomationControlType.TabItem => "tab item", |
||||
|
AutomationControlType.ToolBar => "toolbar", |
||||
|
AutomationControlType.ToolTip => "tooltip", |
||||
|
AutomationControlType.TreeItem => "tree item", |
||||
|
AutomationControlType.Custom => "custom", |
||||
|
AutomationControlType.DataGrid => "data grid", |
||||
|
AutomationControlType.DataItem => "data item", |
||||
|
AutomationControlType.SplitButton => "split button", |
||||
|
AutomationControlType.HeaderItem => "header item", |
||||
|
AutomationControlType.TitleBar => "title bar", |
||||
|
_ => controlType.ToString().ToLowerInvariant(), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
protected abstract void BringIntoViewCore(); |
||||
|
protected abstract AutomationControlType GetAutomationControlTypeCore(); |
||||
|
protected abstract string? GetAutomationIdCore(); |
||||
|
protected abstract Rect GetBoundingRectangleCore(); |
||||
|
protected abstract IReadOnlyList<AutomationPeer> GetOrCreateChildrenCore(); |
||||
|
protected abstract string GetClassNameCore(); |
||||
|
protected abstract string? GetNameCore(); |
||||
|
protected abstract AutomationPeer? GetParentCore(); |
||||
|
protected abstract bool HasKeyboardFocusCore(); |
||||
|
protected abstract bool IsContentElementCore(); |
||||
|
protected abstract bool IsControlElementCore(); |
||||
|
protected abstract bool IsEnabledCore(); |
||||
|
protected abstract bool IsKeyboardFocusableCore(); |
||||
|
protected abstract void SetFocusCore(); |
||||
|
protected abstract bool ShowContextMenuCore(); |
||||
|
protected internal abstract bool TrySetParent(AutomationPeer? parent); |
||||
|
|
||||
|
protected void EnsureEnabled() |
||||
|
{ |
||||
|
if (!IsEnabled()) |
||||
|
throw new ElementNotEnabledException(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class ButtonAutomationPeer : ContentControlAutomationPeer, |
||||
|
IInvokeProvider |
||||
|
{ |
||||
|
public ButtonAutomationPeer(IAutomationNodeFactory factory, Button owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public void Invoke() |
||||
|
{ |
||||
|
EnsureEnabled(); |
||||
|
(Owner as Button)?.PerformClick(); |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Button; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,20 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class CheckBoxAutomationPeer : ToggleButtonAutomationPeer |
||||
|
{ |
||||
|
public CheckBoxAutomationPeer(IAutomationNodeFactory factory, CheckBox owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.CheckBox; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,123 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class ComboBoxAutomationPeer : SelectingItemsControlAutomationPeer, |
||||
|
IExpandCollapseProvider |
||||
|
{ |
||||
|
private UnrealizedSelectionPeer[]? _selection; |
||||
|
|
||||
|
public ComboBoxAutomationPeer(IAutomationNodeFactory factory, ComboBox owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public new ComboBox Owner => (ComboBox)base.Owner; |
||||
|
|
||||
|
public ExpandCollapseState ExpandCollapseState => ToState(Owner.IsDropDownOpen); |
||||
|
public void Collapse() => Owner.IsDropDownOpen = false; |
||||
|
public void Expand() => Owner.IsDropDownOpen = true; |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.ComboBox; |
||||
|
} |
||||
|
|
||||
|
protected override IReadOnlyList<AutomationPeer>? GetSelectionCore() |
||||
|
{ |
||||
|
if (ExpandCollapseState == ExpandCollapseState.Expanded) |
||||
|
return base.GetSelectionCore(); |
||||
|
|
||||
|
// If the combo box is not open then we won't have an ItemsPresenter so the default
|
||||
|
// GetSelectionCore implementation won't work. For this case we create a separate
|
||||
|
// peer to represent the unrealized item.
|
||||
|
if (Owner.SelectedItem is object selection) |
||||
|
{ |
||||
|
_selection ??= new[] { new UnrealizedSelectionPeer(Node.Factory, this) }; |
||||
|
_selection[0].Item = selection; |
||||
|
return _selection; |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
protected override void OwnerPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
base.OwnerPropertyChanged(sender, e); |
||||
|
|
||||
|
if (e.Property == ComboBox.IsDropDownOpenProperty) |
||||
|
{ |
||||
|
RaisePropertyChangedEvent( |
||||
|
ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty, |
||||
|
ToState((bool)e.OldValue!), |
||||
|
ToState((bool)e.NewValue!)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private ExpandCollapseState ToState(bool value) |
||||
|
{ |
||||
|
return value ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed; |
||||
|
} |
||||
|
|
||||
|
private class UnrealizedSelectionPeer : UnrealizedElementAutomationPeer |
||||
|
{ |
||||
|
private readonly ComboBoxAutomationPeer _owner; |
||||
|
private object? _item; |
||||
|
|
||||
|
public UnrealizedSelectionPeer(IAutomationNodeFactory factory, ComboBoxAutomationPeer owner) |
||||
|
: base(factory) |
||||
|
{ |
||||
|
_owner = owner; |
||||
|
} |
||||
|
|
||||
|
public object? Item |
||||
|
{ |
||||
|
get => _item; |
||||
|
set |
||||
|
{ |
||||
|
if (_item != value) |
||||
|
{ |
||||
|
var oldValue = GetNameCore(); |
||||
|
_item = value; |
||||
|
RaisePropertyChangedEvent( |
||||
|
AutomationElementIdentifiers.NameProperty, |
||||
|
oldValue, |
||||
|
GetNameCore()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override string? GetAutomationIdCore() => null; |
||||
|
protected override string GetClassNameCore() => typeof(ComboBoxItem).Name; |
||||
|
protected override AutomationPeer? GetParentCore() => _owner; |
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() => AutomationControlType.ListItem; |
||||
|
|
||||
|
protected override string? GetNameCore() |
||||
|
{ |
||||
|
if (_item is Control c) |
||||
|
{ |
||||
|
var result = AutomationProperties.GetName(c); |
||||
|
|
||||
|
if (result is null && c is ContentControl cc && cc.Presenter?.Child is TextBlock text) |
||||
|
{ |
||||
|
result = text.Text; |
||||
|
} |
||||
|
|
||||
|
if (result is null) |
||||
|
{ |
||||
|
result = c.GetValue(ContentControl.ContentProperty)?.ToString(); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
return _item?.ToString(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class ContentControlAutomationPeer : ControlAutomationPeer |
||||
|
{ |
||||
|
protected ContentControlAutomationPeer(IAutomationNodeFactory factory, ContentControl owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public new ContentControl Owner => (ContentControl)base.Owner; |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() => AutomationControlType.Pane; |
||||
|
|
||||
|
protected override string? GetNameCore() |
||||
|
{ |
||||
|
var result = base.GetNameCore(); |
||||
|
|
||||
|
if (result is null && Owner.Presenter?.Child is TextBlock text) |
||||
|
{ |
||||
|
result = text.Text; |
||||
|
} |
||||
|
|
||||
|
if (result is null) |
||||
|
{ |
||||
|
result = Owner.Content?.ToString(); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
protected override bool IsContentElementCore() => false; |
||||
|
protected override bool IsControlElementCore() => false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,196 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.VisualTree; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// An automation peer which represents a <see cref="Control"/> element.
|
||||
|
/// </summary>
|
||||
|
public class ControlAutomationPeer : AutomationPeer |
||||
|
{ |
||||
|
private IReadOnlyList<AutomationPeer>? _children; |
||||
|
private bool _childrenValid; |
||||
|
private AutomationPeer? _parent; |
||||
|
private bool _parentValid; |
||||
|
|
||||
|
public ControlAutomationPeer(IAutomationNodeFactory factory, Control owner) |
||||
|
: base(factory) |
||||
|
{ |
||||
|
Owner = owner ?? throw new ArgumentNullException("owner"); |
||||
|
|
||||
|
owner.PropertyChanged += OwnerPropertyChanged; |
||||
|
var visualChildren = ((IVisual)owner).VisualChildren; |
||||
|
visualChildren.CollectionChanged += VisualChildrenChanged; |
||||
|
} |
||||
|
|
||||
|
public Control Owner { get; } |
||||
|
|
||||
|
public static AutomationPeer GetOrCreatePeer(IAutomationNodeFactory factory, Control element) |
||||
|
{ |
||||
|
element = element ?? throw new ArgumentNullException("element"); |
||||
|
return element.GetOrCreateAutomationPeer(factory); |
||||
|
} |
||||
|
|
||||
|
public AutomationPeer GetOrCreatePeer(Control element) |
||||
|
{ |
||||
|
return element == Owner ? this : GetOrCreatePeer(Node.Factory, element); |
||||
|
} |
||||
|
|
||||
|
protected override void BringIntoViewCore() => Owner.BringIntoView(); |
||||
|
protected override string? GetAutomationIdCore() => AutomationProperties.GetAutomationId(Owner); |
||||
|
protected override Rect GetBoundingRectangleCore() => GetBounds(Owner.TransformedBounds); |
||||
|
|
||||
|
protected virtual IReadOnlyList<AutomationPeer>? GetChildrenCore() |
||||
|
{ |
||||
|
var children = ((IVisual)Owner).VisualChildren; |
||||
|
|
||||
|
if (children.Count == 0) |
||||
|
return null; |
||||
|
|
||||
|
var result = new List<AutomationPeer>(); |
||||
|
|
||||
|
foreach (var child in children) |
||||
|
{ |
||||
|
if (child is Control c && c.IsVisible) |
||||
|
{ |
||||
|
result.Add(GetOrCreatePeer(c)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
protected override AutomationPeer? GetParentCore() |
||||
|
{ |
||||
|
EnsureConnected(); |
||||
|
return _parent; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Invalidates the peer's children and causes a re-read from <see cref="GetChildrenCore"/>.
|
||||
|
/// </summary>
|
||||
|
protected void InvalidateChildren() |
||||
|
{ |
||||
|
_childrenValid = false; |
||||
|
Node!.ChildrenChanged(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Invalidates the peer's parent.
|
||||
|
/// </summary>
|
||||
|
protected void InvalidateParent() |
||||
|
{ |
||||
|
_parent = null; |
||||
|
_parentValid = false; |
||||
|
} |
||||
|
|
||||
|
protected override IReadOnlyList<AutomationPeer> GetOrCreateChildrenCore() |
||||
|
{ |
||||
|
var children = _children ?? Array.Empty<AutomationPeer>(); |
||||
|
|
||||
|
if (_childrenValid) |
||||
|
return children; |
||||
|
|
||||
|
var newChildren = GetChildrenCore() ?? Array.Empty<AutomationPeer>(); |
||||
|
|
||||
|
foreach (var peer in children.Except(newChildren)) |
||||
|
peer.TrySetParent(null); |
||||
|
foreach (var peer in newChildren) |
||||
|
peer.TrySetParent(this); |
||||
|
|
||||
|
_childrenValid = true; |
||||
|
return _children = newChildren; |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() => AutomationControlType.Custom; |
||||
|
protected override string GetClassNameCore() => Owner.GetType().Name; |
||||
|
protected override string? GetNameCore() => AutomationProperties.GetName(Owner); |
||||
|
protected override bool HasKeyboardFocusCore() => Owner.IsFocused; |
||||
|
protected override bool IsContentElementCore() => true; |
||||
|
protected override bool IsControlElementCore() => true; |
||||
|
protected override bool IsEnabledCore() => Owner.IsEnabled; |
||||
|
protected override bool IsKeyboardFocusableCore() => Owner.Focusable; |
||||
|
protected override void SetFocusCore() => Owner.Focus(); |
||||
|
|
||||
|
protected override bool ShowContextMenuCore() |
||||
|
{ |
||||
|
var c = Owner; |
||||
|
|
||||
|
while (c is object) |
||||
|
{ |
||||
|
if (c.ContextMenu is object) |
||||
|
{ |
||||
|
c.ContextMenu.Open(c); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
c = c.Parent as Control; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
protected internal override bool TrySetParent(AutomationPeer? parent) |
||||
|
{ |
||||
|
_parent = parent; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private Rect GetBounds(TransformedBounds? bounds) |
||||
|
{ |
||||
|
return bounds?.Bounds.TransformToAABB(bounds!.Value.Transform) ?? default; |
||||
|
} |
||||
|
|
||||
|
private void VisualChildrenChanged(object sender, EventArgs e) => InvalidateChildren(); |
||||
|
|
||||
|
private void OwnerPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.Property == Visual.IsVisibleProperty) |
||||
|
{ |
||||
|
var parent = Owner.GetVisualParent(); |
||||
|
if (parent is Control c) |
||||
|
(GetOrCreatePeer(c) as ControlAutomationPeer)?.InvalidateChildren(); |
||||
|
} |
||||
|
else if (e.Property == Visual.TransformedBoundsProperty) |
||||
|
{ |
||||
|
RaisePropertyChangedEvent( |
||||
|
AutomationElementIdentifiers.BoundingRectangleProperty, |
||||
|
GetBounds((TransformedBounds?)e.OldValue), |
||||
|
GetBounds((TransformedBounds?)e.NewValue)); |
||||
|
} |
||||
|
else if (e.Property == Visual.VisualParentProperty) |
||||
|
{ |
||||
|
InvalidateParent(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private void EnsureConnected() |
||||
|
{ |
||||
|
if (!_parentValid) |
||||
|
{ |
||||
|
var parent = Owner.GetVisualParent(); |
||||
|
|
||||
|
while (parent is object) |
||||
|
{ |
||||
|
if (parent is Control c) |
||||
|
{ |
||||
|
var parentPeer = GetOrCreatePeer(c); |
||||
|
parentPeer.GetChildren(); |
||||
|
} |
||||
|
|
||||
|
parent = parent.GetVisualParent(); |
||||
|
} |
||||
|
|
||||
|
_parentValid = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,20 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class ImageAutomationPeer : ControlAutomationPeer |
||||
|
{ |
||||
|
public ImageAutomationPeer(IAutomationNodeFactory factory, Control owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Image; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class ItemsControlAutomationPeer : ControlAutomationPeer, IScrollProvider |
||||
|
{ |
||||
|
private bool _searchedForScrollable; |
||||
|
private IScrollProvider? _scroller; |
||||
|
|
||||
|
public ItemsControlAutomationPeer(IAutomationNodeFactory factory, ItemsControl owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public new ItemsControl Owner => (ItemsControl)base.Owner; |
||||
|
public bool HorizontallyScrollable => _scroller?.HorizontallyScrollable ?? false; |
||||
|
public double HorizontalScrollPercent => _scroller?.HorizontalScrollPercent ?? -1; |
||||
|
public double HorizontalViewSize => _scroller?.HorizontalViewSize ?? 0; |
||||
|
public bool VerticallyScrollable => _scroller?.VerticallyScrollable ?? false; |
||||
|
public double VerticalScrollPercent => _scroller?.VerticalScrollPercent ?? -1; |
||||
|
public double VerticalViewSize => _scroller?.VerticalViewSize ?? 0; |
||||
|
|
||||
|
protected virtual IScrollProvider? Scroller |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (!_searchedForScrollable) |
||||
|
{ |
||||
|
if (Owner.GetValue(ListBox.ScrollProperty) is Control scrollable) |
||||
|
_scroller = GetOrCreatePeer(scrollable) as IScrollProvider; |
||||
|
_searchedForScrollable = true; |
||||
|
} |
||||
|
|
||||
|
return _scroller; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.List; |
||||
|
} |
||||
|
|
||||
|
public void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount) |
||||
|
{ |
||||
|
_scroller?.Scroll(horizontalAmount, verticalAmount); |
||||
|
} |
||||
|
|
||||
|
public void SetScrollPercent(double horizontalPercent, double verticalPercent) |
||||
|
{ |
||||
|
_scroller?.SetScrollPercent(horizontalPercent, verticalPercent); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
using Avalonia.Controls.Selection; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class ListItemAutomationPeer : ContentControlAutomationPeer, |
||||
|
ISelectionItemProvider |
||||
|
{ |
||||
|
public ListItemAutomationPeer(IAutomationNodeFactory factory, ContentControl owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public bool IsSelected => Owner.GetValue(ListBoxItem.IsSelectedProperty); |
||||
|
|
||||
|
public ISelectionProvider? SelectionContainer |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (Owner.Parent is Control parent) |
||||
|
{ |
||||
|
var parentPeer = GetOrCreatePeer(parent); |
||||
|
return parentPeer as ISelectionProvider; |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void Select() |
||||
|
{ |
||||
|
EnsureEnabled(); |
||||
|
|
||||
|
if (Owner.Parent is SelectingItemsControl parent) |
||||
|
{ |
||||
|
var index = parent.ItemContainerGenerator.IndexFromContainer(Owner); |
||||
|
|
||||
|
if (index != -1) |
||||
|
parent.SelectedIndex = index; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void ISelectionItemProvider.AddToSelection() |
||||
|
{ |
||||
|
EnsureEnabled(); |
||||
|
|
||||
|
if (Owner.Parent is ItemsControl parent && |
||||
|
parent.GetValue(ListBox.SelectionProperty) is ISelectionModel selectionModel) |
||||
|
{ |
||||
|
var index = parent.ItemContainerGenerator.IndexFromContainer(Owner); |
||||
|
|
||||
|
if (index != -1) |
||||
|
selectionModel.Select(index); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void ISelectionItemProvider.RemoveFromSelection() |
||||
|
{ |
||||
|
EnsureEnabled(); |
||||
|
|
||||
|
if (Owner.Parent is ItemsControl parent && |
||||
|
parent.GetValue(ListBox.SelectionProperty) is ISelectionModel selectionModel) |
||||
|
{ |
||||
|
var index = parent.ItemContainerGenerator.IndexFromContainer(Owner); |
||||
|
|
||||
|
if (index != -1) |
||||
|
selectionModel.Deselect(index); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.ListItem; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class MenuAutomationPeer : ControlAutomationPeer |
||||
|
{ |
||||
|
public MenuAutomationPeer(IAutomationNodeFactory factory, Menu owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Menu; |
||||
|
} |
||||
|
|
||||
|
protected override bool IsContentElementCore() => false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class MenuItemAutomationPeer : ControlAutomationPeer |
||||
|
{ |
||||
|
public MenuItemAutomationPeer(IAutomationNodeFactory factory, MenuItem owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public new MenuItem Owner => (MenuItem)base.Owner; |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.MenuItem; |
||||
|
} |
||||
|
|
||||
|
protected override string? GetNameCore() |
||||
|
{ |
||||
|
var result = base.GetNameCore(); |
||||
|
|
||||
|
if (result is null && Owner.HeaderPresenter.Child is TextBlock text) |
||||
|
{ |
||||
|
result = text.Text; |
||||
|
} |
||||
|
|
||||
|
if (result is null) |
||||
|
{ |
||||
|
result = Owner.Header?.ToString(); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// An automation peer which represents an element that is exposed to automation as non-
|
||||
|
/// interactive or as not contributing to the logical structure of the application.
|
||||
|
/// </summary>
|
||||
|
public class NoneAutomationPeer : ControlAutomationPeer |
||||
|
{ |
||||
|
public NoneAutomationPeer(IAutomationNodeFactory factory, Control owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Pane; |
||||
|
} |
||||
|
|
||||
|
protected override bool IsContentElementCore() => false; |
||||
|
protected override bool IsControlElementCore() => false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,36 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class PopupRootAutomationPeer : WindowBaseAutomationPeer |
||||
|
{ |
||||
|
public PopupRootAutomationPeer(IAutomationNodeFactory factory, PopupRoot owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
if (owner.IsVisible) |
||||
|
StartTrackingFocus(); |
||||
|
else |
||||
|
owner.Opened += OnOpened; |
||||
|
owner.Closed += OnClosed; |
||||
|
} |
||||
|
|
||||
|
protected override bool IsContentElementCore() => false; |
||||
|
protected override bool IsControlElementCore() => false; |
||||
|
|
||||
|
private void OnOpened(object sender, EventArgs e) |
||||
|
{ |
||||
|
((PopupRoot)Owner).Opened -= OnOpened; |
||||
|
StartTrackingFocus(); |
||||
|
} |
||||
|
|
||||
|
private void OnClosed(object sender, EventArgs e) |
||||
|
{ |
||||
|
((PopupRoot)Owner).Closed -= OnClosed; |
||||
|
StopTrackingFocus(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public abstract class RangeBaseAutomationPeer : ControlAutomationPeer, IRangeValueProvider |
||||
|
{ |
||||
|
public RangeBaseAutomationPeer(IAutomationNodeFactory factory, RangeBase owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
owner.PropertyChanged += OwnerPropertyChanged; |
||||
|
} |
||||
|
|
||||
|
public new RangeBase Owner => (RangeBase)base.Owner; |
||||
|
public virtual bool IsReadOnly => false; |
||||
|
public double Maximum => Owner.Maximum; |
||||
|
public double Minimum => Owner.Minimum; |
||||
|
public double Value => Owner.Value; |
||||
|
public void SetValue(double value) => Owner.Value = value; |
||||
|
|
||||
|
protected virtual void OwnerPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.Property == RangeBase.MinimumProperty) |
||||
|
RaisePropertyChangedEvent(RangeValuePatternIdentifiers.MinimumProperty, e.OldValue, e.NewValue); |
||||
|
else if (e.Property == RangeBase.MaximumProperty) |
||||
|
RaisePropertyChangedEvent(RangeValuePatternIdentifiers.MaximumProperty, e.OldValue, e.NewValue); |
||||
|
else if (e.Property == RangeBase.ValueProperty) |
||||
|
RaisePropertyChangedEvent(RangeValuePatternIdentifiers.ValueProperty, e.OldValue, e.NewValue); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,175 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class ScrollViewerAutomationPeer : ControlAutomationPeer, IScrollProvider |
||||
|
{ |
||||
|
public ScrollViewerAutomationPeer(IAutomationNodeFactory factory, ScrollViewer owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public new ScrollViewer Owner => (ScrollViewer)base.Owner; |
||||
|
|
||||
|
public bool HorizontallyScrollable |
||||
|
{ |
||||
|
get => MathUtilities.GreaterThan(Owner.Extent.Width, Owner.Viewport.Width); |
||||
|
} |
||||
|
|
||||
|
public double HorizontalScrollPercent |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (!HorizontallyScrollable) |
||||
|
return ScrollPatternIdentifiers.NoScroll; |
||||
|
return (double)(Owner.Offset.X * 100.0 / (Owner.Extent.Width - Owner.Viewport.Width)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public double HorizontalViewSize |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (MathUtilities.IsZero(Owner.Extent.Width)) |
||||
|
return 100; |
||||
|
return Math.Min(100, Owner.Viewport.Width * 100.0 / Owner.Extent.Width); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public bool VerticallyScrollable |
||||
|
{ |
||||
|
get => MathUtilities.GreaterThan(Owner.Extent.Height, Owner.Viewport.Height); |
||||
|
} |
||||
|
|
||||
|
public double VerticalScrollPercent |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (!VerticallyScrollable) |
||||
|
return ScrollPatternIdentifiers.NoScroll; |
||||
|
return (double)(Owner.Offset.Y * 100.0 / (Owner.Extent.Height - Owner.Viewport.Height)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public double VerticalViewSize |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (MathUtilities.IsZero(Owner.Extent.Height)) |
||||
|
return 100; |
||||
|
return Math.Min(100, Owner.Viewport.Height * 100.0 / Owner.Extent.Height); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Pane; |
||||
|
} |
||||
|
|
||||
|
protected override bool IsContentElementCore() => false; |
||||
|
|
||||
|
protected override bool IsControlElementCore() |
||||
|
{ |
||||
|
// Return false if the control is part of a control template.
|
||||
|
return Owner.TemplatedParent is null && base.IsControlElementCore(); |
||||
|
} |
||||
|
|
||||
|
public void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount) |
||||
|
{ |
||||
|
if (!IsEnabled()) |
||||
|
throw new ElementNotEnabledException(); |
||||
|
|
||||
|
var scrollHorizontally = horizontalAmount != ScrollAmount.NoAmount; |
||||
|
var scrollVertically = verticalAmount != ScrollAmount.NoAmount; |
||||
|
|
||||
|
if (scrollHorizontally && !HorizontallyScrollable || scrollVertically && !VerticallyScrollable) |
||||
|
{ |
||||
|
throw new InvalidOperationException("Operation cannot be performed"); |
||||
|
} |
||||
|
|
||||
|
switch (horizontalAmount) |
||||
|
{ |
||||
|
case ScrollAmount.LargeDecrement: |
||||
|
Owner.PageLeft(); |
||||
|
break; |
||||
|
case ScrollAmount.SmallDecrement: |
||||
|
Owner.LineLeft(); |
||||
|
break; |
||||
|
case ScrollAmount.SmallIncrement: |
||||
|
Owner.LineRight(); |
||||
|
break; |
||||
|
case ScrollAmount.LargeIncrement: |
||||
|
Owner.PageRight(); |
||||
|
break; |
||||
|
case ScrollAmount.NoAmount: |
||||
|
break; |
||||
|
default: |
||||
|
throw new InvalidOperationException("Operation cannot be performed"); |
||||
|
} |
||||
|
|
||||
|
switch (verticalAmount) |
||||
|
{ |
||||
|
case ScrollAmount.LargeDecrement: |
||||
|
Owner.PageUp(); |
||||
|
break; |
||||
|
case ScrollAmount.SmallDecrement: |
||||
|
Owner.LineUp(); |
||||
|
break; |
||||
|
case ScrollAmount.SmallIncrement: |
||||
|
Owner.LineDown(); |
||||
|
break; |
||||
|
case ScrollAmount.LargeIncrement: |
||||
|
Owner.PageDown(); |
||||
|
break; |
||||
|
case ScrollAmount.NoAmount: |
||||
|
break; |
||||
|
default: |
||||
|
throw new InvalidOperationException("Operation cannot be performed"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void SetScrollPercent(double horizontalPercent, double verticalPercent) |
||||
|
{ |
||||
|
if (!IsEnabled()) |
||||
|
throw new ElementNotEnabledException(); |
||||
|
|
||||
|
var scrollHorizontally = horizontalPercent != ScrollPatternIdentifiers.NoScroll; |
||||
|
var scrollVertically = verticalPercent != ScrollPatternIdentifiers.NoScroll; |
||||
|
|
||||
|
if (scrollHorizontally && !HorizontallyScrollable || scrollVertically && !VerticallyScrollable) |
||||
|
{ |
||||
|
throw new InvalidOperationException("Operation cannot be performed"); |
||||
|
} |
||||
|
|
||||
|
if (scrollHorizontally && (horizontalPercent < 0.0) || (horizontalPercent > 100.0)) |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException("horizontalPercent"); |
||||
|
} |
||||
|
|
||||
|
if (scrollVertically && (verticalPercent < 0.0) || (verticalPercent > 100.0)) |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException("verticalPercent"); |
||||
|
} |
||||
|
|
||||
|
var offset = Owner.Offset; |
||||
|
|
||||
|
if (scrollHorizontally) |
||||
|
{ |
||||
|
offset = offset.WithX((Owner.Extent.Width - Owner.Viewport.Width) * horizontalPercent * 0.01); |
||||
|
} |
||||
|
|
||||
|
if (scrollVertically) |
||||
|
{ |
||||
|
offset = offset.WithY((Owner.Extent.Height - Owner.Viewport.Height) * verticalPercent * 0.01); |
||||
|
} |
||||
|
|
||||
|
Owner.Offset = offset; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,87 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
using Avalonia.Controls.Selection; |
||||
|
using Avalonia.VisualTree; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public abstract class SelectingItemsControlAutomationPeer : ItemsControlAutomationPeer, |
||||
|
ISelectionProvider |
||||
|
{ |
||||
|
private ISelectionModel _selection; |
||||
|
|
||||
|
protected SelectingItemsControlAutomationPeer(IAutomationNodeFactory factory, SelectingItemsControl owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
_selection = owner.GetValue(ListBox.SelectionProperty); |
||||
|
_selection.SelectionChanged += OwnerSelectionChanged; |
||||
|
owner.PropertyChanged += OwnerPropertyChanged; |
||||
|
} |
||||
|
|
||||
|
public bool CanSelectMultiple => GetSelectionModeCore().HasFlagCustom(SelectionMode.Multiple); |
||||
|
public bool IsSelectionRequired => GetSelectionModeCore().HasFlagCustom(SelectionMode.AlwaysSelected); |
||||
|
public IReadOnlyList<AutomationPeer> GetSelection() => GetSelectionCore() ?? Array.Empty<AutomationPeer>(); |
||||
|
|
||||
|
protected virtual IReadOnlyList<AutomationPeer>? GetSelectionCore() |
||||
|
{ |
||||
|
List<AutomationPeer>? result = null; |
||||
|
|
||||
|
if (Owner is SelectingItemsControl owner) |
||||
|
{ |
||||
|
var selection = Owner.GetValue(ListBox.SelectionProperty); |
||||
|
|
||||
|
foreach (var i in selection.SelectedIndexes) |
||||
|
{ |
||||
|
var container = owner.ItemContainerGenerator.ContainerFromIndex(i); |
||||
|
|
||||
|
if (container is Control c && ((IVisual)c).IsAttachedToVisualTree) |
||||
|
{ |
||||
|
var peer = GetOrCreatePeer(c); |
||||
|
|
||||
|
if (peer is object) |
||||
|
{ |
||||
|
result ??= new List<AutomationPeer>(); |
||||
|
result.Add(peer); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
protected virtual SelectionMode GetSelectionModeCore() |
||||
|
{ |
||||
|
return (Owner as SelectingItemsControl)?.GetValue(ListBox.SelectionModeProperty) ?? SelectionMode.Single; |
||||
|
} |
||||
|
|
||||
|
protected virtual void OwnerPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.Property == ListBox.SelectionProperty) |
||||
|
{ |
||||
|
_selection.SelectionChanged -= OwnerSelectionChanged; |
||||
|
_selection = Owner.GetValue(ListBox.SelectionProperty); |
||||
|
_selection.SelectionChanged += OwnerSelectionChanged; |
||||
|
RaiseSelectionChanged(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual void OwnerSelectionChanged(object sender, SelectionModelSelectionChangedEventArgs e) |
||||
|
{ |
||||
|
RaiseSelectionChanged(); |
||||
|
} |
||||
|
|
||||
|
private void RaiseSelectionChanged() |
||||
|
{ |
||||
|
RaisePropertyChangedEvent(SelectionPatternIdentifiers.SelectionProperty, null, null); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class SliderAutomationPeer : RangeBaseAutomationPeer |
||||
|
{ |
||||
|
public SliderAutomationPeer(IAutomationNodeFactory factory, Slider owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Slider; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class TabControlAutomationPeer : SelectingItemsControlAutomationPeer |
||||
|
{ |
||||
|
public TabControlAutomationPeer(IAutomationNodeFactory factory, TabControl owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Tab; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class TabItemAutomationPeer : ListItemAutomationPeer |
||||
|
{ |
||||
|
public TabItemAutomationPeer(IAutomationNodeFactory factory, TabItem owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.TabItem; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class TextAutomationPeer : ControlAutomationPeer |
||||
|
{ |
||||
|
public TextAutomationPeer(IAutomationNodeFactory factory, Control owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Text; |
||||
|
} |
||||
|
|
||||
|
protected override string? GetNameCore() => Owner.GetValue(TextBlock.TextProperty); |
||||
|
|
||||
|
protected override bool IsControlElementCore() |
||||
|
{ |
||||
|
// Return false if the control is part of a control template.
|
||||
|
return Owner.TemplatedParent is null && base.IsControlElementCore(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class TextBoxAutomationPeer : TextAutomationPeer, IValueProvider |
||||
|
{ |
||||
|
public TextBoxAutomationPeer(IAutomationNodeFactory factory, TextBox owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public new TextBox Owner => (TextBox)base.Owner; |
||||
|
public bool IsReadOnly => Owner.IsReadOnly; |
||||
|
public string? Value => Owner.Text; |
||||
|
public void SetValue(string? value) => Owner.Text = value; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class ToggleButtonAutomationPeer : ContentControlAutomationPeer, IToggleProvider |
||||
|
{ |
||||
|
public ToggleButtonAutomationPeer(IAutomationNodeFactory factory, ToggleButton owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public new ToggleButton Owner => (ToggleButton)base.Owner; |
||||
|
|
||||
|
ToggleState IToggleProvider.ToggleState |
||||
|
{ |
||||
|
get => Owner.IsChecked switch |
||||
|
{ |
||||
|
true => ToggleState.On, |
||||
|
false => ToggleState.Off, |
||||
|
null => ToggleState.Indeterminate, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
void IToggleProvider.Toggle() |
||||
|
{ |
||||
|
EnsureEnabled(); |
||||
|
Owner.PerformClick(); |
||||
|
} |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Button; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// An automation peer which represents an unrealized element
|
||||
|
/// </summary>
|
||||
|
public abstract class UnrealizedElementAutomationPeer : AutomationPeer |
||||
|
{ |
||||
|
protected UnrealizedElementAutomationPeer(IAutomationNodeFactory factory) |
||||
|
: base(factory) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public void SetParent(AutomationPeer? parent) => TrySetParent(parent); |
||||
|
protected override void BringIntoViewCore() => GetParent()?.BringIntoView(); |
||||
|
protected override Rect GetBoundingRectangleCore() => GetParent()?.GetBoundingRectangle() ?? default; |
||||
|
protected override IReadOnlyList<AutomationPeer> GetOrCreateChildrenCore() => Array.Empty<AutomationPeer>(); |
||||
|
protected override bool HasKeyboardFocusCore() => false; |
||||
|
protected override bool IsContentElementCore() => false; |
||||
|
protected override bool IsControlElementCore() => false; |
||||
|
protected override bool IsEnabledCore() => true; |
||||
|
protected override bool IsKeyboardFocusableCore() => false; |
||||
|
protected override void SetFocusCore() { } |
||||
|
protected override bool ShowContextMenuCore() => false; |
||||
|
protected internal override bool TrySetParent(AutomationPeer? parent) => false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class WindowAutomationPeer : WindowBaseAutomationPeer |
||||
|
{ |
||||
|
public WindowAutomationPeer(IAutomationNodeFactory factory, Window owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
if (owner.IsVisible) |
||||
|
StartTrackingFocus(); |
||||
|
else |
||||
|
owner.Opened += OnOpened; |
||||
|
owner.Closed += OnClosed; |
||||
|
} |
||||
|
|
||||
|
public new Window Owner => (Window)base.Owner; |
||||
|
|
||||
|
protected override string GetNameCore() => Owner.Title; |
||||
|
|
||||
|
private void OnOpened(object sender, EventArgs e) |
||||
|
{ |
||||
|
Owner.Opened -= OnOpened; |
||||
|
StartTrackingFocus(); |
||||
|
} |
||||
|
|
||||
|
private void OnClosed(object sender, EventArgs e) |
||||
|
{ |
||||
|
Owner.Closed -= OnClosed; |
||||
|
StopTrackingFocus(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
@ -0,0 +1,72 @@ |
|||||
|
using System.ComponentModel; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.VisualTree; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Peers |
||||
|
{ |
||||
|
public class WindowBaseAutomationPeer : ControlAutomationPeer, IRootProvider |
||||
|
{ |
||||
|
private Control? _focus; |
||||
|
|
||||
|
public WindowBaseAutomationPeer(IAutomationNodeFactory factory, WindowBase owner) |
||||
|
: base(factory, owner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public new WindowBase Owner => (WindowBase)base.Owner; |
||||
|
public ITopLevelImpl PlatformImpl => Owner.PlatformImpl; |
||||
|
|
||||
|
protected override AutomationControlType GetAutomationControlTypeCore() |
||||
|
{ |
||||
|
return AutomationControlType.Window; |
||||
|
} |
||||
|
|
||||
|
public AutomationPeer? GetFocus() => _focus is object ? GetOrCreatePeer(_focus) : null; |
||||
|
|
||||
|
public AutomationPeer? GetPeerFromPoint(Point p) |
||||
|
{ |
||||
|
var hit = Owner.GetVisualAt(p)?.FindAncestorOfType<Control>(includeSelf: true); |
||||
|
return hit is object ? GetOrCreatePeer(hit) : null; |
||||
|
} |
||||
|
|
||||
|
protected void StartTrackingFocus() |
||||
|
{ |
||||
|
KeyboardDevice.Instance.PropertyChanged += KeyboardDevicePropertyChanged; |
||||
|
OnFocusChanged(KeyboardDevice.Instance.FocusedElement); |
||||
|
} |
||||
|
|
||||
|
protected void StopTrackingFocus() |
||||
|
{ |
||||
|
KeyboardDevice.Instance.PropertyChanged -= KeyboardDevicePropertyChanged; |
||||
|
} |
||||
|
|
||||
|
private void OnFocusChanged(IInputElement? focus) |
||||
|
{ |
||||
|
var oldFocus = _focus; |
||||
|
|
||||
|
_focus = focus?.VisualRoot == Owner ? focus as Control : null; |
||||
|
|
||||
|
if (_focus != oldFocus) |
||||
|
{ |
||||
|
var peer = _focus is object ? GetOrCreatePeer(_focus) : null; |
||||
|
((IRootAutomationNode)Node).FocusChanged(peer); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void KeyboardDevicePropertyChanged(object sender, PropertyChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.PropertyName == nameof(KeyboardDevice.FocusedElement)) |
||||
|
{ |
||||
|
OnFocusChanged(KeyboardDevice.Instance.FocusedElement); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
@ -0,0 +1,32 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Automation.Peers; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Platform |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a platform implementation of a node in the UI Automation tree.
|
||||
|
/// </summary>
|
||||
|
public interface IAutomationNode |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets a factory which can be used to create child nodes.
|
||||
|
/// </summary>
|
||||
|
IAutomationNodeFactory Factory { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Called by the <see cref="AutomationPeer"/> when the children of the peer change.
|
||||
|
/// </summary>
|
||||
|
void ChildrenChanged(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Called by the <see cref="AutomationPeer"/> when a property other than the parent,
|
||||
|
/// children or root changes.
|
||||
|
/// </summary>
|
||||
|
/// <param name="property">The property that changed.</param>
|
||||
|
/// <param name="oldValue">The previous value of the property.</param>
|
||||
|
/// <param name="newValue">The new value of the property.</param>
|
||||
|
void PropertyChanged(AutomationProperty property, object? oldValue, object? newValue); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using Avalonia.Automation.Peers; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Platform |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Creates nodes in the UI Automation tree of the underlying platform.
|
||||
|
/// </summary>
|
||||
|
public interface IAutomationNodeFactory |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Creates an automation node for a peer.
|
||||
|
/// </summary>
|
||||
|
/// <param name="peer">The peer.</param>
|
||||
|
IAutomationNode CreateNode(AutomationPeer peer); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Avalonia.Automation.Peers; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Platform |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a platform implementation of a root node in the UI Automation tree.
|
||||
|
/// </summary>
|
||||
|
public interface IRootAutomationNode : IAutomationNode |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Called by the <see cref="IRootProvider"/> when its focus changes.
|
||||
|
/// </summary>
|
||||
|
/// <param name="focus">
|
||||
|
/// The automation peer for the newly focused control or null if no control is focused.
|
||||
|
/// </param>
|
||||
|
void FocusChanged(AutomationPeer? focus); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
namespace Avalonia.Automation.Provider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Exposes methods and properties to support UI Automation client access to controls that
|
||||
|
/// visually expand to display content and collapse to hide content.
|
||||
|
/// </summary>
|
||||
|
public interface IExpandCollapseProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the state, expanded or collapsed, of the control.
|
||||
|
/// </summary>
|
||||
|
ExpandCollapseState ExpandCollapseState { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Displays all child nodes, controls, or content of the control.
|
||||
|
/// </summary>
|
||||
|
void Expand(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Hides all nodes, controls, or content that are descendants of the control.
|
||||
|
/// </summary>
|
||||
|
void Collapse(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
namespace Avalonia.Automation.Provider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Exposes methods and properties to support UI Automation client access to controls that
|
||||
|
/// initiate or perform a single, unambiguous action and do not maintain state when
|
||||
|
/// activated.
|
||||
|
/// </summary>
|
||||
|
public interface IInvokeProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Sends a request to activate a control and initiate its single, unambiguous action.
|
||||
|
/// </summary>
|
||||
|
void Invoke(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Provider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Exposes methods and properties to support access by a UI Automation client to controls
|
||||
|
/// that can be set to a value within a range.
|
||||
|
/// </summary>
|
||||
|
public interface IRangeValueProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the value of a control is read-only.
|
||||
|
/// </summary>
|
||||
|
bool IsReadOnly { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the minimum range value that is supported by the control.
|
||||
|
/// </summary>
|
||||
|
double Minimum { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the maximum range value that is supported by the control.
|
||||
|
/// </summary>
|
||||
|
double Maximum { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the value of the control.
|
||||
|
/// </summary>
|
||||
|
double Value { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the value of the control.
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">The value to set.</param>
|
||||
|
public void SetValue(double value); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using Avalonia.Automation.Peers; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Provider |
||||
|
{ |
||||
|
public interface IRootProvider |
||||
|
{ |
||||
|
ITopLevelImpl? PlatformImpl { get; } |
||||
|
AutomationPeer? GetFocus(); |
||||
|
AutomationPeer? GetPeerFromPoint(Point p); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,71 @@ |
|||||
|
namespace Avalonia.Automation.Provider |
||||
|
{ |
||||
|
public enum ScrollAmount |
||||
|
{ |
||||
|
LargeDecrement, |
||||
|
SmallDecrement, |
||||
|
NoAmount, |
||||
|
LargeIncrement, |
||||
|
SmallIncrement, |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Exposes methods and properties to support access by a UI Automation client to a control
|
||||
|
/// that acts as a scrollable container for a collection of child objects.
|
||||
|
/// </summary>
|
||||
|
public interface IScrollProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the control can scroll horizontally.
|
||||
|
/// </summary>
|
||||
|
bool HorizontallyScrollable { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the current horizontal scroll position.
|
||||
|
/// </summary>
|
||||
|
double HorizontalScrollPercent { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the current horizontal view size.
|
||||
|
/// </summary>
|
||||
|
double HorizontalViewSize { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the control can scroll vertically.
|
||||
|
/// </summary>
|
||||
|
bool VerticallyScrollable { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the current vertical scroll position.
|
||||
|
/// </summary>
|
||||
|
double VerticalScrollPercent { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the vertical view size.
|
||||
|
/// </summary>
|
||||
|
double VerticalViewSize { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Scrolls the visible region of the content area horizontally and vertically.
|
||||
|
/// </summary>
|
||||
|
/// <param name="horizontalAmount">The horizontal increment specific to the control.</param>
|
||||
|
/// <param name="verticalAmount">The vertical increment specific to the control.</param>
|
||||
|
void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the horizontal and vertical scroll position as a percentage of the total content
|
||||
|
/// area within the control.
|
||||
|
/// </summary>
|
||||
|
/// <param name="horizontalPercent">
|
||||
|
/// The horizontal position as a percentage of the content area's total range.
|
||||
|
/// <see cref="ScrollPatternIdentifiers.NoScroll"/> should be passed in if the control
|
||||
|
/// cannot be scrolled in this direction.
|
||||
|
/// </param>
|
||||
|
/// <param name="verticalPercent">
|
||||
|
/// The vertical position as a percentage of the content area's total range.
|
||||
|
/// <see cref="ScrollPatternIdentifiers.NoScroll"/> should be passed in if the control
|
||||
|
/// cannot be scrolled in this direction.
|
||||
|
/// </param>
|
||||
|
void SetScrollPercent(double horizontalPercent, double verticalPercent); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Provider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Exposes methods and properties to support access by a UI Automation client to individual,
|
||||
|
/// selectable child controls of containers that implement <see cref="ISelectionProvider"/>.
|
||||
|
/// </summary>
|
||||
|
public interface ISelectionItemProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether an item is selected.
|
||||
|
/// </summary>
|
||||
|
bool IsSelected { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the UI Automation provider that implements <see cref="ISelectionProvider"/> and
|
||||
|
/// acts as the container for the calling object.
|
||||
|
/// </summary>
|
||||
|
ISelectionProvider? SelectionContainer { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds the current element to the collection of selected items.
|
||||
|
/// </summary>
|
||||
|
void AddToSelection(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes the current element from the collection of selected items.
|
||||
|
/// </summary>
|
||||
|
void RemoveFromSelection(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Clears any existing selection and then selects the current element.
|
||||
|
/// </summary>
|
||||
|
void Select(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Automation.Peers; |
||||
|
|
||||
|
namespace Avalonia.Automation.Provider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Exposes methods and properties to support access by a UI Automation client to controls
|
||||
|
/// that act as containers for a collection of individual, selectable child items.
|
||||
|
/// </summary>
|
||||
|
public interface ISelectionProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the provider allows more than one child element
|
||||
|
/// to be selected concurrently.
|
||||
|
/// </summary>
|
||||
|
bool CanSelectMultiple { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the provider requires at least one child element
|
||||
|
/// to be selected.
|
||||
|
/// </summary>
|
||||
|
bool IsSelectionRequired { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Retrieves a provider for each child element that is selected.
|
||||
|
/// </summary>
|
||||
|
IReadOnlyList<AutomationPeer> GetSelection(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
namespace Avalonia.Automation.Provider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains values that specify the toggle state of a UI Automation element.
|
||||
|
/// </summary>
|
||||
|
public enum ToggleState |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The UI Automation element isn't selected, checked, marked, or otherwise activated.
|
||||
|
/// </summary>
|
||||
|
Off, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The UI Automation element is selected, checked, marked, or otherwise activated.
|
||||
|
/// </summary>
|
||||
|
On, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The UI Automation element is in an indeterminate state.
|
||||
|
/// </summary>
|
||||
|
Indeterminate, |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Exposes methods and properties to support UI Automation client access to controls that can
|
||||
|
/// cycle through a set of states and maintain a particular state.
|
||||
|
/// </summary>
|
||||
|
public interface IToggleProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the toggle state of the control.
|
||||
|
/// </summary>
|
||||
|
ToggleState ToggleState { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Cycles through the toggle states of a control.
|
||||
|
/// </summary>
|
||||
|
void Toggle(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Automation.Provider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Exposes methods and properties to support access by a UI Automation client to controls
|
||||
|
/// that have an intrinsic value that does not span a range and that can be represented as
|
||||
|
/// a string.
|
||||
|
/// </summary>
|
||||
|
public interface IValueProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets a value that indicates whether the value of a control is read-only.
|
||||
|
/// </summary>
|
||||
|
bool IsReadOnly { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the value of the control.
|
||||
|
/// </summary>
|
||||
|
public string? Value { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the value of a control.
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">
|
||||
|
/// The value to set. The provider is responsible for converting the value to the
|
||||
|
/// appropriate data type.
|
||||
|
/// </param>
|
||||
|
public void SetValue(string? value); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using Avalonia.Automation.Provider; |
||||
|
|
||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains values used as identifiers by <see cref="IRangeValueProvider"/>.
|
||||
|
/// </summary>
|
||||
|
public static class RangeValuePatternIdentifiers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IRangeValueProvider.IsReadOnly"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty IsReadOnlyProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IRangeValueProvider.Minimum"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty MinimumProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IRangeValueProvider.Maximum"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty MaximumProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IRangeValueProvider.Value"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty ValueProperty { get; } = new(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
using Avalonia.Automation.Provider; |
||||
|
|
||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains values used as identifiers by <see cref="IScrollProvider"/>.
|
||||
|
/// </summary>
|
||||
|
public static class ScrollPatternIdentifiers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Specifies that scrolling should not be performed.
|
||||
|
/// </summary>
|
||||
|
public const double NoScroll = -1; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IScrollProvider.HorizontallyScrollable"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty HorizontallyScrollableProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IScrollProvider.HorizontalScrollPercent"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty HorizontalScrollPercentProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IScrollProvider.HorizontalViewSize"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty HorizontalViewSizeProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IScrollProvider.VerticallyScrollable"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty VerticallyScrollableProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IScrollProvider.VerticalScrollPercent"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty VerticalScrollPercentProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="IScrollProvider.VerticalViewSize"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty VerticalViewSizeProperty { get; } = new(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using Avalonia.Automation.Provider; |
||||
|
|
||||
|
namespace Avalonia.Automation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains values used as identifiers by <see cref="ISelectionProvider"/>.
|
||||
|
/// </summary>
|
||||
|
public static class SelectionPatternIdentifiers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="ISelectionProvider.CanSelectMultiple"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty CanSelectMultipleProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies <see cref="ISelectionProvider.IsSelectionRequired"/> automation property.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty IsSelectionRequiredProperty { get; } = new(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the property that gets the selected items in a container.
|
||||
|
/// </summary>
|
||||
|
public static AutomationProperty SelectionProperty { get; } = new(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using Avalonia.Automation; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using UIA = Avalonia.Win32.Interop.Automation; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Automation |
||||
|
{ |
||||
|
internal partial class AutomationNode : UIA.IExpandCollapseProvider |
||||
|
{ |
||||
|
public ExpandCollapseState ExpandCollapseState |
||||
|
{ |
||||
|
get => InvokeSync<IExpandCollapseProvider, ExpandCollapseState>(x => x.ExpandCollapseState); |
||||
|
} |
||||
|
|
||||
|
public void Expand() => InvokeSync<IExpandCollapseProvider>(x => x.Expand()); |
||||
|
public void Collapse() => InvokeSync<IExpandCollapseProvider>(x => x.Collapse()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using Avalonia.Automation.Provider; |
||||
|
using UIA = Avalonia.Win32.Interop.Automation; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Automation |
||||
|
{ |
||||
|
internal partial class AutomationNode : UIA.IRangeValueProvider |
||||
|
{ |
||||
|
double UIA.IRangeValueProvider.Value => InvokeSync<IRangeValueProvider, double>(x => x.Value); |
||||
|
public bool IsReadOnly => InvokeSync<IRangeValueProvider, bool>(x => x.IsReadOnly); |
||||
|
public double Maximum => InvokeSync<IRangeValueProvider, double>(x => x.Maximum); |
||||
|
public double Minimum => InvokeSync<IRangeValueProvider, double>(x => x.Minimum); |
||||
|
public double LargeChange => 1; |
||||
|
public double SmallChange => 1; |
||||
|
|
||||
|
public void SetValue(double value) => InvokeSync<IRangeValueProvider>(x => x.SetValue(value)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using Avalonia.Automation.Provider; |
||||
|
using UIA = Avalonia.Win32.Interop.Automation; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Automation |
||||
|
{ |
||||
|
internal partial class AutomationNode : UIA.IScrollProvider, UIA.IScrollItemProvider |
||||
|
{ |
||||
|
public bool HorizontallyScrollable => InvokeSync<IScrollProvider, bool>(x => x.HorizontallyScrollable); |
||||
|
public double HorizontalScrollPercent => InvokeSync<IScrollProvider, double>(x => x.HorizontalScrollPercent); |
||||
|
public double HorizontalViewSize => InvokeSync<IScrollProvider, double>(x => x.HorizontalViewSize); |
||||
|
public bool VerticallyScrollable => InvokeSync<IScrollProvider, bool>(x => x.VerticallyScrollable); |
||||
|
public double VerticalScrollPercent => InvokeSync<IScrollProvider, double>(x => x.VerticalScrollPercent); |
||||
|
public double VerticalViewSize => InvokeSync<IScrollProvider, double>(x => x.VerticalViewSize); |
||||
|
|
||||
|
public void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount) |
||||
|
{ |
||||
|
InvokeSync<IScrollProvider>(x => x.Scroll(horizontalAmount, verticalAmount)); |
||||
|
} |
||||
|
|
||||
|
public void SetScrollPercent(double horizontalPercent, double verticalPercent) |
||||
|
{ |
||||
|
InvokeSync<IScrollProvider>(x => x.SetScrollPercent(horizontalPercent, verticalPercent)); |
||||
|
} |
||||
|
|
||||
|
public void ScrollIntoView() |
||||
|
{ |
||||
|
InvokeSync(() => Peer.BringIntoView()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Automation.Peers; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using UIA = Avalonia.Win32.Interop.Automation; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Automation |
||||
|
{ |
||||
|
internal partial class AutomationNode : UIA.ISelectionProvider, UIA.ISelectionItemProvider |
||||
|
{ |
||||
|
public bool CanSelectMultiple => InvokeSync<ISelectionProvider, bool>(x => x.CanSelectMultiple); |
||||
|
public bool IsSelectionRequired => InvokeSync<ISelectionProvider, bool>(x => x.IsSelectionRequired); |
||||
|
public bool IsSelected => InvokeSync<ISelectionItemProvider, bool>(x => x.IsSelected); |
||||
|
|
||||
|
public UIA.IRawElementProviderSimple? SelectionContainer |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
var peer = InvokeSync<ISelectionItemProvider, ISelectionProvider?>(x => x.SelectionContainer); |
||||
|
return (peer as AutomationPeer)?.Node as AutomationNode; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public UIA.IRawElementProviderSimple[] GetSelection() |
||||
|
{ |
||||
|
var peers = InvokeSync<ISelectionProvider, IReadOnlyList<AutomationPeer>>(x => x.GetSelection()); |
||||
|
return peers?.Select(x => (UIA.IRawElementProviderSimple)x.Node).ToArray() ?? |
||||
|
Array.Empty<UIA.IRawElementProviderSimple>(); |
||||
|
} |
||||
|
|
||||
|
public void AddToSelection() => InvokeSync<ISelectionItemProvider>(x => x.AddToSelection()); |
||||
|
public void RemoveFromSelection() => InvokeSync<ISelectionItemProvider>(x => x.RemoveFromSelection()); |
||||
|
public void Select() => InvokeSync<ISelectionItemProvider>(x => x.Select()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using Avalonia.Automation.Provider; |
||||
|
using UIA = Avalonia.Win32.Interop.Automation; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Automation |
||||
|
{ |
||||
|
internal partial class AutomationNode : UIA.IToggleProvider |
||||
|
{ |
||||
|
public ToggleState ToggleState => InvokeSync<IToggleProvider, ToggleState>(x => x.ToggleState); |
||||
|
public void Toggle() => InvokeSync<IToggleProvider>(x => x.Toggle()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System.Runtime.InteropServices; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using UIA = Avalonia.Win32.Interop.Automation; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Automation |
||||
|
{ |
||||
|
internal partial class AutomationNode : UIA.IValueProvider |
||||
|
{ |
||||
|
public string? Value => InvokeSync<IValueProvider, string?>(x => x.Value); |
||||
|
|
||||
|
public void SetValue([MarshalAs(UnmanagedType.LPWStr)] string? value) |
||||
|
{ |
||||
|
InvokeSync<IValueProvider>(x => x.SetValue(value)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,328 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Diagnostics; |
||||
|
using System.Diagnostics.CodeAnalysis; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using Avalonia.Automation; |
||||
|
using Avalonia.Automation.Peers; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Threading; |
||||
|
using Avalonia.Win32.Interop.Automation; |
||||
|
using AAP = Avalonia.Automation.Provider; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
internal partial class AutomationNode : MarshalByRefObject, |
||||
|
IAutomationNode, |
||||
|
IRawElementProviderSimple, |
||||
|
IRawElementProviderSimple2, |
||||
|
IRawElementProviderFragment, |
||||
|
IRawElementProviderAdviseEvents, |
||||
|
IInvokeProvider |
||||
|
{ |
||||
|
private static Dictionary<AutomationProperty, UiaPropertyId> s_propertyMap = new() |
||||
|
{ |
||||
|
{ AutomationElementIdentifiers.BoundingRectangleProperty, UiaPropertyId.BoundingRectangle }, |
||||
|
{ AutomationElementIdentifiers.ClassNameProperty, UiaPropertyId.ClassName }, |
||||
|
{ AutomationElementIdentifiers.NameProperty, UiaPropertyId.Name }, |
||||
|
{ ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty, UiaPropertyId.ExpandCollapseExpandCollapseState }, |
||||
|
{ RangeValuePatternIdentifiers.IsReadOnlyProperty, UiaPropertyId.RangeValueIsReadOnly}, |
||||
|
{ RangeValuePatternIdentifiers.MaximumProperty, UiaPropertyId.RangeValueMaximum }, |
||||
|
{ RangeValuePatternIdentifiers.MinimumProperty, UiaPropertyId.RangeValueMinimum }, |
||||
|
{ RangeValuePatternIdentifiers.ValueProperty, UiaPropertyId.RangeValueValue }, |
||||
|
{ ScrollPatternIdentifiers.HorizontallyScrollableProperty, UiaPropertyId.ScrollHorizontallyScrollable }, |
||||
|
{ ScrollPatternIdentifiers.HorizontalScrollPercentProperty, UiaPropertyId.ScrollHorizontalScrollPercent }, |
||||
|
{ ScrollPatternIdentifiers.HorizontalViewSizeProperty, UiaPropertyId.ScrollHorizontalViewSize }, |
||||
|
{ ScrollPatternIdentifiers.VerticallyScrollableProperty, UiaPropertyId.ScrollVerticallyScrollable }, |
||||
|
{ ScrollPatternIdentifiers.VerticalScrollPercentProperty, UiaPropertyId.ScrollVerticalScrollPercent }, |
||||
|
{ ScrollPatternIdentifiers.VerticalViewSizeProperty, UiaPropertyId.ScrollVerticalViewSize }, |
||||
|
{ SelectionPatternIdentifiers.CanSelectMultipleProperty, UiaPropertyId.SelectionCanSelectMultiple }, |
||||
|
{ SelectionPatternIdentifiers.IsSelectionRequiredProperty, UiaPropertyId.SelectionIsSelectionRequired }, |
||||
|
{ SelectionPatternIdentifiers.SelectionProperty, UiaPropertyId.SelectionSelection }, |
||||
|
}; |
||||
|
|
||||
|
private readonly int[] _runtimeId; |
||||
|
private int _raiseFocusChanged; |
||||
|
private int _raisePropertyChanged; |
||||
|
|
||||
|
public AutomationNode(AutomationPeer peer) |
||||
|
{ |
||||
|
_runtimeId = new int[] { 3, GetHashCode() }; |
||||
|
Peer = peer; |
||||
|
} |
||||
|
|
||||
|
public AutomationPeer Peer { get; } |
||||
|
public IAutomationNodeFactory Factory => AutomationNodeFactory.Instance; |
||||
|
|
||||
|
public Rect BoundingRectangle |
||||
|
{ |
||||
|
get => InvokeSync(() => |
||||
|
{ |
||||
|
if (GetRoot()?.Node is RootAutomationNode root) |
||||
|
return root.ToScreen(Peer.GetBoundingRectangle()); |
||||
|
return default; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public virtual IRawElementProviderFragmentRoot? FragmentRoot |
||||
|
{ |
||||
|
get => InvokeSync(() => GetRoot())?.Node as IRawElementProviderFragmentRoot; |
||||
|
} |
||||
|
|
||||
|
public virtual IRawElementProviderSimple? HostRawElementProvider => null; |
||||
|
public ProviderOptions ProviderOptions => ProviderOptions.ServerSideProvider; |
||||
|
|
||||
|
public void ChildrenChanged() |
||||
|
{ |
||||
|
UiaCoreProviderApi.UiaRaiseStructureChangedEvent( |
||||
|
this, |
||||
|
StructureChangeType.ChildrenInvalidated, |
||||
|
_runtimeId, |
||||
|
_runtimeId.Length); |
||||
|
} |
||||
|
|
||||
|
public void PropertyChanged(AutomationProperty property, object? oldValue, object? newValue) |
||||
|
{ |
||||
|
if (_raisePropertyChanged > 0 && s_propertyMap.TryGetValue(property, out var id)) |
||||
|
{ |
||||
|
UiaCoreProviderApi.UiaRaiseAutomationPropertyChangedEvent(this, (int)id, oldValue, newValue); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[return: MarshalAs(UnmanagedType.IUnknown)] |
||||
|
public virtual object? GetPatternProvider(int patternId) |
||||
|
{ |
||||
|
return (UiaPatternId)patternId switch |
||||
|
{ |
||||
|
UiaPatternId.ExpandCollapse => Peer is IExpandCollapseProvider ? this : null, |
||||
|
UiaPatternId.Invoke => Peer is AAP.IInvokeProvider ? this : null, |
||||
|
UiaPatternId.RangeValue => Peer is AAP.IRangeValueProvider ? this : null, |
||||
|
UiaPatternId.Scroll => Peer is AAP.IScrollProvider ? this : null, |
||||
|
UiaPatternId.ScrollItem => this, |
||||
|
UiaPatternId.Selection => Peer is AAP.ISelectionProvider ? this : null, |
||||
|
UiaPatternId.SelectionItem => Peer is AAP.ISelectionItemProvider ? this : null, |
||||
|
UiaPatternId.Toggle => Peer is AAP.IToggleProvider ? this : null, |
||||
|
UiaPatternId.Value => Peer is AAP.IValueProvider ? this : null, |
||||
|
_ => null, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public virtual object? GetPropertyValue(int propertyId) |
||||
|
{ |
||||
|
return (UiaPropertyId)propertyId switch |
||||
|
{ |
||||
|
UiaPropertyId.AutomationId => InvokeSync(() => Peer.GetAutomationId()), |
||||
|
UiaPropertyId.ClassName => InvokeSync(() => Peer.GetClassName()), |
||||
|
UiaPropertyId.ClickablePoint => new[] { BoundingRectangle.Center.X, BoundingRectangle.Center.Y }, |
||||
|
UiaPropertyId.ControlType => InvokeSync(() => ToUiaControlType(Peer.GetAutomationControlType())), |
||||
|
UiaPropertyId.Culture => CultureInfo.CurrentCulture.LCID, |
||||
|
UiaPropertyId.FrameworkId => "Avalonia", |
||||
|
UiaPropertyId.HasKeyboardFocus => InvokeSync(() => Peer.HasKeyboardFocus()), |
||||
|
UiaPropertyId.IsContentElement => InvokeSync(() => Peer.IsContentElement()), |
||||
|
UiaPropertyId.IsControlElement => InvokeSync(() => Peer.IsControlElement()), |
||||
|
UiaPropertyId.IsEnabled => InvokeSync(() => Peer.IsEnabled()), |
||||
|
UiaPropertyId.IsKeyboardFocusable => InvokeSync(() => Peer.IsKeyboardFocusable()), |
||||
|
UiaPropertyId.LocalizedControlType => InvokeSync(() => Peer.GetLocalizedControlType()), |
||||
|
UiaPropertyId.Name => InvokeSync(() => Peer.GetName()), |
||||
|
UiaPropertyId.ProcessId => Process.GetCurrentProcess().Id, |
||||
|
UiaPropertyId.RuntimeId => _runtimeId, |
||||
|
_ => null, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public int[]? GetRuntimeId() => _runtimeId; |
||||
|
|
||||
|
public virtual IRawElementProviderFragment? Navigate(NavigateDirection direction) |
||||
|
{ |
||||
|
IAutomationNode? GetSibling(int direction) |
||||
|
{ |
||||
|
var children = Peer.GetParent()?.GetChildren(); |
||||
|
|
||||
|
for (var i = 0; i < (children?.Count ?? 0); ++i) |
||||
|
{ |
||||
|
if (ReferenceEquals(children![i], Peer)) |
||||
|
{ |
||||
|
var j = i + direction; |
||||
|
if (j >= 0 && j < children.Count) |
||||
|
return children[j].Node; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return InvokeSync(() => |
||||
|
{ |
||||
|
return direction switch |
||||
|
{ |
||||
|
NavigateDirection.Parent => Peer.GetParent()?.Node, |
||||
|
NavigateDirection.NextSibling => GetSibling(1), |
||||
|
NavigateDirection.PreviousSibling => GetSibling(-1), |
||||
|
NavigateDirection.FirstChild => Peer.GetChildren().FirstOrDefault()?.Node, |
||||
|
NavigateDirection.LastChild => Peer.GetChildren().LastOrDefault()?.Node, |
||||
|
_ => null, |
||||
|
}; |
||||
|
}) as IRawElementProviderFragment; |
||||
|
} |
||||
|
|
||||
|
public void SetFocus() => InvokeSync(() => Peer.SetFocus()); |
||||
|
|
||||
|
IRawElementProviderSimple[]? IRawElementProviderFragment.GetEmbeddedFragmentRoots() => null; |
||||
|
void IRawElementProviderSimple2.ShowContextMenu() => InvokeSync(() => Peer.ShowContextMenu()); |
||||
|
void IInvokeProvider.Invoke() => InvokeSync((AAP.IInvokeProvider x) => x.Invoke()); |
||||
|
|
||||
|
void IRawElementProviderAdviseEvents.AdviseEventAdded(int eventId, int[] properties) |
||||
|
{ |
||||
|
switch ((UiaEventId)eventId) |
||||
|
{ |
||||
|
case UiaEventId.AutomationPropertyChanged: |
||||
|
++_raisePropertyChanged; |
||||
|
break; |
||||
|
case UiaEventId.AutomationFocusChanged: |
||||
|
++_raiseFocusChanged; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void IRawElementProviderAdviseEvents.AdviseEventRemoved(int eventId, int[] properties) |
||||
|
{ |
||||
|
switch ((UiaEventId)eventId) |
||||
|
{ |
||||
|
case UiaEventId.AutomationPropertyChanged: |
||||
|
--_raisePropertyChanged; |
||||
|
break; |
||||
|
case UiaEventId.AutomationFocusChanged: |
||||
|
--_raiseFocusChanged; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected void InvokeSync(Action action) |
||||
|
{ |
||||
|
if (Dispatcher.UIThread.CheckAccess()) |
||||
|
action(); |
||||
|
else |
||||
|
Dispatcher.UIThread.InvokeAsync(action).Wait(); |
||||
|
} |
||||
|
|
||||
|
[return: MaybeNull] |
||||
|
protected T InvokeSync<T>(Func<T> func) |
||||
|
{ |
||||
|
if (Dispatcher.UIThread.CheckAccess()) |
||||
|
return func(); |
||||
|
else |
||||
|
return Dispatcher.UIThread.InvokeAsync(func).Result; |
||||
|
} |
||||
|
|
||||
|
protected void InvokeSync<TInterface>(Action<TInterface> action) |
||||
|
{ |
||||
|
if (Peer is TInterface i) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
InvokeSync(() => action(i)); |
||||
|
} |
||||
|
catch (AggregateException e) when (e.InnerException is ElementNotEnabledException) |
||||
|
{ |
||||
|
throw new COMException(e.Message, UiaCoreProviderApi.UIA_E_ELEMENTNOTENABLED); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[return: MaybeNull] |
||||
|
protected TResult InvokeSync<TInterface, TResult>(Func<TInterface, TResult> func) |
||||
|
{ |
||||
|
if (Peer is TInterface i) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return InvokeSync(() => func(i)); |
||||
|
} |
||||
|
catch (AggregateException e) when (e.InnerException is ElementNotEnabledException) |
||||
|
{ |
||||
|
throw new COMException(e.Message, UiaCoreProviderApi.UIA_E_ELEMENTNOTENABLED); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return default; |
||||
|
} |
||||
|
|
||||
|
protected void RaiseFocusChanged(AutomationNode? focused) |
||||
|
{ |
||||
|
if (_raiseFocusChanged > 0) |
||||
|
{ |
||||
|
UiaCoreProviderApi.UiaRaiseAutomationEvent( |
||||
|
focused, |
||||
|
(int)UiaEventId.AutomationFocusChanged); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private AutomationPeer GetRoot() |
||||
|
{ |
||||
|
Dispatcher.UIThread.VerifyAccess(); |
||||
|
|
||||
|
var peer = Peer; |
||||
|
var parent = peer.GetParent(); |
||||
|
|
||||
|
while (parent is object) |
||||
|
{ |
||||
|
peer = parent; |
||||
|
parent = peer.GetParent(); |
||||
|
} |
||||
|
|
||||
|
return peer; |
||||
|
} |
||||
|
|
||||
|
private static UiaControlTypeId ToUiaControlType(AutomationControlType role) |
||||
|
{ |
||||
|
return role switch |
||||
|
{ |
||||
|
AutomationControlType.Button => UiaControlTypeId.Button, |
||||
|
AutomationControlType.Calendar => UiaControlTypeId.Calendar, |
||||
|
AutomationControlType.CheckBox => UiaControlTypeId.CheckBox, |
||||
|
AutomationControlType.ComboBox => UiaControlTypeId.ComboBox, |
||||
|
AutomationControlType.Edit => UiaControlTypeId.Edit, |
||||
|
AutomationControlType.Hyperlink => UiaControlTypeId.Hyperlink, |
||||
|
AutomationControlType.Image => UiaControlTypeId.Image, |
||||
|
AutomationControlType.ListItem => UiaControlTypeId.ListItem, |
||||
|
AutomationControlType.List => UiaControlTypeId.List, |
||||
|
AutomationControlType.Menu => UiaControlTypeId.Menu, |
||||
|
AutomationControlType.MenuBar => UiaControlTypeId.MenuBar, |
||||
|
AutomationControlType.MenuItem => UiaControlTypeId.MenuItem, |
||||
|
AutomationControlType.ProgressBar => UiaControlTypeId.ProgressBar, |
||||
|
AutomationControlType.RadioButton => UiaControlTypeId.RadioButton, |
||||
|
AutomationControlType.ScrollBar => UiaControlTypeId.ScrollBar, |
||||
|
AutomationControlType.Slider => UiaControlTypeId.Slider, |
||||
|
AutomationControlType.Spinner => UiaControlTypeId.Spinner, |
||||
|
AutomationControlType.StatusBar => UiaControlTypeId.StatusBar, |
||||
|
AutomationControlType.Tab => UiaControlTypeId.Tab, |
||||
|
AutomationControlType.TabItem => UiaControlTypeId.TabItem, |
||||
|
AutomationControlType.Text => UiaControlTypeId.Text, |
||||
|
AutomationControlType.ToolBar => UiaControlTypeId.ToolBar, |
||||
|
AutomationControlType.ToolTip => UiaControlTypeId.ToolTip, |
||||
|
AutomationControlType.Tree => UiaControlTypeId.Tree, |
||||
|
AutomationControlType.TreeItem => UiaControlTypeId.TreeItem, |
||||
|
AutomationControlType.Custom => UiaControlTypeId.Custom, |
||||
|
AutomationControlType.Group => UiaControlTypeId.Group, |
||||
|
AutomationControlType.Thumb => UiaControlTypeId.Thumb, |
||||
|
AutomationControlType.DataGrid => UiaControlTypeId.DataGrid, |
||||
|
AutomationControlType.DataItem => UiaControlTypeId.DataItem, |
||||
|
AutomationControlType.Document => UiaControlTypeId.Document, |
||||
|
AutomationControlType.SplitButton => UiaControlTypeId.SplitButton, |
||||
|
AutomationControlType.Window => UiaControlTypeId.Window, |
||||
|
AutomationControlType.Pane => UiaControlTypeId.Pane, |
||||
|
AutomationControlType.Header => UiaControlTypeId.Header, |
||||
|
AutomationControlType.HeaderItem => UiaControlTypeId.HeaderItem, |
||||
|
AutomationControlType.Table => UiaControlTypeId.Table, |
||||
|
AutomationControlType.TitleBar => UiaControlTypeId.TitleBar, |
||||
|
AutomationControlType.Separator => UiaControlTypeId.Separator, |
||||
|
_ => UiaControlTypeId.Custom, |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Avalonia.Automation.Peers; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Threading; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Automation |
||||
|
{ |
||||
|
internal class AutomationNodeFactory : IAutomationNodeFactory |
||||
|
{ |
||||
|
public static readonly AutomationNodeFactory Instance = new AutomationNodeFactory(); |
||||
|
|
||||
|
public IAutomationNode CreateNode(AutomationPeer peer) |
||||
|
{ |
||||
|
Dispatcher.UIThread.VerifyAccess(); |
||||
|
return peer is IRootProvider ? new RootAutomationNode(peer) : new AutomationNode(peer); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using Avalonia.Automation.Peers; |
||||
|
using Avalonia.Automation.Platform; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
using Avalonia.Win32.Interop.Automation; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Automation |
||||
|
{ |
||||
|
internal class RootAutomationNode : AutomationNode, |
||||
|
IRawElementProviderFragmentRoot, |
||||
|
IRootAutomationNode |
||||
|
{ |
||||
|
public RootAutomationNode(AutomationPeer peer) |
||||
|
: base(peer) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override IRawElementProviderFragmentRoot? FragmentRoot => this; |
||||
|
public new IRootProvider Peer => (IRootProvider)base.Peer; |
||||
|
public WindowImpl? WindowImpl => Peer.PlatformImpl as WindowImpl; |
||||
|
|
||||
|
public IRawElementProviderFragment? ElementProviderFromPoint(double x, double y) |
||||
|
{ |
||||
|
if (WindowImpl is null) |
||||
|
return null; |
||||
|
|
||||
|
var p = WindowImpl.PointToClient(new PixelPoint((int)x, (int)y)); |
||||
|
var peer = (WindowBaseAutomationPeer)Peer; |
||||
|
var found = InvokeSync(() => peer.GetPeerFromPoint(p)); |
||||
|
var result = found?.Node as IRawElementProviderFragment; |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public IRawElementProviderFragment? GetFocus() |
||||
|
{ |
||||
|
var focus = InvokeSync(() => Peer.GetFocus()); |
||||
|
return (AutomationNode?)focus?.Node; |
||||
|
} |
||||
|
|
||||
|
public void FocusChanged(AutomationPeer? focus) |
||||
|
{ |
||||
|
var node = focus?.Node as AutomationNode; |
||||
|
RaiseFocusChanged(node); |
||||
|
} |
||||
|
|
||||
|
public Rect ToScreen(Rect rect) |
||||
|
{ |
||||
|
if (WindowImpl is null) |
||||
|
return default; |
||||
|
return new PixelRect( |
||||
|
WindowImpl.PointToScreen(rect.TopLeft), |
||||
|
WindowImpl.PointToScreen(rect.BottomRight)) |
||||
|
.ToRect(1); |
||||
|
} |
||||
|
|
||||
|
public override IRawElementProviderSimple? HostRawElementProvider |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
var handle = WindowImpl?.Handle.Handle ?? IntPtr.Zero; |
||||
|
if (handle == IntPtr.Zero) |
||||
|
return null; |
||||
|
var hr = UiaCoreProviderApi.UiaHostProviderFromHwnd(handle, out var result); |
||||
|
Marshal.ThrowExceptionForHR(hr); |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("70d46e77-e3a8-449d-913c-e30eb2afecdb")] |
||||
|
public enum DockPosition |
||||
|
{ |
||||
|
Top, |
||||
|
Left, |
||||
|
Bottom, |
||||
|
Right, |
||||
|
Fill, |
||||
|
None |
||||
|
} |
||||
|
|
||||
|
[ComVisible(true)] |
||||
|
[Guid("159bc72c-4ad3-485e-9637-d7052edf0146")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IDockProvider |
||||
|
{ |
||||
|
void SetDockPosition(DockPosition dockPosition); |
||||
|
DockPosition DockPosition { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using Avalonia.Automation; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("d847d3a5-cab0-4a98-8c32-ecb45c59ad24")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IExpandCollapseProvider |
||||
|
{ |
||||
|
void Expand(); |
||||
|
void Collapse(); |
||||
|
ExpandCollapseState ExpandCollapseState { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("d02541f1-fb81-4d64-ae32-f520f8a6dbd1")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IGridItemProvider |
||||
|
{ |
||||
|
int Row { get; } |
||||
|
int Column { get; } |
||||
|
int RowSpan { get; } |
||||
|
int ColumnSpan { get; } |
||||
|
IRawElementProviderSimple ContainingGrid { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("b17d6187-0907-464b-a168-0ef17a1572b1")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IGridProvider |
||||
|
{ |
||||
|
IRawElementProviderSimple GetItem(int row, int column); |
||||
|
int RowCount { get; } |
||||
|
int ColumnCount { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
// See the LICENSE file in the project root for more information.
|
||||
|
|
||||
|
// Description: Invoke pattern provider interface
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("54fcb24b-e18e-47a2-b4d3-eccbe77599a2")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IInvokeProvider |
||||
|
{ |
||||
|
void Invoke(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("6278cab1-b556-4a1a-b4e0-418acc523201")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IMultipleViewProvider |
||||
|
{ |
||||
|
string GetViewName(int viewId); |
||||
|
void SetCurrentView(int viewId); |
||||
|
int CurrentView { get; } |
||||
|
int[] GetSupportedViews(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("36dc7aef-33e6-4691-afe1-2be7274b3d33")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IRangeValueProvider |
||||
|
{ |
||||
|
void SetValue(double value); |
||||
|
double Value { get; } |
||||
|
bool IsReadOnly { [return: MarshalAs(UnmanagedType.Bool)] get; } |
||||
|
double Maximum { get; } |
||||
|
double Minimum { get; } |
||||
|
double LargeChange { get; } |
||||
|
double SmallChange { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("a407b27b-0f6d-4427-9292-473c7bf93258")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IRawElementProviderAdviseEvents : IRawElementProviderSimple |
||||
|
{ |
||||
|
void AdviseEventAdded(int eventId, int [] properties); |
||||
|
void AdviseEventRemoved(int eventId, int [] properties); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("670c3006-bf4c-428b-8534-e1848f645122")] |
||||
|
public enum NavigateDirection |
||||
|
{ |
||||
|
Parent, |
||||
|
NextSibling, |
||||
|
PreviousSibling, |
||||
|
FirstChild, |
||||
|
LastChild, |
||||
|
} |
||||
|
|
||||
|
// NOTE: This interface needs to be public otherwise Navigate is never called. I have no idea
|
||||
|
// why given that IRawElementProviderSimple and IRawElementProviderFragmentRoot seem to get
|
||||
|
// called fine when they're internal, but I lost a couple of days to this.
|
||||
|
[ComVisible(true)] |
||||
|
[Guid("f7063da8-8359-439c-9297-bbc5299a7d87")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IRawElementProviderFragment : IRawElementProviderSimple |
||||
|
{ |
||||
|
IRawElementProviderFragment? Navigate(NavigateDirection direction); |
||||
|
int[]? GetRuntimeId(); |
||||
|
Rect BoundingRectangle { get; } |
||||
|
IRawElementProviderSimple[]? GetEmbeddedFragmentRoots(); |
||||
|
void SetFocus(); |
||||
|
IRawElementProviderFragmentRoot? FragmentRoot { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("620ce2a5-ab8f-40a9-86cb-de3c75599b58")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IRawElementProviderFragmentRoot : IRawElementProviderFragment |
||||
|
{ |
||||
|
IRawElementProviderFragment ElementProviderFromPoint(double x, double y); |
||||
|
IRawElementProviderFragment GetFocus(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,285 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[Flags] |
||||
|
public enum ProviderOptions |
||||
|
{ |
||||
|
ClientSideProvider = 0x0001, |
||||
|
ServerSideProvider = 0x0002, |
||||
|
NonClientAreaProvider = 0x0004, |
||||
|
OverrideProvider = 0x0008, |
||||
|
ProviderOwnsSetFocus = 0x0010, |
||||
|
UseComThreading = 0x0020 |
||||
|
} |
||||
|
|
||||
|
internal enum UiaPropertyId |
||||
|
{ |
||||
|
RuntimeId = 30000, |
||||
|
BoundingRectangle, |
||||
|
ProcessId, |
||||
|
ControlType, |
||||
|
LocalizedControlType, |
||||
|
Name, |
||||
|
AcceleratorKey, |
||||
|
AccessKey, |
||||
|
HasKeyboardFocus, |
||||
|
IsKeyboardFocusable, |
||||
|
IsEnabled, |
||||
|
AutomationId, |
||||
|
ClassName, |
||||
|
HelpText, |
||||
|
ClickablePoint, |
||||
|
Culture, |
||||
|
IsControlElement, |
||||
|
IsContentElement, |
||||
|
LabeledBy, |
||||
|
IsPassword, |
||||
|
NativeWindowHandle, |
||||
|
ItemType, |
||||
|
IsOffscreen, |
||||
|
Orientation, |
||||
|
FrameworkId, |
||||
|
IsRequiredForForm, |
||||
|
ItemStatus, |
||||
|
IsDockPatternAvailable, |
||||
|
IsExpandCollapsePatternAvailable, |
||||
|
IsGridItemPatternAvailable, |
||||
|
IsGridPatternAvailable, |
||||
|
IsInvokePatternAvailable, |
||||
|
IsMultipleViewPatternAvailable, |
||||
|
IsRangeValuePatternAvailable, |
||||
|
IsScrollPatternAvailable, |
||||
|
IsScrollItemPatternAvailable, |
||||
|
IsSelectionItemPatternAvailable, |
||||
|
IsSelectionPatternAvailable, |
||||
|
IsTablePatternAvailable, |
||||
|
IsTableItemPatternAvailable, |
||||
|
IsTextPatternAvailable, |
||||
|
IsTogglePatternAvailable, |
||||
|
IsTransformPatternAvailable, |
||||
|
IsValuePatternAvailable, |
||||
|
IsWindowPatternAvailable, |
||||
|
ValueValue, |
||||
|
ValueIsReadOnly, |
||||
|
RangeValueValue, |
||||
|
RangeValueIsReadOnly, |
||||
|
RangeValueMinimum, |
||||
|
RangeValueMaximum, |
||||
|
RangeValueLargeChange, |
||||
|
RangeValueSmallChange, |
||||
|
ScrollHorizontalScrollPercent, |
||||
|
ScrollHorizontalViewSize, |
||||
|
ScrollVerticalScrollPercent, |
||||
|
ScrollVerticalViewSize, |
||||
|
ScrollHorizontallyScrollable, |
||||
|
ScrollVerticallyScrollable, |
||||
|
SelectionSelection, |
||||
|
SelectionCanSelectMultiple, |
||||
|
SelectionIsSelectionRequired, |
||||
|
GridRowCount, |
||||
|
GridColumnCount, |
||||
|
GridItemRow, |
||||
|
GridItemColumn, |
||||
|
GridItemRowSpan, |
||||
|
GridItemColumnSpan, |
||||
|
GridItemContainingGrid, |
||||
|
DockDockPosition, |
||||
|
ExpandCollapseExpandCollapseState, |
||||
|
MultipleViewCurrentView, |
||||
|
MultipleViewSupportedViews, |
||||
|
WindowCanMaximize, |
||||
|
WindowCanMinimize, |
||||
|
WindowWindowVisualState, |
||||
|
WindowWindowInteractionState, |
||||
|
WindowIsModal, |
||||
|
WindowIsTopmost, |
||||
|
SelectionItemIsSelected, |
||||
|
SelectionItemSelectionContainer, |
||||
|
TableRowHeaders, |
||||
|
TableColumnHeaders, |
||||
|
TableRowOrColumnMajor, |
||||
|
TableItemRowHeaderItems, |
||||
|
TableItemColumnHeaderItems, |
||||
|
ToggleToggleState, |
||||
|
TransformCanMove, |
||||
|
TransformCanResize, |
||||
|
TransformCanRotate, |
||||
|
IsLegacyIAccessiblePatternAvailable, |
||||
|
LegacyIAccessibleChildId, |
||||
|
LegacyIAccessibleName, |
||||
|
LegacyIAccessibleValue, |
||||
|
LegacyIAccessibleDescription, |
||||
|
LegacyIAccessibleRole, |
||||
|
LegacyIAccessibleState, |
||||
|
LegacyIAccessibleHelp, |
||||
|
LegacyIAccessibleKeyboardShortcut, |
||||
|
LegacyIAccessibleSelection, |
||||
|
LegacyIAccessibleDefaultAction, |
||||
|
AriaRole, |
||||
|
AriaProperties, |
||||
|
IsDataValidForForm, |
||||
|
ControllerFor, |
||||
|
DescribedBy, |
||||
|
FlowsTo, |
||||
|
ProviderDescription, |
||||
|
IsItemContainerPatternAvailable, |
||||
|
IsVirtualizedItemPatternAvailable, |
||||
|
IsSynchronizedInputPatternAvailable, |
||||
|
OptimizeForVisualContent, |
||||
|
IsObjectModelPatternAvailable, |
||||
|
AnnotationAnnotationTypeId, |
||||
|
AnnotationAnnotationTypeName, |
||||
|
AnnotationAuthor, |
||||
|
AnnotationDateTime, |
||||
|
AnnotationTarget, |
||||
|
IsAnnotationPatternAvailable, |
||||
|
IsTextPattern2Available, |
||||
|
StylesStyleId, |
||||
|
StylesStyleName, |
||||
|
StylesFillColor, |
||||
|
StylesFillPatternStyle, |
||||
|
StylesShape, |
||||
|
StylesFillPatternColor, |
||||
|
StylesExtendedProperties, |
||||
|
IsStylesPatternAvailable, |
||||
|
IsSpreadsheetPatternAvailable, |
||||
|
SpreadsheetItemFormula, |
||||
|
SpreadsheetItemAnnotationObjects, |
||||
|
SpreadsheetItemAnnotationTypes, |
||||
|
IsSpreadsheetItemPatternAvailable, |
||||
|
Transform2CanZoom, |
||||
|
IsTransformPattern2Available, |
||||
|
LiveSetting, |
||||
|
IsTextChildPatternAvailable, |
||||
|
IsDragPatternAvailable, |
||||
|
DragIsGrabbed, |
||||
|
DragDropEffect, |
||||
|
DragDropEffects, |
||||
|
IsDropTargetPatternAvailable, |
||||
|
DropTargetDropTargetEffect, |
||||
|
DropTargetDropTargetEffects, |
||||
|
DragGrabbedItems, |
||||
|
Transform2ZoomLevel, |
||||
|
Transform2ZoomMinimum, |
||||
|
Transform2ZoomMaximum, |
||||
|
FlowsFrom, |
||||
|
IsTextEditPatternAvailable, |
||||
|
IsPeripheral, |
||||
|
IsCustomNavigationPatternAvailable, |
||||
|
PositionInSet, |
||||
|
SizeOfSet, |
||||
|
Level, |
||||
|
AnnotationTypes, |
||||
|
AnnotationObjects, |
||||
|
LandmarkType, |
||||
|
LocalizedLandmarkType, |
||||
|
FullDescription, |
||||
|
FillColor, |
||||
|
OutlineColor, |
||||
|
FillType, |
||||
|
VisualEffects, |
||||
|
OutlineThickness, |
||||
|
CenterPoint, |
||||
|
Rotatation, |
||||
|
Size |
||||
|
} |
||||
|
|
||||
|
internal enum UiaPatternId |
||||
|
{ |
||||
|
Invoke = 10000, |
||||
|
Selection, |
||||
|
Value, |
||||
|
RangeValue, |
||||
|
Scroll, |
||||
|
ExpandCollapse, |
||||
|
Grid, |
||||
|
GridItem, |
||||
|
MultipleView, |
||||
|
Window, |
||||
|
SelectionItem, |
||||
|
Dock, |
||||
|
Table, |
||||
|
TableItem, |
||||
|
Text, |
||||
|
Toggle, |
||||
|
Transform, |
||||
|
ScrollItem, |
||||
|
LegacyIAccessible, |
||||
|
ItemContainer, |
||||
|
VirtualizedItem, |
||||
|
SynchronizedInput, |
||||
|
ObjectModel, |
||||
|
Annotation, |
||||
|
Text2, |
||||
|
Styles, |
||||
|
Spreadsheet, |
||||
|
SpreadsheetItem, |
||||
|
Transform2, |
||||
|
TextChild, |
||||
|
Drag, |
||||
|
DropTarget, |
||||
|
TextEdit, |
||||
|
CustomNavigation |
||||
|
}; |
||||
|
|
||||
|
internal enum UiaControlTypeId |
||||
|
{ |
||||
|
Button = 50000, |
||||
|
Calendar, |
||||
|
CheckBox, |
||||
|
ComboBox, |
||||
|
Edit, |
||||
|
Hyperlink, |
||||
|
Image, |
||||
|
ListItem, |
||||
|
List, |
||||
|
Menu, |
||||
|
MenuBar, |
||||
|
MenuItem, |
||||
|
ProgressBar, |
||||
|
RadioButton, |
||||
|
ScrollBar, |
||||
|
Slider, |
||||
|
Spinner, |
||||
|
StatusBar, |
||||
|
Tab, |
||||
|
TabItem, |
||||
|
Text, |
||||
|
ToolBar, |
||||
|
ToolTip, |
||||
|
Tree, |
||||
|
TreeItem, |
||||
|
Custom, |
||||
|
Group, |
||||
|
Thumb, |
||||
|
DataGrid, |
||||
|
DataItem, |
||||
|
Document, |
||||
|
SplitButton, |
||||
|
Window, |
||||
|
Pane, |
||||
|
Header, |
||||
|
HeaderItem, |
||||
|
Table, |
||||
|
TitleBar, |
||||
|
Separator, |
||||
|
SemanticZoom, |
||||
|
AppBar |
||||
|
}; |
||||
|
|
||||
|
[ComVisible(true)] |
||||
|
[Guid("d6dd68d1-86fd-4332-8666-9abedea2d24c")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IRawElementProviderSimple |
||||
|
{ |
||||
|
ProviderOptions ProviderOptions { get; } |
||||
|
[return: MarshalAs(UnmanagedType.IUnknown)] |
||||
|
object? GetPatternProvider(int patternId); |
||||
|
object? GetPropertyValue(int propertyId); |
||||
|
IRawElementProviderSimple? HostRawElementProvider { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("a0a839a9-8da1-4a82-806a-8e0d44e79f56")] |
||||
|
public interface IRawElementProviderSimple2 |
||||
|
{ |
||||
|
void ShowContextMenu(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("2360c714-4bf1-4b26-ba65-9b21316127eb")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IScrollItemProvider |
||||
|
{ |
||||
|
void ScrollIntoView(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("b38b8077-1fc3-42a5-8cae-d40c2215055a")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IScrollProvider |
||||
|
{ |
||||
|
void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount); |
||||
|
void SetScrollPercent(double horizontalPercent, double verticalPercent); |
||||
|
double HorizontalScrollPercent { get; } |
||||
|
double VerticalScrollPercent { get; } |
||||
|
double HorizontalViewSize { get; } |
||||
|
double VerticalViewSize { get; } |
||||
|
bool HorizontallyScrollable { [return: MarshalAs(UnmanagedType.Bool)] get; } |
||||
|
bool VerticallyScrollable { [return: MarshalAs(UnmanagedType.Bool)] get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("2acad808-b2d4-452d-a407-91ff1ad167b2")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface ISelectionItemProvider |
||||
|
{ |
||||
|
void Select(); |
||||
|
void AddToSelection(); |
||||
|
void RemoveFromSelection(); |
||||
|
bool IsSelected { [return: MarshalAs(UnmanagedType.Bool)] get; } |
||||
|
IRawElementProviderSimple? SelectionContainer { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("fb8b03af-3bdf-48d4-bd36-1a65793be168")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface ISelectionProvider |
||||
|
{ |
||||
|
IRawElementProviderSimple [] GetSelection(); |
||||
|
bool CanSelectMultiple { [return: MarshalAs(UnmanagedType.Bool)] get; } |
||||
|
bool IsSelectionRequired { [return: MarshalAs(UnmanagedType.Bool)] get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("fdc8f176-aed2-477a-8c89-5604c66f278d")] |
||||
|
public enum SynchronizedInputType |
||||
|
{ |
||||
|
KeyUp = 0x01, |
||||
|
KeyDown = 0x02, |
||||
|
MouseLeftButtonUp = 0x04, |
||||
|
MouseLeftButtonDown = 0x08, |
||||
|
MouseRightButtonUp = 0x10, |
||||
|
MouseRightButtonDown = 0x20 |
||||
|
} |
||||
|
|
||||
|
[ComVisible(true)] |
||||
|
[Guid("29db1a06-02ce-4cf7-9b42-565d4fab20ee")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface ISynchronizedInputProvider |
||||
|
{ |
||||
|
void StartListening(SynchronizedInputType inputType); |
||||
|
void Cancel(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("b9734fa6-771f-4d78-9c90-2517999349cd")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface ITableItemProvider : IGridItemProvider |
||||
|
{ |
||||
|
IRawElementProviderSimple [] GetRowHeaderItems(); |
||||
|
IRawElementProviderSimple [] GetColumnHeaderItems(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("15fdf2e2-9847-41cd-95dd-510612a025ea")] |
||||
|
public enum RowOrColumnMajor |
||||
|
{ |
||||
|
RowMajor, |
||||
|
ColumnMajor, |
||||
|
Indeterminate, |
||||
|
} |
||||
|
|
||||
|
[ComVisible(true)] |
||||
|
[Guid("9c860395-97b3-490a-b52a-858cc22af166")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface ITableProvider : IGridProvider |
||||
|
{ |
||||
|
IRawElementProviderSimple [] GetRowHeaders(); |
||||
|
IRawElementProviderSimple [] GetColumnHeaders(); |
||||
|
RowOrColumnMajor RowOrColumnMajor { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[Flags] |
||||
|
[ComVisible(true)] |
||||
|
[Guid("3d9e3d8f-bfb0-484f-84ab-93ff4280cbc4")] |
||||
|
public enum SupportedTextSelection |
||||
|
{ |
||||
|
None, |
||||
|
Single, |
||||
|
Multiple, |
||||
|
} |
||||
|
|
||||
|
[ComVisible(true)] |
||||
|
[Guid("3589c92c-63f3-4367-99bb-ada653b77cf2")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface ITextProvider |
||||
|
{ |
||||
|
ITextRangeProvider [] GetSelection(); |
||||
|
ITextRangeProvider [] GetVisibleRanges(); |
||||
|
ITextRangeProvider RangeFromChild(IRawElementProviderSimple childElement); |
||||
|
ITextRangeProvider RangeFromPoint(Point screenLocation); |
||||
|
ITextRangeProvider DocumentRange { get; } |
||||
|
SupportedTextSelection SupportedTextSelection { get; } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
@ -0,0 +1,48 @@ |
|||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
public enum TextPatternRangeEndpoint |
||||
|
{ |
||||
|
Start = 0, |
||||
|
End = 1, |
||||
|
} |
||||
|
|
||||
|
public enum TextUnit |
||||
|
{ |
||||
|
Character = 0, |
||||
|
Format = 1, |
||||
|
Word = 2, |
||||
|
Line = 3, |
||||
|
Paragraph = 4, |
||||
|
Page = 5, |
||||
|
Document = 6, |
||||
|
} |
||||
|
|
||||
|
[ComVisible(true)] |
||||
|
[Guid("5347ad7b-c355-46f8-aff5-909033582f63")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface ITextRangeProvider |
||||
|
|
||||
|
{ |
||||
|
ITextRangeProvider Clone(); |
||||
|
[return: MarshalAs(UnmanagedType.Bool)] |
||||
|
bool Compare(ITextRangeProvider range); |
||||
|
int CompareEndpoints(TextPatternRangeEndpoint endpoint, ITextRangeProvider targetRange, TextPatternRangeEndpoint targetEndpoint); |
||||
|
void ExpandToEnclosingUnit(TextUnit unit); |
||||
|
ITextRangeProvider FindAttribute(int attribute, object value, [MarshalAs(UnmanagedType.Bool)] bool backward); |
||||
|
ITextRangeProvider FindText(string text, [MarshalAs(UnmanagedType.Bool)] bool backward, [MarshalAs(UnmanagedType.Bool)] bool ignoreCase); |
||||
|
object GetAttributeValue(int attribute); |
||||
|
double [] GetBoundingRectangles(); |
||||
|
IRawElementProviderSimple GetEnclosingElement(); |
||||
|
string GetText(int maxLength); |
||||
|
int Move(TextUnit unit, int count); |
||||
|
int MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, int count); |
||||
|
void MoveEndpointByRange(TextPatternRangeEndpoint endpoint, ITextRangeProvider targetRange, TextPatternRangeEndpoint targetEndpoint); |
||||
|
void Select(); |
||||
|
void AddToSelection(); |
||||
|
void RemoveFromSelection(); |
||||
|
void ScrollIntoView([MarshalAs(UnmanagedType.Bool)] bool alignToTop); |
||||
|
IRawElementProviderSimple[] GetChildren(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using Avalonia.Automation.Provider; |
||||
|
|
||||
|
namespace Avalonia.Win32.Interop.Automation |
||||
|
{ |
||||
|
[ComVisible(true)] |
||||
|
[Guid("56d00bd0-c4f4-433c-a836-1a52a57e0892")] |
||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
||||
|
public interface IToggleProvider |
||||
|
{ |
||||
|
void Toggle( ); |
||||
|
ToggleState ToggleState { get; } |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue