From e82ed6324bc98a6e322b3e6dabe99e11ee5fbfda Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Tue, 28 Jul 2026 22:42:10 -0500 Subject: [PATCH 01/20] Improve accessibility with AutomationProperties support Add AutomationProperties.AutomationId and Name to dialogs and controls for enhanced screen reader and UI automation support. Update ShortcutControl and WordBorder to set automation properties programmatically; implement custom AutomationPeer for WordBorder to support Value pattern. Replace Path.GetTempPath with AutomationProfile.GetTemporaryDirectory for temp files. Minor UI tweaks for accessibility and event handling. These changes improve assistive tech usability and test automation readiness. --- Text-Grab/Controls/AddOrRemoveWindow.xaml | 10 +++++ Text-Grab/Controls/FindAndReplaceWindow.xaml | 10 +++++ Text-Grab/Controls/NotifyIconWindow.xaml | 14 +++++++ Text-Grab/Controls/NotifyIconWindow.xaml.cs | 2 +- .../Controls/PatternMatchModeDialog.xaml | 12 +++++- Text-Grab/Controls/PostGrabActionEditor.xaml | 16 ++++++++ Text-Grab/Controls/QrCodeWindow.xaml | 8 ++++ Text-Grab/Controls/QrCodeWindow.xaml.cs | 2 +- Text-Grab/Controls/RegexEditorDialog.xaml | 8 +++- Text-Grab/Controls/RegexManager.xaml | 11 ++++++ Text-Grab/Controls/ShortcutControl.xaml | 4 +- Text-Grab/Controls/ShortcutControl.xaml.cs | 12 ++++++ .../Controls/TextOnlyTemplateDialog.xaml | 5 +++ Text-Grab/Controls/WordBorder.xaml | 2 + Text-Grab/Controls/WordBorder.xaml.cs | 38 +++++++++++++++++++ 15 files changed, 149 insertions(+), 5 deletions(-) diff --git a/Text-Grab/Controls/AddOrRemoveWindow.xaml b/Text-Grab/Controls/AddOrRemoveWindow.xaml index afb2a4fa..07b1d115 100644 --- a/Text-Grab/Controls/AddOrRemoveWindow.xaml +++ b/Text-Grab/Controls/AddOrRemoveWindow.xaml @@ -7,6 +7,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="Add or remove text on each line" + AutomationProperties.AutomationId="AddRemoveDialog" Width="330" Height="320" Background="{DynamicResource ApplicationBackgroundBrush}" @@ -53,6 +54,7 @@ --> diff --git a/Text-Grab/Controls/NotifyIconWindow.xaml b/Text-Grab/Controls/NotifyIconWindow.xaml index 10ee70fe..d637461a 100644 --- a/Text-Grab/Controls/NotifyIconWindow.xaml +++ b/Text-Grab/Controls/NotifyIconWindow.xaml @@ -8,6 +8,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wpfui="http://schemas.lepo.co/wpfui/2022/xaml" Title="NotifyIconWindow" + AutomationProperties.AutomationId="NotifyIconWindow" Width="0" Height="0" Background="Transparent" @@ -24,6 +25,8 @@ @@ -41,6 +45,7 @@ @@ -49,6 +54,7 @@ @@ -58,6 +64,7 @@ @@ -66,6 +73,7 @@ @@ -74,6 +82,7 @@ @@ -83,6 +92,7 @@ @@ -91,6 +101,7 @@ @@ -99,6 +110,7 @@ @@ -107,6 +119,7 @@ @@ -116,6 +129,7 @@ diff --git a/Text-Grab/Controls/NotifyIconWindow.xaml.cs b/Text-Grab/Controls/NotifyIconWindow.xaml.cs index 035b7613..0579877e 100644 --- a/Text-Grab/Controls/NotifyIconWindow.xaml.cs +++ b/Text-Grab/Controls/NotifyIconWindow.xaml.cs @@ -221,7 +221,7 @@ private void OpenClipboardImageGrabFrame_Click(object sender, RoutedEventArgs e) if (bitmapSource is null) return; - string tempPath = Path.Combine(Path.GetTempPath(), $"TextGrab_Clipboard_{Guid.NewGuid()}.png"); + string tempPath = Path.Combine(AutomationProfile.GetTemporaryDirectory(), $"TextGrab_Clipboard_{Guid.NewGuid()}.png"); using (FileStream fileStream = new(tempPath, FileMode.Create)) { diff --git a/Text-Grab/Controls/PatternMatchModeDialog.xaml b/Text-Grab/Controls/PatternMatchModeDialog.xaml index 5194543e..9530e092 100644 --- a/Text-Grab/Controls/PatternMatchModeDialog.xaml +++ b/Text-Grab/Controls/PatternMatchModeDialog.xaml @@ -6,6 +6,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="Pattern Match Options" + AutomationProperties.AutomationId="PatternMatchDialog" Width="420" Height="450" MinWidth="380" @@ -34,12 +35,14 @@ + AutomationProperties.AutomationId="PatternMatch.ModeOptions" Margin="0,0,0,12"> @@ -82,23 +86,28 @@ + AutomationProperties.AutomationId="PatternMatch.Separator" Text=", " /> - + diff --git a/Text-Grab/Controls/PostGrabActionEditor.xaml b/Text-Grab/Controls/PostGrabActionEditor.xaml index 3c5d0095..214face3 100644 --- a/Text-Grab/Controls/PostGrabActionEditor.xaml +++ b/Text-Grab/Controls/PostGrabActionEditor.xaml @@ -7,6 +7,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="Post-Grab Actions Settings" + AutomationProperties.AutomationId="PostGrabActionsDialog" Width="900" Height="700" Background="{DynamicResource ApplicationBackgroundBrush}" @@ -73,6 +74,7 @@ @@ -106,6 +108,7 @@ VerticalAlignment="Center"> @@ -211,6 +218,7 @@ @@ -297,6 +306,7 @@ @@ -307,6 +317,7 @@ @@ -317,6 +328,7 @@ @@ -331,6 +343,7 @@ @@ -452,12 +465,14 @@ Orientation="Horizontal"> diff --git a/Text-Grab/Controls/QrCodeWindow.xaml b/Text-Grab/Controls/QrCodeWindow.xaml index 5989fb92..c1b991f6 100644 --- a/Text-Grab/Controls/QrCodeWindow.xaml +++ b/Text-Grab/Controls/QrCodeWindow.xaml @@ -7,6 +7,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="Text Grab QR Code" + AutomationProperties.AutomationId="QrCodeDialog" Width="400" Height="600" Closing="FluentWindow_Closing" @@ -33,23 +34,27 @@ Icon="{StaticResource TextGrabIcon}" /> @@ -64,6 +69,7 @@ Text="Error Correction Level" /> @@ -78,6 +84,7 @@ diff --git a/Text-Grab/Controls/QrCodeWindow.xaml.cs b/Text-Grab/Controls/QrCodeWindow.xaml.cs index 085df232..276274cb 100644 --- a/Text-Grab/Controls/QrCodeWindow.xaml.cs +++ b/Text-Grab/Controls/QrCodeWindow.xaml.cs @@ -173,7 +173,7 @@ private void SetQrCodeToText(string textOfCode = "") UiTitleBar.Title = $"QR Code: {TextOfCode.Truncate(30)}"; int trimLength = TextOfCode.Length < maxLength ? TextOfCode.Length : maxLength; qrCodeFileName = $"QR-{TextOfCode[..trimLength].ReplaceReservedCharacters()}"; - tempPath = Path.Combine(Path.GetTempPath(), qrCodeFileName + ".png"); + tempPath = Path.Combine(AutomationProfile.GetTemporaryDirectory(), qrCodeFileName + ".png"); QrBitmap.Save(tempPath, ImageFormat.Png); hBitmap = QrBitmap.GetHbitmap(); diff --git a/Text-Grab/Controls/RegexEditorDialog.xaml b/Text-Grab/Controls/RegexEditorDialog.xaml index a9889dd8..5596a0d6 100644 --- a/Text-Grab/Controls/RegexEditorDialog.xaml +++ b/Text-Grab/Controls/RegexEditorDialog.xaml @@ -6,6 +6,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="Edit Regex Pattern" + AutomationProperties.AutomationId="RegexEditorDialog" Width="600" Height="400" MinWidth="500" @@ -35,12 +36,14 @@ - + diff --git a/Text-Grab/Controls/RegexManager.xaml b/Text-Grab/Controls/RegexManager.xaml index 2d21f3aa..a71fbd3a 100644 --- a/Text-Grab/Controls/RegexManager.xaml +++ b/Text-Grab/Controls/RegexManager.xaml @@ -7,6 +7,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="Patterns Manager" + AutomationProperties.AutomationId="RegexManagerDialog" Width="900" Height="600" MinWidth="700" @@ -41,6 +42,7 @@ Background="{ui:ThemeResource SolidBackgroundFillColorBaseAltBrush}"> diff --git a/Text-Grab/Controls/ShortcutControl.xaml b/Text-Grab/Controls/ShortcutControl.xaml index 348e44ab..b03edfaf 100644 --- a/Text-Grab/Controls/ShortcutControl.xaml +++ b/Text-Grab/Controls/ShortcutControl.xaml @@ -7,12 +7,14 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" x:Name="ShortcutUserControl" + AutomationProperties.Name="{Binding ElementName=ShortcutUserControl, Path=ShortcutName}" Margin="0,0,0,3" HorizontalAlignment="Stretch" d:DataContext="{d:DesignInstance Type=local:ShortcutControl}" d:DesignHeight="60" d:DesignWidth="500" BorderThickness="3" + Loaded="ShortcutControl_Loaded" PreviewKeyDown="ShortcutControl_PreviewKeyDown" PreviewKeyUp="ShortcutControl_PreviewKeyUp" mc:Ignorable="d"> @@ -52,7 +54,7 @@ Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal"> - + new WordBorderAutomationPeer(this); + #endregion Events #region Properties @@ -162,6 +171,35 @@ public string DisplayText set { SetValue(DisplayTextProperty, value); } } + internal sealed class WordBorderAutomationPeer(WordBorder owner) : FrameworkElementAutomationPeer(owner), IValueProvider + { + private WordBorder WordBorder => (WordBorder)Owner; + + public bool IsReadOnly => !WordBorder.IsEnabled; + + public string Value => WordBorder.DisplayText; + + protected override AutomationControlType GetAutomationControlTypeCore() => AutomationControlType.Edit; + + protected override string GetClassNameCore() => nameof(WordBorder); + + protected override string GetNameCore() => WordBorder.DisplayText; + + public override object? GetPattern(PatternInterface patternInterface) => + patternInterface == PatternInterface.Value ? this : base.GetPattern(patternInterface); + + public void SetValue(string value) + { + if (IsReadOnly) + throw new ElementNotEnabledException(); + + WordBorder.DisplayText = value; + } + + internal void RaiseValueChanged(string oldValue, string newValue) => + RaisePropertyChangedEvent(ValuePatternIdentifiers.ValueProperty, oldValue, newValue); + } + public double DisplayLineHeight { get { return (double)GetValue(DisplayLineHeightProperty); } From 7899af7257ecb0874ae8c5cfc134a61504cc304d Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Tue, 28 Jul 2026 22:42:28 -0500 Subject: [PATCH 02/20] Add AutomationIds to settings controls for accessibility Added AutomationProperties.AutomationId to nearly all interactive controls across all settings XAML pages to improve accessibility and enable automated UI testing. In select cases, also set AutomationProperties.Name for enhanced context. Updated file/folder pickers and temp file paths to use automation-aware or profile-based directories. No changes to UI logic or behavior; changes are strictly for accessibility, automation, and testability. --- Text-Grab/Pages/DangerSettings.xaml | 11 ++++++++ Text-Grab/Pages/DangerSettings.xaml.cs | 3 ++- Text-Grab/Pages/EditTextWindowSettings.xaml | 26 +++++++++++-------- Text-Grab/Pages/FullscreenGrabSettings.xaml | 19 +++++++++++--- Text-Grab/Pages/GeneralSettings.xaml | 28 +++++++++++++++++++++ Text-Grab/Pages/GrabFrameSettings.xaml | 16 ++++++++---- Text-Grab/Pages/KeysSettings.xaml | 12 +++++++++ Text-Grab/Pages/LanguageSettings.xaml | 17 ++++++++++++- Text-Grab/Pages/LanguageSettings.xaml.cs | 2 +- Text-Grab/Pages/QuickLookupSettings.xaml | 11 +++++--- Text-Grab/Pages/TesseractSettings.xaml | 9 ++++++- Text-Grab/Pages/VoiceOutputSettings.xaml | 8 ++++++ 12 files changed, 137 insertions(+), 25 deletions(-) diff --git a/Text-Grab/Pages/DangerSettings.xaml b/Text-Grab/Pages/DangerSettings.xaml index e66fa6d8..4ef01d91 100644 --- a/Text-Grab/Pages/DangerSettings.xaml +++ b/Text-Grab/Pages/DangerSettings.xaml @@ -8,6 +8,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="DangerSettings" + AutomationProperties.AutomationId="Settings.DangerPage" d:DesignHeight="450" d:DesignWidth="800" Loaded="Page_Loaded" @@ -21,6 +22,7 @@ @@ -74,6 +80,7 @@ Icon="{ui:SymbolIcon ArrowImport24}"> @@ -121,6 +129,7 @@ Icon="{ui:SymbolIcon BrainCircuit24}"> @@ -134,6 +143,7 @@ Icon="{ui:SymbolIcon ArrowReset24}"> - + - + - + - + - + - + - + - + @@ -135,6 +139,7 @@ Text="Font family:" /> @@ -150,6 +155,7 @@ Text="Font size:" /> - + - + diff --git a/Text-Grab/Pages/FullscreenGrabSettings.xaml b/Text-Grab/Pages/FullscreenGrabSettings.xaml index 37243803..c1963321 100644 --- a/Text-Grab/Pages/FullscreenGrabSettings.xaml +++ b/Text-Grab/Pages/FullscreenGrabSettings.xaml @@ -7,6 +7,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wpfui="http://schemas.lepo.co/wpfui/2022/xaml" Title="FullscreenGrabSettings" + AutomationProperties.AutomationId="Settings.FullscreenGrabPage" d:DesignHeight="450" d:DesignWidth="800" Loaded="Page_Loaded" @@ -24,18 +25,21 @@ Default (Standard) Single Line (S) Table (T) @@ -50,6 +54,7 @@ @@ -59,6 +64,7 @@ @@ -68,6 +74,7 @@ @@ -77,6 +84,7 @@ @@ -91,14 +99,14 @@ Description="Automatically route capture text into the Edit Text Window (same as pressing E)." HeaderText="Send output to Edit Text Window by default" Icon="{wpfui:SymbolIcon WindowEdit20}"> - + - + @@ -108,13 +116,14 @@ HeaderText="Insert captured text into the focused app" Icon="{wpfui:SymbolIcon ClipboardPaste24}"> - + @@ -145,12 +155,14 @@ - + winget install -e --id UB-Mannheim.TesseractOCR diff --git a/Text-Grab/Pages/VoiceOutputSettings.xaml b/Text-Grab/Pages/VoiceOutputSettings.xaml index 02aba3a8..089a51f2 100644 --- a/Text-Grab/Pages/VoiceOutputSettings.xaml +++ b/Text-Grab/Pages/VoiceOutputSettings.xaml @@ -7,6 +7,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="VoiceOutputSettings" + AutomationProperties.AutomationId="Settings.VoiceOutputPage" d:DesignHeight="700" d:DesignWidth="800" Loaded="Page_Loaded" @@ -24,6 +25,7 @@ Icon="{ui:SymbolIcon PersonVoice24}"> @@ -35,6 +37,7 @@ @@ -57,12 +61,14 @@ @@ -91,6 +98,7 @@ Icon="{ui:SymbolIcon Play24}">