diff --git a/native/Avalonia.Native/src/OSX/automation.mm b/native/Avalonia.Native/src/OSX/automation.mm index f8c288c489..b42dc22f7a 100644 --- a/native/Avalonia.Native/src/OSX/automation.mm +++ b/native/Avalonia.Native/src/OSX/automation.mm @@ -220,6 +220,11 @@ return GetNSStringAndRelease(_peer->GetHelpText()); } +- (NSString *)accessibilityPlaceholderValue +{ + return GetNSStringAndRelease(_peer->GetPlaceholderText()); +} + - (id)accessibilityValue { if (_peer->IsRangeValueProvider()) diff --git a/samples/IntegrationTestApp/Pages/AutomationPage.axaml b/samples/IntegrationTestApp/Pages/AutomationPage.axaml index c02bc1baa6..91317bcb11 100644 --- a/samples/IntegrationTestApp/Pages/AutomationPage.axaml +++ b/samples/IntegrationTestApp/Pages/AutomationPage.axaml @@ -10,7 +10,7 @@ TextBlockWithNameAndAutomationId Label for TextBox - + Foo diff --git a/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs index b32b60118c..47754c9b50 100644 --- a/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs @@ -283,12 +283,29 @@ namespace Avalonia.Automation.Peers /// public string GetHelpText() => GetHelpTextCore() ?? string.Empty; + /// + /// Gets text that provides a placeholder for the element that is associated with this automation peer. + /// + /// + /// + /// + /// Windows + /// No mapping. + /// + /// + /// macOS + /// NSAccessibilityProtocol.accessibilityPlaceholderValue + /// + /// + /// + public string GetPlaceholderText() => GetPlaceholderTextCore() ?? string.Empty; + /// /// Gets the control type for the element that is associated with the UI Automation peer. /// /// /// Gets the type of the element. - /// + /// /// /// /// Windows @@ -595,6 +612,7 @@ namespace Avalonia.Automation.Peers protected abstract AutomationPeer? GetLabeledByCore(); protected abstract string? GetNameCore(); protected virtual string? GetHelpTextCore() => null; + protected virtual string? GetPlaceholderTextCore() => null; protected virtual AutomationLandmarkType? GetLandmarkTypeCore() => null; protected virtual int GetHeadingLevelCore() => 0; protected virtual string? GetItemTypeCore() => null; diff --git a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs index cdab4911f2..aaabc6f495 100644 --- a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs @@ -132,6 +132,12 @@ namespace Avalonia.Automation.Peers result = ToolTip.GetTip(Owner) as string; } + // Windows uses HelpText for placeholder text; macOS uses a separate property. + if (string.IsNullOrWhiteSpace(result)) + { + result = GetPlaceholderTextCore(); + } + return result; } protected override AutomationLandmarkType? GetLandmarkTypeCore() => AutomationProperties.GetLandmarkType(Owner); diff --git a/src/Avalonia.Controls/Automation/Peers/InteropAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/InteropAutomationPeer.cs index 5dfd507e1b..cdbb3286d8 100644 --- a/src/Avalonia.Controls/Automation/Peers/InteropAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/InteropAutomationPeer.cs @@ -29,6 +29,7 @@ internal class InteropAutomationPeer : AutomationPeer protected override AutomationPeer? GetLabeledByCore() => throw new NotImplementedException(); protected override string? GetNameCore() => throw new NotImplementedException(); protected override string? GetHelpTextCore() => throw new NotImplementedException(); + protected override string? GetPlaceholderTextCore() => throw new NotImplementedException(); protected override IReadOnlyList GetOrCreateChildrenCore() => throw new NotImplementedException(); protected override AutomationPeer? GetParentCore() => _parent; protected override bool HasKeyboardFocusCore() => throw new NotImplementedException(); diff --git a/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs index dacec48d36..4f41e088c6 100644 --- a/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs @@ -21,6 +21,8 @@ namespace Avalonia.Automation.Peers return AutomationControlType.Edit; } + protected override string? GetPlaceholderTextCore() => Owner.PlaceholderText; + protected virtual void OwnerPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) { if(e.Property == TextBox.TextProperty) diff --git a/src/Avalonia.Native/AvnAutomationPeer.cs b/src/Avalonia.Native/AvnAutomationPeer.cs index 86e0c5453d..cb418261f7 100644 --- a/src/Avalonia.Native/AvnAutomationPeer.cs +++ b/src/Avalonia.Native/AvnAutomationPeer.cs @@ -46,6 +46,7 @@ namespace Avalonia.Native public IAvnAutomationPeer? LabeledBy => Wrap(_inner.GetLabeledBy()); public IAvnString? Name => _inner.GetName().ToAvnString(); public IAvnString? HelpText => _inner.GetHelpText().ToAvnString(); + public IAvnString? PlaceholderText => _inner.GetPlaceholderText().ToAvnString(); public AvnLandmarkType LandmarkType => (AvnLandmarkType?)_inner.GetLandmarkType() ?? AvnLandmarkType.LandmarkNone; public int HeadingLevel => _inner.GetHeadingLevel(); public IAvnAutomationPeer? Parent => Wrap(_inner.GetParent()); diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl index 7aabeceb72..ea8c1b4694 100644 --- a/src/Avalonia.Native/avn.idl +++ b/src/Avalonia.Native/avn.idl @@ -1328,6 +1328,7 @@ interface IAvnAutomationPeer : IUnknown void ValueProvider_SetValue([const] char* value); IAvnString* GetHelpText(); + IAvnString* GetPlaceholderText(); AvnLandmarkType GetLandmarkType(); int GetHeadingLevel();