Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add switch "NotifyUIAProviderTheText" to control screen Reader to announce the content of RichTextBox #12986

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ internal static partial class LocalAppContextSwitches
internal const string EnableMsoComponentManagerSwitchName = "Switch.System.Windows.Forms.EnableMsoComponentManager";
internal const string TreeNodeCollectionAddRangeRespectsSortOrderSwitchName = "System.Windows.Forms.TreeNodeCollectionAddRangeRespectsSortOrder";
internal const string MoveTreeViewTextLocationOnePixelSwitchName = "System.Windows.Forms.TreeView.MoveTreeViewTextLocationOnePixel";
internal const string NotifyUIAProviderTheTextSwitchName = "System.Windows.Forms.RichTextBox.NotifyUIAProviderTheText";

private static int s_scaleTopLevelFormMinMaxSizeForDpi;
private static int s_anchorLayoutV2;
Expand All @@ -37,8 +38,8 @@ internal static partial class LocalAppContextSwitches
private static int s_noClientNotifications;
private static int s_enableMsoComponentManager;
private static int s_treeNodeCollectionAddRangeRespectsSortOrder;

private static int s_moveTreeViewTextLocationOnePixel;
private static int s_notifyUIAProviderTheText;

private static FrameworkName? s_targetFrameworkName;

Expand Down Expand Up @@ -231,4 +232,13 @@ public static bool MoveTreeViewTextLocationOnePixel
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => GetCachedSwitchValue(MoveTreeViewTextLocationOnePixelSwitchName, ref s_moveTreeViewTextLocationOnePixel);
}

/// <summary>
/// Indicates whether the text of the RichTextBox is sent to the UIA provider.
/// </summary>
public static bool NotifyUIAProviderTheText
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => GetCachedSwitchValue(NotifyUIAProviderTheTextSwitchName, ref s_notifyUIAProviderTheText);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2403,7 +2403,7 @@ protected override void OnGotFocus(EventArgs e)

// Use parent's accessible object because RichTextBox doesn't support UIA Providers, and its
// AccessibilityObject doesn't get created even when assistive tech (e.g. Narrator) is used
if (Parent?.IsAccessibilityObjectCreated == true)
if (AppContextSwitches.NotifyUIAProviderTheText && Parent?.IsAccessibilityObjectCreated == true)
{
Parent.AccessibilityObject.InternalRaiseAutomationNotification(
Automation.AutomationNotificationKind.Other,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Windows.Forms.Primitives;

namespace System;

/// <summary>
/// Scope for enabling / disabling the NotifyUIAProviderTheText Switch.
/// </summary>
public readonly ref struct NotifyUIAProviderTheRichTextContent
{
private readonly AppContextSwitchScope _switchScope;

public NotifyUIAProviderTheRichTextContent(bool enable)
{
// Prevent multiple NotifyUIAProviderTheRichTextContent from running simultaneously. Using Monitor to allow recursion on
// the same thread.
Monitor.Enter(typeof(NotifyUIAProviderTheRichTextContent));
_switchScope = new(WinFormsAppContextSwitchNames.NotifyUIAProviderTheText, GetDefaultValue, enable);
}

public void Dispose()
{
try
{
_switchScope.Dispose();
}
finally
{
Monitor.Exit(typeof(NotifyUIAProviderTheRichTextContent));
}
}

public static bool GetDefaultValue() =>
typeof(LocalAppContextSwitches).TestAccessor()
.CreateDelegate<Func<string, bool>>("GetSwitchDefaultValue")(WinFormsAppContextSwitchNames.NotifyUIAProviderTheText);
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,10 @@ public const string ServicePointManagerCheckCrl
/// </summary>
public const string TreeNodeCollectionAddRangeRespectsSortOrder
= "System.Windows.Forms.TreeNodeCollectionAddRangeRespectsSortOrder";

/// <summary>
/// The switch that controls whether the text of the <see cref="Windows.Forms.RichTextBox" /> is sent to the UIA provider.
/// </summary>
public const string NotifyUIAProviderTheText
= "System.Windows.Forms.RichTextBox.NotifyUIAProviderTheText";
}
Original file line number Diff line number Diff line change
Expand Up @@ -10594,6 +10594,7 @@ public void RichTextBox_CheckRichEditWithVersionCanCreateOldVersions()
[NewAndDefaultData<EventArgs>]
public void RichTextBox_OnGotFocus_RaisesAutomationNotification_WithText(EventArgs eventArgs)
{
using NotifyUIAProviderTheRichTextContent scope = new(enable: true);
Mock<Control> mockParent = new() { CallBase = true };
Mock<Control.ControlAccessibleObject> mockAccessibleObject = new(MockBehavior.Strict, mockParent.Object);
mockAccessibleObject
Expand Down