Skip to content

Commit

Permalink
Implementing HeadingLevel and IsDialog automation properties (#4751)
Browse files Browse the repository at this point in the history
* Felipe coworking session for new UIAutomation property investigation

* adding None as the default result

* adding apicompat changes

* Coworking session with Felipe: adding OS checks for new automation properties

* Fix reference assemblies

* Changing HeadingLevel enum to be in the correct way

* adding isdialog implementation

* changing to isdialog from getisdialog

* improving isdialog implementation

* Update src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Automation/AutomationProperties.cs

Co-authored-by: ThomasGoulet73 <51839772+ThomasGoulet73@users.noreply.github.com>

* Update src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClient/System/Windows/Automation/AutomationElement.cs

Co-authored-by: ThomasGoulet73 <51839772+ThomasGoulet73@users.noreply.github.com>

* Update src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationTypes/System/Windows/Automation/AutomationElementIdentifiers.cs

Co-authored-by: ThomasGoulet73 <51839772+ThomasGoulet73@users.noreply.github.com>

* Update src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Automation/Peers/AutomationPeer.cs

Co-authored-by: ThomasGoulet73 <51839772+ThomasGoulet73@users.noreply.github.com>

* Update src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationTypes/System/Windows/Automation/AutomationElementIdentifiers.cs

Co-authored-by: ThomasGoulet73 <51839772+ThomasGoulet73@users.noreply.github.com>

* Update src/Microsoft.DotNet.Wpf/src/Shared/System/Windows/InterOp/OSVersionHelper.cs

Co-authored-by: ThomasGoulet73 <51839772+ThomasGoulet73@users.noreply.github.com>

* adding headinglevel summary

* removing empty lines and adding description

* Update src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Automation/Peers/AutomationPeer.cs

Co-authored-by: ThomasGoulet73 <51839772+ThomasGoulet73@users.noreply.github.com>

* Update src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Automation/Peers/AutomationPeer.cs

Co-authored-by: Sam Bent <sambent@microsoft.com>

* suggested changes

* removing unecessary comment and adding rs5 for isDialog

* changing enum constant

* Adding window isdialogcore implementation

* overriding headinglevelcore in peers

* editing override of isdialog

* changing values of enum for heading level so it correctly show in accessibility insights

* changing IsDialogCore() to virtual

* adding prefix in automation properties

* changing location of automationheadinglevel.cs to fix api compat errors

* updating presentationcore return types for heading level

* Revert "changing location of automationheadinglevel.cs to fix api compat errors"

This reverts commit 0afb956, as it creates some problems when running wpf

* maintaining the values of the enum as this for further testing

* Update src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Automation/Peers/WindowAutomationPeer.cs

Co-authored-by: Sam Bent <sambent@microsoft.com>

* changing enums to start on 0 and fixing automaticalli added code

* first try to add enum mapping

* removing unreachable code

* moving the headinglevel conversion to automarionpeer.cs

* removing api compat error

* moving headinglevel ids enum to only the places where it is necessary

* reverting baseline files

* removing disclaimer

* removing switches

Co-authored-by: Ryland <41491307+ryalanms@users.noreply.github.com>
Co-authored-by: Felipe da Conceicao Guimaraes <felipeda@microsoft.com>
Co-authored-by: ThomasGoulet73 <51839772+ThomasGoulet73@users.noreply.github.com>
Co-authored-by: Sam Bent <sambent@microsoft.com>
  • Loading branch information
5 people authored Jul 15, 2021
1 parent 85d9507 commit 27a2ce3
Show file tree
Hide file tree
Showing 22 changed files with 545 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@
<Compile Include="System\Windows\UIElement3D.cs" />
<Compile Include="System\Windows\UIPropertyMetadata.cs" />
<Compile Include="System\Windows\Automation\AutomationLiveSetting.cs" />
<Compile Include="System\Windows\Automation\AutomationHeadingLevel.cs" />
<Compile Include="System\Windows\Automation\AutomationProperties.cs" />
<Compile Include="System\Windows\Automation\IsOffscreenBehavior.cs" />
<Compile Include="System\Windows\Automation\Peers\AutomationPeer.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// 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: Enumeration for possible values of AutomationProperties.HeadingLevel
//

namespace System.Windows.Automation
{
/// <summary>
/// Describes the heading level of a control
/// </summary>
public enum AutomationHeadingLevel
{
/// <summary>
/// The element does not have a heading level
/// </summary>
None = 0,

/// <summary>
/// The element has a heading level of 1
/// </summary>
Level1,

/// <summary>
/// The element has a heading level of 2
/// </summary>
Level2,

/// <summary>
/// The element has a heading level of 3
/// </summary>
Level3,

/// <summary>
/// The element has a heading level of 4
/// </summary>
Level4,

/// <summary>
/// The element has a heading level of 5
/// </summary>
Level5,

/// <summary>
/// The element has a heading level of 6
/// </summary>
Level6,

/// <summary>
/// The element has a heading level of 7
/// </summary>
Level7,

/// <summary>
/// The element has a heading level of 8
/// </summary>
Level8,

/// <summary>
/// The element has a heading level of 9
/// </summary>
Level9,
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,75 @@ public static int GetSizeOfSet(DependencyObject element)
}
#endregion

#region HeadingLevel
public static readonly DependencyProperty HeadingLevelProperty =
DependencyProperty.RegisterAttached(
"HeadingLevel",
typeof(AutomationHeadingLevel),
typeof(AutomationProperties),
new UIPropertyMetadata(AutomationHeadingLevel.None));

/// <summary>
/// Helper for setting HeadingLevel property on a DependencyObject.
/// </summary>
public static void SetHeadingLevel(DependencyObject element, AutomationHeadingLevel value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}

element.SetValue(HeadingLevelProperty, value);
}

/// <summary>
/// Helper for reading HeadingLevel property from a DependencyObject.
/// </summary>
public static AutomationHeadingLevel GetHeadingLevel(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}

return ((AutomationHeadingLevel)element.GetValue(HeadingLevelProperty));
}
#endregion

#region isDialog
public static readonly DependencyProperty IsDialogProperty =
DependencyProperty.RegisterAttached(
"IsDialog",
typeof(bool),
typeof(AutomationProperties),
new UIPropertyMetadata(false));

/// <summary>
/// Helper for setting IsDialog property on a DependencyObject.
/// </summary>
public static void SetIsDialog(DependencyObject element, bool value)
{
if(element == null)
{
throw new ArgumentNullException(nameof(element));
}
element.SetValue(IsDialogProperty, value);
}

/// <summary>
/// Helper for reading IsDialog property from a DependencyObject.
/// </summary>
public static bool GetIsDialog(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}

return (bool)element.GetValue(IsDialogProperty);
}
#endregion

#region private implementation
// Validation callback for string properties
private static bool IsNotNull(object value)
Expand All @@ -608,4 +677,3 @@ private static bool IsNotNull(object value)
#endregion
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,11 @@ virtual protected string GetLocalizedControlTypeCore()
///
abstract protected bool IsControlElementCore();

///
virtual protected bool IsDialogCore(){
return false;
}

///
abstract protected AutomationPeer GetLabeledByCore();

Expand Down Expand Up @@ -703,6 +708,13 @@ virtual protected int GetPositionInSetCore()
return AutomationProperties.AutomationPositionInSetDefault;
}

/// <summary>
/// Override this method to provide UIAutomation with the heading level of this element.
/// </summary>
virtual protected AutomationHeadingLevel GetHeadingLevelCore()
{
return AutomationHeadingLevel.None;
}

//
// INTERNAL STUFF - NOT OVERRIDABLE
Expand Down Expand Up @@ -1263,6 +1275,104 @@ public int GetSizeOfSet()
return result;
}

/// <summary>
/// Attempt to get the value for the HeadingLevel property.
/// </summary>
/// <remarks>
/// This public call cannot be attempted if another public call is in progress.
/// </remarks>
/// <returns>
/// The value for the HeadingLevel property.
/// </returns>
public AutomationHeadingLevel GetHeadingLevel()
{
AutomationHeadingLevel result = AutomationHeadingLevel.None;

if (_publicCallInProgress)
throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

try
{
_publicCallInProgress = true;
result = GetHeadingLevelCore();
}
finally
{
_publicCallInProgress = false;
}
return result;
}


private enum HeadingLevel
{
None = 80050,
Level1,
Level2,
Level3,
Level4,
Level5,
Level6,
Level7,
Level8,
Level9,
}
private static HeadingLevel ConvertHeadingLevelToId(AutomationHeadingLevel value){
switch(value)
{
case AutomationHeadingLevel.None:
return HeadingLevel.None;
case AutomationHeadingLevel.Level1:
return HeadingLevel.Level1;
case AutomationHeadingLevel.Level2:
return HeadingLevel.Level2;
case AutomationHeadingLevel.Level3:
return HeadingLevel.Level3;
case AutomationHeadingLevel.Level4:
return HeadingLevel.Level4;
case AutomationHeadingLevel.Level5:
return HeadingLevel.Level5;
case AutomationHeadingLevel.Level6:
return HeadingLevel.Level6;
case AutomationHeadingLevel.Level7:
return HeadingLevel.Level7;
case AutomationHeadingLevel.Level8:
return HeadingLevel.Level8;
case AutomationHeadingLevel.Level9:
return HeadingLevel.Level9;
default:
return HeadingLevel.None;
}
}


/// <summary>
/// Attempt to get the value for the IsDialog property.
/// </summary>
/// <remarks>
/// This public call cannot be attempted if another public call is in progress.
/// </remarks>
/// <returns>
/// The value for the IsDialog property.
/// </returns>
public bool IsDialog()
{
bool result = false;
if(_publicCallInProgress)
throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

try
{
_publicCallInProgress = true;
result = IsDialogCore();
}
finally
{
_publicCallInProgress = false;
}
return result;
}

/// <summary>
/// Attempt to get the value for the PositionInSet property.
/// </summary>
Expand Down Expand Up @@ -1756,7 +1866,7 @@ private void RaisePropertyChangedInternal(IRawElementProviderSimple provider,
#endif
}

// InvalidateLimit – lower bound for raising ChildrenInvalidated StructureChange event
// InvalidateLimit is the lower bound for raising ChildrenInvalidated StructureChange event
internal void UpdateChildrenInternal(int invalidateLimit)
{
List<AutomationPeer> oldChildren = _children;
Expand Down Expand Up @@ -1989,7 +2099,7 @@ internal void UpdateSubtree()

/// <summary>
/// propagate the new value for AncestorsInvalid through the parent chain,
/// use EventSource (wrapper) peers whenever available as it’s the one connected to the tree.
/// use EventSource (wrapper) peers whenever available as it's the one connected to the tree.
/// </summary>
internal void InvalidateAncestorsRecursive()
{
Expand Down Expand Up @@ -2061,6 +2171,10 @@ internal object GetPropertyValue(int propertyId)
if (getProperty != null)
{
result = getProperty(this);
if(AutomationElementIdentifiers.HeadingLevelProperty != null && propertyId == AutomationElementIdentifiers.HeadingLevelProperty.Id)
{
result = ConvertHeadingLevelToId((AutomationHeadingLevel)result);
}
}

return result;
Expand Down Expand Up @@ -2312,6 +2426,14 @@ private static void Initialize()
{
s_propertyInfo[AutomationElementIdentifiers.PositionInSetProperty.Id] = new GetProperty(GetPositionInSet);
}
if (AutomationElementIdentifiers.HeadingLevelProperty != null)
{
s_propertyInfo[AutomationElementIdentifiers.HeadingLevelProperty.Id] = new GetProperty(GetHeadingLevel);
}
if (AutomationElementIdentifiers.IsDialogProperty != null)
{
s_propertyInfo[AutomationElementIdentifiers.IsDialogProperty.Id] = new GetProperty(IsDialog);
}
}

private delegate object WrapObject(AutomationPeer peer, object iface);
Expand Down Expand Up @@ -2363,6 +2485,8 @@ internal PatternInfo(int id, WrapObject wrapObject, PatternInterface patternInte
private static object GetControllerFor(AutomationPeer peer) { return peer.GetControllerForProviderArray(); }
private static object GetSizeOfSet(AutomationPeer peer) { return peer.GetSizeOfSet(); }
private static object GetPositionInSet(AutomationPeer peer) { return peer.GetPositionInSet(); }
private static object GetHeadingLevel(AutomationPeer peer) { return peer.GetHeadingLevel(); }
private static object IsDialog(AutomationPeer peer) { return peer.IsDialog(); }

private static Hashtable s_patternInfo;
private static Hashtable s_propertyInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ override protected bool IsEnabledCore()
return _owner.IsEnabled;
}

/// <summary>
/// <see cref="AutomationPeer.IsDialogCore"/>
/// </summary>
override protected bool IsDialogCore()
{
return AutomationProperties.GetIsDialog(_owner);
}

/// <summary>
/// <see cref="AutomationPeer.IsPasswordCore"/>
/// </summary>
Expand Down Expand Up @@ -287,6 +295,15 @@ override protected int GetSizeOfSetCore()
return AutomationProperties.GetSizeOfSet(_owner);
}

/// <summary>
/// Provides a value for UIAutomation's HeadingLevel property
/// Reads <see cref="AutomationProperties.HeadingLevelProperty"/> and returns the value
/// </summary>
override protected AutomationHeadingLevel GetHeadingLevelCore()
{
return AutomationProperties.GetHeadingLevel(_owner);
}

/// <summary>
/// <see cref="AutomationPeer.GetClickablePointCore"/>
/// </summary>
Expand Down
Loading

0 comments on commit 27a2ce3

Please sign in to comment.