From 39ef38227d4ad1d93466a1c813b1a073768aaa05 Mon Sep 17 00:00:00 2001 From: "Leaf Shi (BEYONDSOFT CONSULTING INC)" Date: Thu, 20 Feb 2025 14:05:21 +0800 Subject: [PATCH 1/2] Add switch "NotifyUIAProviderTheText" to control Narrator to announce the content of RichTextBox --- .../LocalAppContextSwitches.cs | 12 +++++++++++- .../Forms/Controls/RichTextBox/RichTextBox.cs | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/System.Windows.Forms.Primitives/src/System/LocalAppContextSwitches/LocalAppContextSwitches.cs b/src/System.Windows.Forms.Primitives/src/System/LocalAppContextSwitches/LocalAppContextSwitches.cs index 5b728b3472a..487be447e64 100644 --- a/src/System.Windows.Forms.Primitives/src/System/LocalAppContextSwitches/LocalAppContextSwitches.cs +++ b/src/System.Windows.Forms.Primitives/src/System/LocalAppContextSwitches/LocalAppContextSwitches.cs @@ -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; @@ -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; @@ -231,4 +232,13 @@ public static bool MoveTreeViewTextLocationOnePixel [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetCachedSwitchValue(MoveTreeViewTextLocationOnePixelSwitchName, ref s_moveTreeViewTextLocationOnePixel); } + + /// + /// Indicates whether the text of the RichTextBox is sent to the UIA provider. + /// + public static bool NotifyUIAProviderTheText + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetCachedSwitchValue(NotifyUIAProviderTheTextSwitchName, ref s_notifyUIAProviderTheText); + } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/RichTextBox/RichTextBox.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/RichTextBox/RichTextBox.cs index a95ff9d90c5..b1c5651943d 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/RichTextBox/RichTextBox.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/RichTextBox/RichTextBox.cs @@ -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, From 09028008cefa5bc0c11d6cee98f2256d8d1a719e Mon Sep 17 00:00:00 2001 From: "Leaf Shi (BEYONDSOFT CONSULTING INC)" Date: Fri, 21 Feb 2025 17:06:23 +0800 Subject: [PATCH 2/2] Add switch to test project --- .../NotifyUIAProviderTheRichTextContent.cs | 38 +++++++++++++++++++ .../WinFormsAppContextSwitchNames.cs | 6 +++ .../System/Windows/Forms/RichTextBoxTests.cs | 1 + 3 files changed, 45 insertions(+) create mode 100644 src/System.Windows.Forms/tests/TestUtilities/NotifyUIAProviderTheRichTextContent.cs diff --git a/src/System.Windows.Forms/tests/TestUtilities/NotifyUIAProviderTheRichTextContent.cs b/src/System.Windows.Forms/tests/TestUtilities/NotifyUIAProviderTheRichTextContent.cs new file mode 100644 index 00000000000..0cfc255518e --- /dev/null +++ b/src/System.Windows.Forms/tests/TestUtilities/NotifyUIAProviderTheRichTextContent.cs @@ -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; + +/// +/// Scope for enabling / disabling the NotifyUIAProviderTheText Switch. +/// +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>("GetSwitchDefaultValue")(WinFormsAppContextSwitchNames.NotifyUIAProviderTheText); +} diff --git a/src/System.Windows.Forms/tests/TestUtilities/WinFormsAppContextSwitchNames.cs b/src/System.Windows.Forms/tests/TestUtilities/WinFormsAppContextSwitchNames.cs index a9458f9b799..c63e848d418 100644 --- a/src/System.Windows.Forms/tests/TestUtilities/WinFormsAppContextSwitchNames.cs +++ b/src/System.Windows.Forms/tests/TestUtilities/WinFormsAppContextSwitchNames.cs @@ -50,4 +50,10 @@ public const string ServicePointManagerCheckCrl /// public const string TreeNodeCollectionAddRangeRespectsSortOrder = "System.Windows.Forms.TreeNodeCollectionAddRangeRespectsSortOrder"; + + /// + /// The switch that controls whether the text of the is sent to the UIA provider. + /// + public const string NotifyUIAProviderTheText + = "System.Windows.Forms.RichTextBox.NotifyUIAProviderTheText"; } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs index cdc387512a2..3e44b36b33f 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs @@ -10594,6 +10594,7 @@ public void RichTextBox_CheckRichEditWithVersionCanCreateOldVersions() [NewAndDefaultData] public void RichTextBox_OnGotFocus_RaisesAutomationNotification_WithText(EventArgs eventArgs) { + using NotifyUIAProviderTheRichTextContent scope = new(enable: true); Mock mockParent = new() { CallBase = true }; Mock mockAccessibleObject = new(MockBehavior.Strict, mockParent.Object); mockAccessibleObject