From 567062837f56a2610fadf1ef6e53f98914eff679 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 13 Nov 2024 21:28:26 -0600 Subject: [PATCH 01/30] update package --- Text-Grab/Text-Grab.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Text-Grab/Text-Grab.csproj b/Text-Grab/Text-Grab.csproj index 757c06f9..710271a8 100644 --- a/Text-Grab/Text-Grab.csproj +++ b/Text-Grab/Text-Grab.csproj @@ -72,7 +72,7 @@ - + From 50baa8717526daddbd07e58f2000a827d8a2224c Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 20 Nov 2024 22:39:13 -0600 Subject: [PATCH 02/30] Update packages --- Tests/Tests.csproj | 2 +- Text-Grab-Package/Text-Grab-Package.wapproj | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index c72a359a..e5b17420 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -9,7 +9,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Text-Grab-Package/Text-Grab-Package.wapproj b/Text-Grab-Package/Text-Grab-Package.wapproj index fa97345d..ccba0d23 100644 --- a/Text-Grab-Package/Text-Grab-Package.wapproj +++ b/Text-Grab-Package/Text-Grab-Package.wapproj @@ -161,5 +161,10 @@ True + + + + + \ No newline at end of file From b882750caddbd93a757c0b7fcf2f7596212aa28e Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 20 Nov 2024 23:07:29 -0600 Subject: [PATCH 03/30] Add initial idea of post capture actions --- Text-Grab/Views/FullscreenGrab.xaml | 25 +++++++++++++++++++ Text-Grab/Views/FullscreenGrab.xaml.cs | 34 ++++++++++++++------------ 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Text-Grab/Views/FullscreenGrab.xaml b/Text-Grab/Views/FullscreenGrab.xaml index 63fa6daa..dc73238d 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml +++ b/Text-Grab/Views/FullscreenGrab.xaml @@ -222,6 +222,31 @@ + + + + + + + + + + + + (); - destinationTextBox = etw.PassedTextControl; - } - - OutputUtilities.HandleTextFromOcr( - TextFromOCR, - isSingleLine, - isTable, - destinationTextBox); - WindowUtilities.CloseAllFullscreenGrabs(); - } - else + if (string.IsNullOrWhiteSpace(TextFromOCR)) { BackgroundBrush.Opacity = .2; TopButtonsStackPanel.Visibility = Visibility.Visible; + return; } + + if (GuidFixMenuItem.IsChecked is true) + TextFromOCR = TextFromOCR.CorrectCommonGuidErrors(); + + if (SendToEditTextToggleButton.IsChecked is true && destinationTextBox is null) + { + EditTextWindow etw = WindowUtilities.OpenOrActivateWindow(); + destinationTextBox = etw.PassedTextControl; + } + + OutputUtilities.HandleTextFromOcr( + TextFromOCR, + isSingleLine, + isTable, + destinationTextBox); + WindowUtilities.CloseAllFullscreenGrabs(); } private void SendToEditTextToggleButton_Click(object sender, RoutedEventArgs e) From 1dba41b6cb542156a0db22f7c69cef32df4abefa Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 20 Nov 2024 23:13:43 -0600 Subject: [PATCH 04/30] Add Bing search as a post action --- Text-Grab/Views/FullscreenGrab.xaml | 3 ++- Text-Grab/Views/FullscreenGrab.xaml.cs | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Text-Grab/Views/FullscreenGrab.xaml b/Text-Grab/Views/FullscreenGrab.xaml index dc73238d..c1e8c3a4 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml +++ b/Text-Grab/Views/FullscreenGrab.xaml @@ -237,7 +237,8 @@ IsCheckable="True" StaysOpenOnClick="True" /> (); destinationTextBox = etw.PassedTextControl; From c4c5fbe71131d46088f924dfd139d441b07edea3 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Thu, 28 Nov 2024 10:20:24 -0500 Subject: [PATCH 05/30] Add ctrl shortcut to ETW bottom bar buttons --- Text-Grab/Utilities/CustomBottomBarUtilities.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Text-Grab/Utilities/CustomBottomBarUtilities.cs b/Text-Grab/Utilities/CustomBottomBarUtilities.cs index 90293561..a070db7b 100644 --- a/Text-Grab/Utilities/CustomBottomBarUtilities.cs +++ b/Text-Grab/Utilities/CustomBottomBarUtilities.cs @@ -71,6 +71,8 @@ public static List GetBottomBarButtons(EditTextWindow editTex List methods = GetMethods(editTextWindow); Dictionary routedCommands = EditTextWindow.GetRoutedCommands(); + int index = 1; + foreach (ButtonInfo buttonItem in GetCustomBottomBarItemsSetting()) { CollapsibleButton button = new() @@ -78,7 +80,7 @@ public static List GetBottomBarButtons(EditTextWindow editTex ButtonText = buttonItem.ButtonText, IsSymbol = buttonItem.IsSymbol, CustomButton = buttonItem, - ToolTip = buttonItem.ButtonText, + ToolTip = $"{buttonItem.ButtonText} (ctrl + {index})", ButtonSymbol = buttonItem.SymbolIcon }; @@ -97,6 +99,7 @@ public static List GetBottomBarButtons(EditTextWindow editTex button.Command = routedCommand; bottomBarButtons.Add(button); + index++; } return bottomBarButtons; From 0f05fe2c3325ddc810f06cd4fba5857bdf413cea Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 4 Sep 2024 22:16:30 -0500 Subject: [PATCH 06/30] try a slightly different Per Monitor DPI tweak from ScreenToGif --- Text-Grab/app.manifest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Text-Grab/app.manifest b/Text-Grab/app.manifest index ebc7645e..68697878 100644 --- a/Text-Grab/app.manifest +++ b/Text-Grab/app.manifest @@ -64,8 +64,8 @@ also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. --> - true - PerMonitorV2 + PerMonitorV2 + true/PM From 0344601a40206b1e2bedd34e16b368f971259c8a Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 4 Sep 2024 22:16:53 -0500 Subject: [PATCH 07/30] Scale down screens to make sure the window is actually intersecting them --- Text-Grab/Utilities/WindowUtilities.cs | 27 ++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/Text-Grab/Utilities/WindowUtilities.cs b/Text-Grab/Utilities/WindowUtilities.cs index 2d2f3016..eefae058 100644 --- a/Text-Grab/Utilities/WindowUtilities.cs +++ b/Text-Grab/Utilities/WindowUtilities.cs @@ -42,14 +42,15 @@ public static void SetWindowPosition(Window passedWindow) if (storedPosition != null && storedPosition.Count == 4) { - bool couldParseAll = false; - couldParseAll = double.TryParse(storedPosition[0], out double parsedX); - couldParseAll = double.TryParse(storedPosition[1], out double parsedY); - couldParseAll = double.TryParse(storedPosition[2], out double parsedWid); - couldParseAll = double.TryParse(storedPosition[3], out double parsedHei); + bool couldParseX = double.TryParse(storedPosition[0], out double parsedX); + bool couldParseY = double.TryParse(storedPosition[1], out double parsedY); + bool couldParseW = double.TryParse(storedPosition[2], out double parsedWid); + bool couldParseH = double.TryParse(storedPosition[3], out double parsedHei); + + bool couldParseAll = couldParseX && couldParseY && couldParseW && couldParseH; + Rect storedSize = new((int)parsedX, (int)parsedY, (int)parsedWid, (int)parsedHei); DisplayInfo[] allScreens = DisplayInfo.AllDisplayInfos; - WindowCollection allWindows = Application.Current.Windows; if (parsedHei < 10 || parsedWid < 10) return; @@ -57,6 +58,8 @@ public static void SetWindowPosition(Window passedWindow) foreach (DisplayInfo screen in allScreens) { Rect screenRect = screen.Bounds; + DpiScale dpi = System.Windows.Media.VisualTreeHelper.GetDpi(passedWindow); + screenRect = screenRect.GetScaledDownByDpi(dpi); if (screenRect.IntersectsWith(storedSize)) isStoredRectWithinScreen = true; } @@ -251,7 +254,7 @@ private static void TryInjectModifierKeyUp(ref List inputs, VirtualKeySho { WindowCollection allWindows = Application.Current.Windows; - foreach (var window in allWindows) + foreach (Window window in allWindows) { if (window is T matchWindow) { @@ -262,7 +265,15 @@ private static void TryInjectModifierKeyUp(ref List inputs, VirtualKeySho // No Window Found, open a new one T newWindow = new(); - newWindow.Show(); + + try + { + newWindow.Show(); + } + catch (Exception ex) + { + MessageBox.Show("An error occurred while trying to open a new window. Please try again.", ex.Message); + } return newWindow; } From ee3d8caa609f9855d7c666cd5e7a7fceb32ef7cb Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Mon, 16 Sep 2024 19:42:37 -0500 Subject: [PATCH 08/30] update packages --- Tests/Tests.csproj | 4 ++-- Text-Grab/Text-Grab.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 792d45d7..a982867c 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -9,9 +9,9 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Text-Grab/Text-Grab.csproj b/Text-Grab/Text-Grab.csproj index 0af29a12..258c20d8 100644 --- a/Text-Grab/Text-Grab.csproj +++ b/Text-Grab/Text-Grab.csproj @@ -70,7 +70,7 @@ - + From 8ac85ca60bdb4c4a76086b9c2928821a3b008231 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 18 Sep 2024 22:07:06 -0500 Subject: [PATCH 09/30] Update code formatting --- .editorconfig | 101 ++++++++++++++++++++++++++++--------- Tests/FilesIoTests.cs | 9 +--- Tests/OcrTests.cs | 4 +- Tests/QrCodeTests.cs | 2 +- Tests/StringMethodTests.cs | 3 +- 5 files changed, 82 insertions(+), 37 deletions(-) diff --git a/.editorconfig b/.editorconfig index e98c87da..41e25e9d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,36 @@ -# Remove the line below if you want to inherit .editorconfig settings from higher directories +# EditorConfig is awesome: https://EditorConfig.org + +# Remove the line below if you want to inherit '.editorconfig' settings from higher directories root = true +[*] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion + +[*.{yml,yaml,appxmanifest,manifest,config}] +indent_style = space +indent_size = 2 + +# Files that require CRLF line endings +[*.{bat,cmd,wapproj}] +end_of_line = crlf +indent_style = space +indent_size = 4 + +[*.{sln,props}] +indent_style = tab +indent_size = 8 + # C# files [*.cs] @@ -13,7 +43,6 @@ tab_width = 4 # New line preferences end_of_line = crlf -insert_final_newline = false #### .NET Coding Conventions #### @@ -82,14 +111,14 @@ csharp_style_var_for_built_in_types = false:suggestion csharp_style_var_when_type_is_apparent = false:suggestion # Expression-bodied members -csharp_style_expression_bodied_accessors = true -csharp_style_expression_bodied_constructors = false -csharp_style_expression_bodied_indexers = true -csharp_style_expression_bodied_lambdas = true -csharp_style_expression_bodied_local_functions = false -csharp_style_expression_bodied_methods = false -csharp_style_expression_bodied_operators = false -csharp_style_expression_bodied_properties = true +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent # Pattern matching preferences csharp_style_pattern_matching_over_as_with_null_check = true @@ -109,12 +138,12 @@ csharp_style_prefer_readonly_struct = true csharp_style_prefer_readonly_struct_member = true # Code-block preferences -csharp_prefer_braces = when_multiline -csharp_prefer_simple_using_statement = true -csharp_style_namespace_declarations = file_scoped -csharp_style_prefer_method_group_conversion = true -csharp_style_prefer_primary_constructors = true -csharp_style_prefer_top_level_statements = true +csharp_prefer_braces = when_multiline:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_namespace_declarations = file_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_top_level_statements = true:silent # Expression-level preferences csharp_prefer_simple_default_expression = true @@ -132,7 +161,7 @@ csharp_style_unused_value_assignment_preference = discard_variable csharp_style_unused_value_expression_statement_preference = discard_variable # 'using' directive preferences -csharp_using_directive_placement = outside_namespace +csharp_using_directive_placement = outside_namespace:silent # New line preferences csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true @@ -208,24 +237,46 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case dotnet_naming_symbols.interface.applicable_kinds = interface dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = +dotnet_naming_symbols.interface.required_modifiers = dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = +dotnet_naming_symbols.types.required_modifiers = dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.non_field_members.required_modifiers = # Naming styles -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_diagnostic.CA1069.severity = none # CA1069: Enums values should not be duplicated +dotnet_diagnostic.CA2211.severity = none +dotnet_diagnostic.CA1806.severity = none +dotnet_diagnostic.CA1016.severity = none +dotnet_diagnostic.CA1806.severity = none +dotnet_diagnostic.CA1822.severity = none +dotnet_diagnostic.CA1845.severity = none +dotnet_diagnostic.CA1513.severity = none +dotnet_diagnostic.CA1859.severity = none +dotnet_diagnostic.CA1854.severity = none +dotnet_diagnostic.NU1503.severity = none +dotnet_diagnostic.CA1869.severity = none +dotnet_diagnostic.CA1067.severity = none +dotnet_diagnostic.IDE0011.severity = none +dotnet_diagnostic.IDE0060.severity = none +dotnet_diagnostic.IDE0059.severity = none +dotnet_diagnostic.IDE0055.severity = none +dotnet_diagnostic.CA2263.severity = none +dotnet_diagnostic.IDE0051.severity = none +dotnet_diagnostic.IDE0052.severity = none +dotnet_diagnostic.CS1591.severity = none \ No newline at end of file diff --git a/Tests/FilesIoTests.cs b/Tests/FilesIoTests.cs index 50deccd7..1e0b7903 100644 --- a/Tests/FilesIoTests.cs +++ b/Tests/FilesIoTests.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; using Text_Grab; using Text_Grab.Utilities; @@ -16,7 +11,7 @@ public class FilesIoTests [WpfFact] public async Task CanSaveImagesWithHistory() { - Bitmap fontSampleBitmap = new Bitmap(FileUtilities.GetPathToLocalFile(fontSamplePath)); + Bitmap fontSampleBitmap = new(FileUtilities.GetPathToLocalFile(fontSamplePath)); bool couldSave = await FileUtilities.SaveImageFile(fontSampleBitmap, "newTest.png", FileStorageKind.WithHistory); diff --git a/Tests/OcrTests.cs b/Tests/OcrTests.cs index 20b626b4..141ef18a 100644 --- a/Tests/OcrTests.cs +++ b/Tests/OcrTests.cs @@ -256,8 +256,8 @@ public async Task GetTessLanguages() Assert.Contains(tag, actualStrings); } } - - [WpfFact(Skip ="fails GitHub actions")] + + [WpfFact(Skip = "fails GitHub actions")] public async Task GetTesseractStrongLanguages() { List expectedList = new() diff --git a/Tests/QrCodeTests.cs b/Tests/QrCodeTests.cs index f89c9543..fe6f78e0 100644 --- a/Tests/QrCodeTests.cs +++ b/Tests/QrCodeTests.cs @@ -9,7 +9,7 @@ public class QrCodeTests public void generateSvgImage() { string testString = "This is only a test"; - var svg = BarcodeUtilities.GetSvgQrCodeForText(testString, ErrorCorrectionLevel.L); + ZXing.Rendering.SvgRenderer.SvgImage svg = BarcodeUtilities.GetSvgQrCodeForText(testString, ErrorCorrectionLevel.L); Assert.NotNull(svg); } diff --git a/Tests/StringMethodTests.cs b/Tests/StringMethodTests.cs index 3ce59f6d..cc4e2b55 100644 --- a/Tests/StringMethodTests.cs +++ b/Tests/StringMethodTests.cs @@ -1,6 +1,5 @@ using System.Text; using Text_Grab; -using System.Linq; using Text_Grab.Utilities; namespace Tests; @@ -95,7 +94,7 @@ public void TryFixToLetters_ReplacesDigitsWithLetters_AsExpected(string input, s } [Theory] - [InlineData("","")] + [InlineData("", "")] [InlineData("he11o there", "hello there")] [InlineData("my number is l23456789o", "my number is 1234567890")] public void TryFixNumOrLetters(string input, string expected) From 2bd5c455074344f2a7fadd621ffa734e3370a778 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 18 Sep 2024 22:28:49 -0500 Subject: [PATCH 10/30] Code style --- Text-Grab/App.xaml.cs | 4 +- Text-Grab/Controls/AddOrRemoveWindow.xaml.cs | 1 - Text-Grab/Controls/CollapsibleButton.xaml.cs | 1 - .../Controls/FindAndReplaceWindow.xaml.cs | 7 +- Text-Grab/Controls/PreviousGrabWindow.xaml.cs | 2 +- Text-Grab/Controls/QrCodeWindow.xaml.cs | 297 +++++++++--------- Text-Grab/Controls/ShortcutControl.xaml.cs | 7 +- Text-Grab/Controls/WordBorder.xaml.cs | 12 +- Text-Grab/Controls/ZoomBorder.cs | 4 +- Text-Grab/DesktopNotificationManagerCompat.cs | 18 +- Text-Grab/Enums.cs | 2 +- Text-Grab/Extensions/ControlExtensions.cs | 4 +- Text-Grab/Extensions/ImageExtensions.cs | 10 +- Text-Grab/Extensions/LanguageExtensions.cs | 2 +- .../Extensions/SettingsStorageExtensions.cs | 6 +- Text-Grab/Extensions/ShapeExtensions.cs | 6 +- Text-Grab/Models/DragDataObject.cs | 6 +- Text-Grab/Models/OcrOutput.cs | 1 - Text-Grab/Models/ResultTable.cs | 16 +- Text-Grab/Models/ShortcutKeySet.cs | 4 +- Text-Grab/NativeMethods.cs | 2 +- Text-Grab/OSInterop.cs | 6 +- Text-Grab/Pages/GeneralSettings.xaml.cs | 4 +- Text-Grab/Pages/KeysSettings.xaml.cs | 2 +- Text-Grab/Services/HistoryService.cs | 4 +- Text-Grab/Services/SettingsService.cs | 2 +- Text-Grab/TextGrabNotificationActivator.cs | 35 +-- Text-Grab/UndoRedoOperations/AddWordBorder.cs | 3 +- Text-Grab/UndoRedoOperations/ChangeWord.cs | 9 +- .../UndoRedoOperations/RemoveWordBorder.cs | 3 +- Text-Grab/UndoRedoOperations/UndoRedo.cs | 21 +- Text-Grab/Utilities/BarcodeUtilities.cs | 7 +- Text-Grab/Utilities/ClipboardUtilities.cs | 4 +- Text-Grab/Utilities/CursorClipper.cs | 8 +- .../Utilities/CustomBottomBarUtilities.cs | 2 - Text-Grab/Utilities/FileUtilities.cs | 15 +- Text-Grab/Utilities/HotKeyManager.cs | 12 +- Text-Grab/Utilities/IoUtilities.cs | 1 - Text-Grab/Utilities/LanguageUtilities.cs | 1 - Text-Grab/Utilities/NotificationUtilities.cs | 6 +- Text-Grab/Utilities/NotifyIconUtilities.cs | 2 +- Text-Grab/Utilities/OcrUtilities.cs | 36 +-- Text-Grab/Utilities/OutputUtilities.cs | 1 - Text-Grab/Utilities/RegistryMonitor.cs | 93 ++++-- Text-Grab/Utilities/ShortcutKeysUtilities.cs | 3 +- Text-Grab/Utilities/Singleton.cs | 2 +- Text-Grab/Utilities/StreamWrapper.cs | 18 +- Text-Grab/Utilities/StringMethods.cs | 6 +- Text-Grab/Utilities/SystemThemeUtility.cs | 9 +- Text-Grab/Utilities/TesseractHelper.cs | 6 +- Text-Grab/Utilities/WindowResizer.cs | 59 ++-- Text-Grab/Utilities/WindowUtilities.cs | 6 +- Text-Grab/Views/EditTextWindow.xaml.cs | 16 +- Text-Grab/Views/FirstRunWindow.xaml.cs | 2 +- Text-Grab/Views/FullscreenGrab.xaml.cs | 6 +- Text-Grab/Views/GrabFrame.xaml.cs | 5 +- Text-Grab/Views/QuickSimpleLookup.xaml.cs | 24 +- Text-Grab/WPFExtensionMethods.cs | 11 +- 58 files changed, 424 insertions(+), 438 deletions(-) diff --git a/Text-Grab/App.xaml.cs b/Text-Grab/App.xaml.cs index 35015e3e..662c6703 100644 --- a/Text-Grab/App.xaml.cs +++ b/Text-Grab/App.xaml.cs @@ -27,7 +27,7 @@ public partial class App : System.Windows.Application { #region Fields - readonly static Settings _defaultSettings = AppUtilities.TextGrabSettings; + private static readonly Settings _defaultSettings = AppUtilities.TextGrabSettings; #endregion Fields @@ -232,7 +232,7 @@ private void appExit(object sender, ExitEventArgs e) Singleton.Instance.WriteHistory(); } - async void appStartup(object sender, StartupEventArgs e) + private async void appStartup(object sender, StartupEventArgs e) { NumberOfRunningInstances = Process.GetProcessesByName("Text-Grab").Length; Current.DispatcherUnhandledException += CurrentDispatcherUnhandledException; diff --git a/Text-Grab/Controls/AddOrRemoveWindow.xaml.cs b/Text-Grab/Controls/AddOrRemoveWindow.xaml.cs index fa691054..5b086626 100644 --- a/Text-Grab/Controls/AddOrRemoveWindow.xaml.cs +++ b/Text-Grab/Controls/AddOrRemoveWindow.xaml.cs @@ -2,7 +2,6 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; -using Windows.Graphics.Printing.Workflow; namespace Text_Grab.Controls; diff --git a/Text-Grab/Controls/CollapsibleButton.xaml.cs b/Text-Grab/Controls/CollapsibleButton.xaml.cs index 5620c770..28c2c588 100644 --- a/Text-Grab/Controls/CollapsibleButton.xaml.cs +++ b/Text-Grab/Controls/CollapsibleButton.xaml.cs @@ -1,7 +1,6 @@ using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows; -using System.Windows.Controls; using Text_Grab.Models; using Wpf.Ui.Controls; diff --git a/Text-Grab/Controls/FindAndReplaceWindow.xaml.cs b/Text-Grab/Controls/FindAndReplaceWindow.xaml.cs index afa63844..9b570d1b 100644 --- a/Text-Grab/Controls/FindAndReplaceWindow.xaml.cs +++ b/Text-Grab/Controls/FindAndReplaceWindow.xaml.cs @@ -1,7 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -28,7 +27,7 @@ public partial class FindAndReplaceWindow : FluentWindow public static RoutedCommand ReplaceAllCmd = new(); public static RoutedCommand ReplaceOneCmd = new(); public static RoutedCommand TextSearchCmd = new(); - DispatcherTimer ChangeFindTextTimer = new(); + private DispatcherTimer ChangeFindTextTimer = new(); private MatchCollection? Matches; private string stringFromWindow = ""; private EditTextWindow? textEditWindow; @@ -171,11 +170,11 @@ private void CopyMatchesCmd_Executed(object sender, ExecutedRoutedEventArgs e) StringBuilder stringBuilder = new(); - var selection = ResultsListView.SelectedItems; + IList selection = ResultsListView.SelectedItems; if (selection.Count < 2) selection = ResultsListView.Items; - foreach (var item in selection) + foreach (object? item in selection) if (item is FindResult findResult) stringBuilder.AppendLine(findResult.Text); diff --git a/Text-Grab/Controls/PreviousGrabWindow.xaml.cs b/Text-Grab/Controls/PreviousGrabWindow.xaml.cs index 33550ef9..063fb0f2 100644 --- a/Text-Grab/Controls/PreviousGrabWindow.xaml.cs +++ b/Text-Grab/Controls/PreviousGrabWindow.xaml.cs @@ -20,7 +20,7 @@ public PreviousGrabWindow(Rect rect) Left = rect.Left - borderThickness; Top = rect.Top - borderThickness; - DispatcherTimer timer = new DispatcherTimer(); + DispatcherTimer timer = new(); timer.Interval = TimeSpan.FromMilliseconds(500); timer.Tick += (s, e) => { timer.Stop(); Close(); }; timer.Start(); diff --git a/Text-Grab/Controls/QrCodeWindow.xaml.cs b/Text-Grab/Controls/QrCodeWindow.xaml.cs index d80bccc9..59d96342 100644 --- a/Text-Grab/Controls/QrCodeWindow.xaml.cs +++ b/Text-Grab/Controls/QrCodeWindow.xaml.cs @@ -14,190 +14,189 @@ using static ZXing.Rendering.SvgRenderer; // using static System.Net.Mime.MediaTypeNames; -namespace Text_Grab.Controls +namespace Text_Grab.Controls; + +/// +/// Interaction logic for QrCodeWindow.xaml +/// +public partial class QrCodeWindow : FluentWindow { - /// - /// Interaction logic for QrCodeWindow.xaml - /// - public partial class QrCodeWindow : FluentWindow - { - #region Fields + #region Fields - private IntPtr hBitmap; - private string qrCodeFileName = string.Empty; - private string tempPath = string.Empty; - private DispatcherTimer textDebounceTimer = new(); - private ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L; - #endregion Fields + private IntPtr hBitmap; + private string qrCodeFileName = string.Empty; + private string tempPath = string.Empty; + private DispatcherTimer textDebounceTimer = new(); + private ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L; + #endregion Fields - #region Constructors + #region Constructors - public QrCodeWindow(string textOfCode) - { - InitializeComponent(); + public QrCodeWindow(string textOfCode) + { + InitializeComponent(); - textOfCode = textOfCode.MakeStringSingleLine(); - QrCodeTextBox.Text = textOfCode; - textDebounceTimer.Interval = new(0, 0, 0, 0, 200); - textDebounceTimer.Tick += TextDebounceTimer_Tick; - SetQrCodeToText(textOfCode); - } + textOfCode = textOfCode.MakeStringSingleLine(); + QrCodeTextBox.Text = textOfCode; + textDebounceTimer.Interval = new(0, 0, 0, 0, 200); + textDebounceTimer.Tick += TextDebounceTimer_Tick; + SetQrCodeToText(textOfCode); + } - private void TextDebounceTimer_Tick(object? sender, EventArgs e) - { - SetQrCodeToText(TextOfCode); - } - #endregion Constructors + private void TextDebounceTimer_Tick(object? sender, EventArgs e) + { + SetQrCodeToText(TextOfCode); + } + #endregion Constructors - #region Properties + #region Properties - public Bitmap? QrBitmap { get; set; } - public string TextOfCode { get; set; } = string.Empty; + public Bitmap? QrBitmap { get; set; } + public string TextOfCode { get; set; } = string.Empty; - #endregion Properties + #endregion Properties - #region Methods + #region Methods - private void CodeImage_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) + private void CodeImage_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + if (QrBitmap is null) + return; + + try { - if (QrBitmap is null) - return; - - try - { - // DoDragDrop with file thumbnail as drag image - var dataObject = DragDataObject.FromFile(tempPath); - dataObject.SetDragImage(hBitmap, QrBitmap.Width, QrBitmap.Height); - DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Copy); - } - catch - { - // DoDragDrop without drag image - IDataObject dataObject = new DataObject(DataFormats.FileDrop, new[] { tempPath }); - DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Copy); - } + // DoDragDrop with file thumbnail as drag image + System.Runtime.InteropServices.ComTypes.IDataObject dataObject = DragDataObject.FromFile(tempPath); + dataObject.SetDragImage(hBitmap, QrBitmap.Width, QrBitmap.Height); + DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Copy); } - - private void CopyButton_Click(object sender, RoutedEventArgs e) + catch { - Clipboard.SetData(DataFormats.Bitmap, QrBitmap); + // DoDragDrop without drag image + IDataObject dataObject = new DataObject(DataFormats.FileDrop, new[] { tempPath }); + DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Copy); } + } + + private void CopyButton_Click(object sender, RoutedEventArgs e) + { + Clipboard.SetData(DataFormats.Bitmap, QrBitmap); + } + + private void ErrorCorrectionComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) + { + if (sender is not ComboBox comboBox + || comboBox.SelectedItem is not ComboBoxItem selectedItem + || selectedItem.Tag is not string tagLevel) + return; - private void ErrorCorrectionComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) + errorCorrectionLevel = tagLevel switch { - if (sender is not ComboBox comboBox - || comboBox.SelectedItem is not ComboBoxItem selectedItem - || selectedItem.Tag is not string tagLevel) - return; - - errorCorrectionLevel = tagLevel switch - { - "L" => ErrorCorrectionLevel.L, - "M" => ErrorCorrectionLevel.M, - "Q" => ErrorCorrectionLevel.Q, - "H" => ErrorCorrectionLevel.H, - _ => ErrorCorrectionLevel.L - }; - - SetQrCodeToText(); - } + "L" => ErrorCorrectionLevel.L, + "M" => ErrorCorrectionLevel.M, + "Q" => ErrorCorrectionLevel.Q, + "H" => ErrorCorrectionLevel.H, + _ => ErrorCorrectionLevel.L + }; + + SetQrCodeToText(); + } - private void FluentWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + private void FluentWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + NativeMethods.DeleteObject(hBitmap); + if (File.Exists(tempPath)) { - NativeMethods.DeleteObject(hBitmap); - if (File.Exists(tempPath)) - { - try { File.Delete(tempPath); } - catch { } - } + try { File.Delete(tempPath); } + catch { } } + } - private void QrCodeTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) - { - if (!IsLoaded) - return; + private void QrCodeTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) + { + if (!IsLoaded) + return; - textDebounceTimer.Stop(); - // if (sender is not TextBox senderBox || senderBox.Text is not string textboxString) - // return; + textDebounceTimer.Stop(); + // if (sender is not TextBox senderBox || senderBox.Text is not string textboxString) + // return; - TextOfCode = QrCodeTextBox.Text; - textDebounceTimer.Start(); - } + TextOfCode = QrCodeTextBox.Text; + textDebounceTimer.Start(); + } + + private void SaveButton_Click(object sender, RoutedEventArgs e) + { + if (QrBitmap is null) + return; - private void SaveButton_Click(object sender, RoutedEventArgs e) + SaveFileDialog dialog = new() { - if (QrBitmap is null) - return; + FileName = qrCodeFileName + ".png", + Filter = "Image | *.png", + InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), + RestoreDirectory = true, + }; - SaveFileDialog dialog = new() - { - FileName = qrCodeFileName + ".png", - Filter = "Image | *.png", - InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), - RestoreDirectory = true, - }; + if (dialog.ShowDialog() is not true) + return; - if (dialog.ShowDialog() is not true) - return; + QrBitmap.Save(dialog.FileName); + } - QrBitmap.Save(dialog.FileName); - } + private void SetQrCodeToText(string textOfCode = "") + { + if (!string.IsNullOrEmpty(textOfCode)) + TextOfCode = textOfCode; + + if (string.IsNullOrEmpty(TextOfCode)) + return; - private void SetQrCodeToText(string textOfCode = "") + bool showError = false; + int maxCharLength = 2953; + if (TextOfCode.Length > maxCharLength) { - if (!string.IsNullOrEmpty(textOfCode)) - TextOfCode = textOfCode; - - if (string.IsNullOrEmpty(TextOfCode)) - return; - - bool showError = false; - int maxCharLength = 2953; - if (TextOfCode.Length > maxCharLength) - { - TextOfCode = TextOfCode.Substring(0, maxCharLength); - showError = true; - } - QrBitmap = BarcodeUtilities.GetQrCodeForText(TextOfCode, errorCorrectionLevel); - CodeImage.ToolTip = textOfCode; - CodeImage.Source = ImageMethods.BitmapToImageSource(QrBitmap); - - if (showError) - LengthErrorTextBlock.Visibility = Visibility.Visible; - - int maxLength = 50; - UiTitleBar.Title = $"QR Code: {TextOfCode.Truncate(30)}"; - int trimLength = TextOfCode.Length < maxLength ? TextOfCode.Length : maxLength; - qrCodeFileName = $"QR-{TextOfCode.Substring(0, trimLength).ReplaceReservedCharacters()}"; - tempPath = Path.Combine(Path.GetTempPath(), qrCodeFileName + ".png"); - - QrBitmap.Save(tempPath, ImageFormat.Png); - hBitmap = QrBitmap.GetHbitmap(); + TextOfCode = TextOfCode[..maxCharLength]; + showError = true; } - private async void SvgButton_Click(object sender, RoutedEventArgs e) - { - if (QrBitmap is null) - return; + QrBitmap = BarcodeUtilities.GetQrCodeForText(TextOfCode, errorCorrectionLevel); + CodeImage.ToolTip = textOfCode; + CodeImage.Source = ImageMethods.BitmapToImageSource(QrBitmap); + + if (showError) + LengthErrorTextBlock.Visibility = Visibility.Visible; + + int maxLength = 50; + 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"); - SaveFileDialog dialog = new() - { - FileName = qrCodeFileName + ".svg", - Filter = "SVG | *.svg", - InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), - RestoreDirectory = true, - }; + QrBitmap.Save(tempPath, ImageFormat.Png); + hBitmap = QrBitmap.GetHbitmap(); + } + private async void SvgButton_Click(object sender, RoutedEventArgs e) + { + if (QrBitmap is null) + return; - if (dialog.ShowDialog() is not true) - return; + SaveFileDialog dialog = new() + { + FileName = qrCodeFileName + ".svg", + Filter = "SVG | *.svg", + InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), + RestoreDirectory = true, + }; - SvgImage svgImage = BarcodeUtilities.GetSvgQrCodeForText(TextOfCode, errorCorrectionLevel); + if (dialog.ShowDialog() is not true) + return; - if (string.IsNullOrWhiteSpace(svgImage.Content)) - return; + SvgImage svgImage = BarcodeUtilities.GetSvgQrCodeForText(TextOfCode, errorCorrectionLevel); - await FileUtilities.SaveTextFile(svgImage.Content, dialog.FileName, FileStorageKind.Absolute); - } - #endregion Methods + if (string.IsNullOrWhiteSpace(svgImage.Content)) + return; + + await FileUtilities.SaveTextFile(svgImage.Content, dialog.FileName, FileStorageKind.Absolute); } + #endregion Methods } diff --git a/Text-Grab/Controls/ShortcutControl.xaml.cs b/Text-Grab/Controls/ShortcutControl.xaml.cs index 53904cb9..9eebb6f8 100644 --- a/Text-Grab/Controls/ShortcutControl.xaml.cs +++ b/Text-Grab/Controls/ShortcutControl.xaml.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Windows; using System.Windows.Controls; @@ -40,10 +39,8 @@ public string ShortcutName public static readonly DependencyProperty ShortcutNameProperty = DependencyProperty.Register("ShortcutName", typeof(string), typeof(ShortcutControl), new PropertyMetadata("shortcutName")); - - bool isRecording = false; - - string previousSequence = string.Empty; + private bool isRecording = false; + private string previousSequence = string.Empty; public bool HasModifier { get; set; } = false; public bool HasLetter { get; set; } = false; diff --git a/Text-Grab/Controls/WordBorder.xaml.cs b/Text-Grab/Controls/WordBorder.xaml.cs index 1d25761f..19fc45f4 100644 --- a/Text-Grab/Controls/WordBorder.xaml.cs +++ b/Text-Grab/Controls/WordBorder.xaml.cs @@ -7,10 +7,8 @@ using System.Windows.Media; using System.Windows.Threading; using Text_Grab.Models; -using Text_Grab.Properties; using Text_Grab.Utilities; using Text_Grab.Views; -using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window; namespace Text_Grab.Controls; @@ -28,10 +26,10 @@ public partial class WordBorder : UserControl, INotifyPropertyChanged public static RoutedCommand MergeWordsCommand = new(); private int contextMenuBaseSize; - private SolidColorBrush contrastingForeground = new SolidColorBrush(Colors.White); + private SolidColorBrush contrastingForeground = new(Colors.White); private DispatcherTimer debounceTimer = new(); private double left = 0; - private SolidColorBrush matchingBackground = new SolidColorBrush(Colors.Black); + private SolidColorBrush matchingBackground = new(Colors.Black); private double top = 0; #endregion Fields @@ -201,7 +199,7 @@ public void SetAsBarcode() EditWordTextBox.Height = this.Height - 2; EditWordTextBox.FontSize = 14; - if (Uri.TryCreate(Word, UriKind.Absolute, out var uri)) + if (Uri.TryCreate(Word, UriKind.Absolute, out Uri? uri)) EditWordTextBox.Background = new SolidColorBrush(Colors.Blue); } @@ -248,7 +246,7 @@ private void EditWordTextBox_ContextMenuOpening(object sender, ContextMenuEventA textBoxContextMenu.Items.RemoveAt(contextMenuBaseSize); } - if (Uri.TryCreate(Word, UriKind.Absolute, out var uri)) + if (Uri.TryCreate(Word, UriKind.Absolute, out Uri? uri)) { string headerText = $"Try to go to: {Word}"; int maxLength = 36; @@ -310,7 +308,7 @@ private void SizeHandle_MouseDown(object sender, MouseButtonEventArgs e) { if (sender is not FrameworkElement fe) return; - Enum.TryParse(typeof(Side), fe.Tag.ToString(), out var side); + Enum.TryParse(typeof(Side), fe.Tag.ToString(), out object? side); if (side is not Side sideEnum) return; diff --git a/Text-Grab/Controls/ZoomBorder.cs b/Text-Grab/Controls/ZoomBorder.cs index a3a30fa2..4f55be2d 100644 --- a/Text-Grab/Controls/ZoomBorder.cs +++ b/Text-Grab/Controls/ZoomBorder.cs @@ -22,7 +22,7 @@ private TranslateTransform GetTranslateTransform(UIElement element) => (TranslateTransform)((TransformGroup)element.RenderTransform) .Children.First(tr => tr is TranslateTransform); - private ScaleTransform GetScaleTransform(UIElement element) => + private ScaleTransform GetScaleTransform(UIElement element) => (ScaleTransform)((TransformGroup)element.RenderTransform) .Children.First(tr => tr is ScaleTransform); @@ -132,7 +132,7 @@ private void Child_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) Cursor = Cursors.Arrow; } - void Child_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) + private void Child_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { } diff --git a/Text-Grab/DesktopNotificationManagerCompat.cs b/Text-Grab/DesktopNotificationManagerCompat.cs index 302c1b0f..e5c1a565 100644 --- a/Text-Grab/DesktopNotificationManagerCompat.cs +++ b/Text-Grab/DesktopNotificationManagerCompat.cs @@ -100,7 +100,7 @@ private static void RegisterComServer(String exePath) { // We register the EXE to start up when the notification is activated string regString = String.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}", typeof(T).GUID); - using (var key = Registry.CurrentUser.CreateSubKey(regString)) + using (RegistryKey key = Registry.CurrentUser.CreateSubKey(regString)) { // Include a flag so we know this was a toast activation and should wait for COM to process // We also wrap EXE path in quotes for extra security @@ -111,7 +111,7 @@ private static void RegisterComServer(String exePath) { // For elevated apps, we need to ensure they'll activate in existing running process by adding // some values in local machine - using (var key = Registry.LocalMachine.CreateSubKey(regString)) + using (RegistryKey key = Registry.LocalMachine.CreateSubKey(regString)) { // Same as above, except also including AppId to link to our AppId entry below key.SetValue("LocalServer32", '"' + exePath + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG); @@ -120,7 +120,7 @@ private static void RegisterComServer(String exePath) // This tells COM to match any client, so Action Center will activate our elevated process. // More info: https://docs.microsoft.com/windows/win32/com/runas - using (var key = Registry.LocalMachine.CreateSubKey(String.Format("SOFTWARE\\Classes\\AppID\\{{{0}}}", typeof(T).GUID))) + using (RegistryKey key = Registry.LocalMachine.CreateSubKey(String.Format("SOFTWARE\\Classes\\AppID\\{{{0}}}", typeof(T).GUID))) { key.SetValue("RunAs", "Interactive User"); } @@ -135,7 +135,7 @@ public static void RegisterActivator() where T : NotificationActivator, new() { // Big thanks to FrecherxDachs for figuring out the following code which works in .NET Core 3: https://github.com/FrecherxDachs/UwpNotificationNetCoreTest - var uuid = typeof(T).GUID; + Guid uuid = typeof(T).GUID; uint _cookie; CoRegisterClassObject(uuid, new NotificationActivatorClassFactory(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, out _cookie); @@ -160,7 +160,7 @@ private interface IClassFactory private const int CLSCTX_LOCAL_SERVER = 4; private const int REGCLS_MULTIPLEUSE = 1; private const int S_OK = 0; - private static readonly Guid IUnknownGuid = new Guid("00000000-0000-0000-C000-000000000046"); + private static readonly Guid IUnknownGuid = new("00000000-0000-0000-C000-000000000046"); private class NotificationActivatorClassFactory : IClassFactory where T : NotificationActivator, new() { @@ -277,10 +277,10 @@ private static bool IsElevated /// private class DesktopBridgeHelpers { - const long APPMODEL_ERROR_NO_PACKAGE = 15700L; + private const long APPMODEL_ERROR_NO_PACKAGE = 15700L; [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName); + private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName); private static bool? _isRunningAsUwp; public static bool IsRunningAsUwp() @@ -294,7 +294,7 @@ public static bool IsRunningAsUwp() else { int length = 0; - StringBuilder sb = new StringBuilder(0); + StringBuilder sb = new(0); int result = GetCurrentPackageFullName(ref length, sb); sb = new StringBuilder(length); @@ -492,7 +492,7 @@ public IEnumerator> GetEnumerator() public bool TryGetValue(string key, out string value) { - foreach (var item in _data) + foreach (NOTIFICATION_USER_INPUT_DATA item in _data) { if (item.Key == key) { diff --git a/Text-Grab/Enums.cs b/Text-Grab/Enums.cs index 9f892d44..ea00f4a3 100644 --- a/Text-Grab/Enums.cs +++ b/Text-Grab/Enums.cs @@ -83,4 +83,4 @@ public enum ScrollBehavior None = 0, Resize = 1, Zoom = 2, -} \ No newline at end of file +} diff --git a/Text-Grab/Extensions/ControlExtensions.cs b/Text-Grab/Extensions/ControlExtensions.cs index 038b7131..ec80e918 100644 --- a/Text-Grab/Extensions/ControlExtensions.cs +++ b/Text-Grab/Extensions/ControlExtensions.cs @@ -21,12 +21,12 @@ public static double GetHorizontalScaleFactor(this Viewbox viewbox) public static Rect GetAbsolutePlacement(this FrameworkElement element, bool relativeToScreen = false) { - var absolutePos = element.PointToScreen(new System.Windows.Point(0, 0)); + Point absolutePos = element.PointToScreen(new System.Windows.Point(0, 0)); if (relativeToScreen) { return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight); } - var posMW = Application.Current.MainWindow.PointToScreen(new System.Windows.Point(0, 0)); + Point posMW = Application.Current.MainWindow.PointToScreen(new System.Windows.Point(0, 0)); absolutePos = new System.Windows.Point(absolutePos.X - posMW.X, absolutePos.Y - posMW.Y); return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight); } diff --git a/Text-Grab/Extensions/ImageExtensions.cs b/Text-Grab/Extensions/ImageExtensions.cs index 055a9851..be8c0720 100644 --- a/Text-Grab/Extensions/ImageExtensions.cs +++ b/Text-Grab/Extensions/ImageExtensions.cs @@ -27,16 +27,16 @@ internal static RotateFlipType GetRotateFlipType(this Image img) return RotateFlipType.RotateNoneFlipNone; int val = BitConverter.ToUInt16(propValue, 0); - var rot = RotateFlipType.RotateNoneFlipNone; + RotateFlipType rot = RotateFlipType.RotateNoneFlipNone; - if (val == 3 || val == 4) + if (val is 3 or 4) rot = RotateFlipType.Rotate180FlipNone; - else if (val == 5 || val == 6) + else if (val is 5 or 6) rot = RotateFlipType.Rotate90FlipNone; - else if (val == 7 || val == 8) + else if (val is 7 or 8) rot = RotateFlipType.Rotate270FlipNone; - if (val == 2 || val == 4 || val == 5 || val == 7) + if (val is 2 or 4 or 5 or 7) rot |= RotateFlipType.RotateNoneFlipX; return rot; diff --git a/Text-Grab/Extensions/LanguageExtensions.cs b/Text-Grab/Extensions/LanguageExtensions.cs index 5d3d30e5..4f6fc4cf 100644 --- a/Text-Grab/Extensions/LanguageExtensions.cs +++ b/Text-Grab/Extensions/LanguageExtensions.cs @@ -27,7 +27,7 @@ public static bool IsRightToLeft(this Language language) public static bool IsLatinBased(this Language language) { // List of Latin-based languages - List LatinLanguages = new List() + List LatinLanguages = new() { "en", // English "es", // Spanish diff --git a/Text-Grab/Extensions/SettingsStorageExtensions.cs b/Text-Grab/Extensions/SettingsStorageExtensions.cs index bb873788..0c28c87c 100644 --- a/Text-Grab/Extensions/SettingsStorageExtensions.cs +++ b/Text-Grab/Extensions/SettingsStorageExtensions.cs @@ -58,7 +58,7 @@ public static void SaveString(this ApplicationDataContainer settings, string key { if (settings.Values.TryGetValue(key, out object? obj)) return await Json.ToObjectAsync((string)obj); - + return default; } @@ -68,7 +68,7 @@ public static async Task SaveFileAsync(this StorageFolder folder, b if (string.IsNullOrEmpty(fileName)) throw new ArgumentException("File name is null or empty. Specify a valid file name", nameof(fileName)); - + StorageFile storageFile = await folder.CreateFileAsync(fileName, options); await FileIO.WriteBytesAsync(storageFile, content); return storageFile; @@ -92,7 +92,7 @@ public static async Task SaveFileAsync(this StorageFolder folder, b { if (file == null) return null; - + using IRandomAccessStream stream = await file.OpenReadAsync(); using DataReader reader = new(stream.GetInputStreamAt(0)); await reader.LoadAsync((uint)stream.Size); diff --git a/Text-Grab/Extensions/ShapeExtensions.cs b/Text-Grab/Extensions/ShapeExtensions.cs index 22827206..d666960b 100644 --- a/Text-Grab/Extensions/ShapeExtensions.cs +++ b/Text-Grab/Extensions/ShapeExtensions.cs @@ -50,12 +50,12 @@ public static Rect GetScaleSizeByFraction(this Rect rect, Double scaleFactor) public static bool IsGood(this Rect rect) { - if (double.IsNaN(rect.X) + if (double.IsNaN(rect.X) || double.IsNegativeInfinity(rect.X) || double.IsPositiveInfinity(rect.X)) return false; - - if (double.IsNaN(rect.Y) + + if (double.IsNaN(rect.Y) || double.IsNegativeInfinity(rect.Y) || double.IsPositiveInfinity(rect.Y)) return false; diff --git a/Text-Grab/Models/DragDataObject.cs b/Text-Grab/Models/DragDataObject.cs index a5adc178..55d861df 100644 --- a/Text-Grab/Models/DragDataObject.cs +++ b/Text-Grab/Models/DragDataObject.cs @@ -11,7 +11,7 @@ namespace Text_Grab.Models; // based on: https://stackoverflow.com/questions/61041282/showing-image-thumbnail-with-mouse-cursor-while-dragging/61148788#61148788 public static class DragDataObject { - private static readonly Guid DataObject = new Guid("b8c0bd9f-ed24-455c-83e6-d5390c4fe8c4"); + private static readonly Guid DataObject = new("b8c0bd9f-ed24-455c-83e6-d5390c4fe8c4"); public static IDataObject FromFile(string filePath) { @@ -25,7 +25,7 @@ public static void SetDragImage(this IDataObject dataObject, IntPtr hBitmap, int ArgumentNullException.ThrowIfNull(dataObject); IDragSourceHelper dragDropHelper = (IDragSourceHelper)new DragDropHelper(); - ShDragImage dragImage = new ShDragImage + ShDragImage dragImage = new() { HBmpDragImage = hBitmap, SizeDragImage = new Size(width, height), @@ -81,7 +81,7 @@ private interface IDragSourceHelper return null; } - Bitmap bitmap = new Bitmap(source.PixelWidth, source.PixelHeight, DrawingImaging.PixelFormat.Format32bppArgb); + Bitmap bitmap = new(source.PixelWidth, source.PixelHeight, DrawingImaging.PixelFormat.Format32bppArgb); DrawingImaging.BitmapData bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), DrawingImaging.ImageLockMode.WriteOnly, DrawingImaging.PixelFormat.Format32bppArgb); source.CopyPixels(System.Windows.Int32Rect.Empty, bitmapData.Scan0, bitmapData.Height * bitmapData.Stride, bitmapData.Stride); diff --git a/Text-Grab/Models/OcrOutput.cs b/Text-Grab/Models/OcrOutput.cs index 07677e46..27232161 100644 --- a/Text-Grab/Models/OcrOutput.cs +++ b/Text-Grab/Models/OcrOutput.cs @@ -2,7 +2,6 @@ using Text_Grab.Properties; using Text_Grab.Utilities; using Windows.Globalization; -using Windows.Media.Ocr; namespace Text_Grab.Models; diff --git a/Text-Grab/Models/ResultTable.cs b/Text-Grab/Models/ResultTable.cs index 669311b9..3a07cd9a 100644 --- a/Text-Grab/Models/ResultTable.cs +++ b/Text-Grab/Models/ResultTable.cs @@ -41,10 +41,10 @@ public ResultTable(ref List wordBorders, DpiScale dpiScale) Rectangle bordersBorder = new(); if (wordBorders.Count > 0) { - var leftsMin = wordBorders.Select(x => x.Left).Min(); - var topsMin = wordBorders.Select(x => x.Top).Min(); - var rightsMax = wordBorders.Select(x => x.Right).Max(); - var bottomsMax = wordBorders.Select(x => x.Bottom).Max(); + double leftsMin = wordBorders.Select(x => x.Left).Min(); + double topsMin = wordBorders.Select(x => x.Top).Min(); + double rightsMax = wordBorders.Select(x => x.Right).Max(); + double bottomsMax = wordBorders.Select(x => x.Bottom).Max(); bordersBorder = new() { @@ -72,13 +72,13 @@ private void ParseRowAndColumnLines() if (Rows.Count >= 1) { topBound = (int)Rows[0].Top; - bottomBound = (int)Rows[Rows.Count - 1].Bottom; + bottomBound = (int)Rows[^1].Bottom; } if (Columns.Count >= 1) { leftBound = (int)Columns[0].Left; - rightBound = (int)Columns[Columns.Count - 1].Right; + rightBound = (int)Columns[^1].Right; } BoundingRect = new() @@ -333,7 +333,7 @@ private static List FindOutlierRowIds( Canvas.SetLeft(rowBorder, tableBoundingRect.X); Canvas.SetTop(rowBorder, row.Top); - Rect rowRect = new Rect(tableBoundingRect.X, row.Top, rowBorder.Width, rowBorder.Height); + Rect rowRect = new(tableBoundingRect.X, row.Top, rowBorder.Width, rowBorder.Height); foreach (WordBorder wb in wordBorders) { @@ -375,7 +375,7 @@ private static List FindOutlierColumnIds( Canvas.SetLeft(columnBorder, column.Left); Canvas.SetTop(columnBorder, tableBoundingRect.Y); - Rect columnRect = new Rect(column.Left, tableBoundingRect.Y, columnBorder.Width, columnBorder.Height); + Rect columnRect = new(column.Left, tableBoundingRect.Y, columnBorder.Width, columnBorder.Height); foreach (WordBorder wb in wordBorders) { if (wb.IntersectsWith(columnRect)) diff --git a/Text-Grab/Models/ShortcutKeySet.cs b/Text-Grab/Models/ShortcutKeySet.cs index 9a0ee272..be0544e4 100644 --- a/Text-Grab/Models/ShortcutKeySet.cs +++ b/Text-Grab/Models/ShortcutKeySet.cs @@ -41,14 +41,14 @@ public ShortcutKeySet(string shortcutsAsString) if (!shortcutsAsString.Contains('-')) return; - var enabledSplitKeys = shortcutsAsString.Split('-'); + string[] enabledSplitKeys = shortcutsAsString.Split('-'); bool parsedEnabledSuccessfully = bool.TryParse(enabledSplitKeys[0], out bool parsedEnabled); if (!parsedEnabledSuccessfully || enabledSplitKeys.Length < 2) return; - var splitUpString = enabledSplitKeys[1].Split('+'); + string[] splitUpString = enabledSplitKeys[1].Split('+'); string? keyString = splitUpString.LastOrDefault(); if (Enum.TryParse(keyString, out Key parsedKey)) diff --git a/Text-Grab/NativeMethods.cs b/Text-Grab/NativeMethods.cs index a1feff36..cb15c71c 100644 --- a/Text-Grab/NativeMethods.cs +++ b/Text-Grab/NativeMethods.cs @@ -5,7 +5,7 @@ internal static partial class NativeMethods { // See http://msdn.microsoft.com/en-us/library/ms649021%28v=vs.85%29.aspx public const int WM_CLIPBOARDUPDATE = 0x031D; - public static IntPtr HWND_MESSAGE = new IntPtr(-3); + public static IntPtr HWND_MESSAGE = new(-3); // See http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only [LibraryImport("user32.dll", SetLastError = true)] diff --git a/Text-Grab/OSInterop.cs b/Text-Grab/OSInterop.cs index da4dc134..21b594fa 100644 --- a/Text-Grab/OSInterop.cs +++ b/Text-Grab/OSInterop.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -static partial class OSInterop +internal static partial class OSInterop { [LibraryImport("user32.dll")] public static partial int GetSystemMetrics(int smIndex); @@ -38,8 +38,8 @@ public struct RECT public class MONITORINFOEX { public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX)); - public RECT rcMonitor = new RECT(); - public RECT rcWork = new RECT(); + public RECT rcMonitor = new(); + public RECT rcWork = new(); [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public char[] szDevice = new char[32]; public int dwFlags; diff --git a/Text-Grab/Pages/GeneralSettings.xaml.cs b/Text-Grab/Pages/GeneralSettings.xaml.cs index f340e2c2..3f116592 100644 --- a/Text-Grab/Pages/GeneralSettings.xaml.cs +++ b/Text-Grab/Pages/GeneralSettings.xaml.cs @@ -247,7 +247,7 @@ private void HistorySwitch_Checked(object sender, RoutedEventArgs e) { if (!settingsSet) return; - + DefaultSettings.UseHistory = true; } @@ -311,7 +311,7 @@ private async void StartupOnLoginCheckBox_Checked(object sender, RoutedEventArgs { if (!settingsSet) return; - + DefaultSettings.StartupOnLogin = true; await ImplementAppOptions.ImplementStartupOption(true); } diff --git a/Text-Grab/Pages/KeysSettings.xaml.cs b/Text-Grab/Pages/KeysSettings.xaml.cs index 84cbb3ac..4ec8532c 100644 --- a/Text-Grab/Pages/KeysSettings.xaml.cs +++ b/Text-Grab/Pages/KeysSettings.xaml.cs @@ -94,7 +94,7 @@ private bool HotKeysAllDifferent() return false; return true; - } + } private void Page_Loaded(object sender, RoutedEventArgs e) { diff --git a/Text-Grab/Services/HistoryService.cs b/Text-Grab/Services/HistoryService.cs index 10bd7b77..5271b12d 100644 --- a/Text-Grab/Services/HistoryService.cs +++ b/Text-Grab/Services/HistoryService.cs @@ -250,11 +250,11 @@ public void WriteHistory() private static async Task> LoadHistory(string fileName) { - string rawText = await FileUtilities.GetTextFileAsync($"{fileName}.json",FileStorageKind.WithHistory); + string rawText = await FileUtilities.GetTextFileAsync($"{fileName}.json", FileStorageKind.WithHistory); if (string.IsNullOrWhiteSpace(rawText)) return new List(); - var tempHistory = JsonSerializer.Deserialize>(rawText); + List? tempHistory = JsonSerializer.Deserialize>(rawText); if (tempHistory is List jsonList && jsonList.Count > 0) return tempHistory; diff --git a/Text-Grab/Services/SettingsService.cs b/Text-Grab/Services/SettingsService.cs index 05c2429e..fd1cddd8 100644 --- a/Text-Grab/Services/SettingsService.cs +++ b/Text-Grab/Services/SettingsService.cs @@ -47,7 +47,7 @@ private void MigrateLocalSettingsToClassic() throw; #endif } - + } } diff --git a/Text-Grab/TextGrabNotificationActivator.cs b/Text-Grab/TextGrabNotificationActivator.cs index f9e077a6..2ab367cb 100644 --- a/Text-Grab/TextGrabNotificationActivator.cs +++ b/Text-Grab/TextGrabNotificationActivator.cs @@ -1,27 +1,26 @@ using System; using System.Runtime.InteropServices; -namespace Text_Grab +namespace Text_Grab; + +// The GUID CLSID must be unique to your app. Create a new GUID if copying this code. +[ClassInterface(ClassInterfaceType.None)] +[ComSourceInterfaces(typeof(INotificationActivationCallback))] +[Guid("215d64d2-031c-33c7-96e3-61794cd1ee61"), ComVisible(true)] +public class TextGrabNotificationActivator : NotificationActivator { - // The GUID CLSID must be unique to your app. Create a new GUID if copying this code. - [ClassInterface(ClassInterfaceType.None)] - [ComSourceInterfaces(typeof(INotificationActivationCallback))] - [Guid("215d64d2-031c-33c7-96e3-61794cd1ee61"), ComVisible(true)] - public class TextGrabNotificationActivator : NotificationActivator + public override void OnActivated(string invokedArgs, NotificationUserInput userInput, string appUserModelId) { - public override void OnActivated(string invokedArgs, NotificationUserInput userInput, string appUserModelId) + System.Windows.Application.Current.Dispatcher.Invoke(delegate { - System.Windows.Application.Current.Dispatcher.Invoke(delegate + // Tapping on the top-level header launches with empty args + if (invokedArgs.Length != 0) { - // Tapping on the top-level header launches with empty args - if (invokedArgs.Length != 0) - { - // Perform a normal launch - EditTextWindow mtw = new EditTextWindow(invokedArgs); - mtw.Show(); - return; - } - }); - } + // Perform a normal launch + EditTextWindow mtw = new(invokedArgs); + mtw.Show(); + return; + } + }); } } diff --git a/Text-Grab/UndoRedoOperations/AddWordBorder.cs b/Text-Grab/UndoRedoOperations/AddWordBorder.cs index 889ffc9a..cfae4708 100644 --- a/Text-Grab/UndoRedoOperations/AddWordBorder.cs +++ b/Text-Grab/UndoRedoOperations/AddWordBorder.cs @@ -1,13 +1,12 @@ using System.Collections.Generic; using System.Windows.Controls; using Text_Grab.Controls; -using Text_Grab.UndoRedoOperations; namespace Text_Grab.UndoRedoOperations; internal class AddWordBorder : Operation, IUndoRedoOperation { - public AddWordBorder(uint transactionId, WordBorder wordBorder, + public AddWordBorder(uint transactionId, WordBorder wordBorder, Canvas canvas, ICollection wordBorders) : base(transactionId) { WordBorder = wordBorder; diff --git a/Text-Grab/UndoRedoOperations/ChangeWord.cs b/Text-Grab/UndoRedoOperations/ChangeWord.cs index 9d125b9f..2ba2d47c 100644 --- a/Text-Grab/UndoRedoOperations/ChangeWord.cs +++ b/Text-Grab/UndoRedoOperations/ChangeWord.cs @@ -1,19 +1,16 @@ -using System.Collections.Generic; -using System.Windows.Controls; -using Text_Grab.Controls; -using Text_Grab.UndoRedoOperations; +using Text_Grab.Controls; namespace Text_Grab.UndoRedoOperations; internal class ChangeWord : Operation, IUndoRedoOperation { - public ChangeWord(uint transactionId, WordBorder wordBorder, + public ChangeWord(uint transactionId, WordBorder wordBorder, string oldWord, string newWord) : base(transactionId) { WordBorder = wordBorder; OldWord = oldWord; NewWord = newWord; - + } private WordBorder WordBorder; diff --git a/Text-Grab/UndoRedoOperations/RemoveWordBorder.cs b/Text-Grab/UndoRedoOperations/RemoveWordBorder.cs index 9d1794c5..c8175cc2 100644 --- a/Text-Grab/UndoRedoOperations/RemoveWordBorder.cs +++ b/Text-Grab/UndoRedoOperations/RemoveWordBorder.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Windows.Controls; using Text_Grab.Controls; -using Text_Grab.UndoRedoOperations; namespace Text_Grab.UndoRedoOperations; @@ -16,7 +15,7 @@ public RemoveWordBorder(uint transactionId, List removingWordBorders } private List RemovingWordBorders; - + private Canvas Canvas; private ICollection WordBorders; diff --git a/Text-Grab/UndoRedoOperations/UndoRedo.cs b/Text-Grab/UndoRedoOperations/UndoRedo.cs index ae39b07c..ca356022 100644 --- a/Text-Grab/UndoRedoOperations/UndoRedo.cs +++ b/Text-Grab/UndoRedoOperations/UndoRedo.cs @@ -1,9 +1,8 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; namespace Text_Grab.UndoRedoOperations; -class UndoRedo +internal class UndoRedo { public const int UndoRedoTransactionCapacity = 100; @@ -112,12 +111,12 @@ public void Undo() if (UndoStack.Count == 0 || UndoStack.Last is null) return; - var operationNode = UndoStack.Last; - var currentTransactionId = operationNode.Value.TransactionId; + LinkedListNode? operationNode = UndoStack.Last; + uint currentTransactionId = operationNode.Value.TransactionId; while (operationNode != null && operationNode.Value.TransactionId == currentTransactionId) { - var prev = operationNode.Previous; - var operation = operationNode.Value; + LinkedListNode? prev = operationNode.Previous; + IUndoRedoOperation operation = operationNode.Value; operation.Undo(); // Add operation into redo stack. @@ -137,12 +136,12 @@ public void Redo() if (RedoStack.Count == 0 || RedoStack.Last is null) return; - var operationNode = RedoStack.Last; - var currentTransactionId = operationNode.Value.TransactionId; + LinkedListNode? operationNode = RedoStack.Last; + uint currentTransactionId = operationNode.Value.TransactionId; while (operationNode != null && operationNode.Value.TransactionId == currentTransactionId) { - var prev = operationNode.Previous; - var operation = RedoStack.Last.Value; + LinkedListNode? prev = operationNode.Previous; + IUndoRedoOperation operation = RedoStack.Last.Value; operation.Redo(); // Add operation into Undo Stack. diff --git a/Text-Grab/Utilities/BarcodeUtilities.cs b/Text-Grab/Utilities/BarcodeUtilities.cs index dad9b505..40385f79 100644 --- a/Text-Grab/Utilities/BarcodeUtilities.cs +++ b/Text-Grab/Utilities/BarcodeUtilities.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; using System.Drawing; -using System.Windows.Media; using Text_Grab.Models; using ZXing; using ZXing.Common; @@ -29,7 +26,7 @@ public static OcrOutput TryToReadBarcodes(Bitmap bitmap) if (result is not null) resultString = result.Text; - return new OcrOutput () + return new OcrOutput() { Kind = OcrOutputKind.Barcode, RawOutput = resultString, @@ -79,7 +76,7 @@ public static SvgImage GetSvgQrCodeForText(string text, ErrorCorrectionLevel cor }; encodingOptions.Hints.Add(ZXing.EncodeHintType.ERROR_CORRECTION, correctionLevel); barcodeWriter.Options = encodingOptions; - + SvgImage svg = barcodeWriter.Write(text); return svg; diff --git a/Text-Grab/Utilities/ClipboardUtilities.cs b/Text-Grab/Utilities/ClipboardUtilities.cs index ec3a528d..833e09ba 100644 --- a/Text-Grab/Utilities/ClipboardUtilities.cs +++ b/Text-Grab/Utilities/ClipboardUtilities.cs @@ -79,7 +79,7 @@ public static (bool, ImageSource?) TryGetImageFromClipboard() trimmedData = CleanTeamsBase64Image(trimmedData); // used some code from https://github.com/veler/DevToys - string base64 = trimmedData.Substring(trimmedData.IndexOf(',') + 1); + string base64 = trimmedData[(trimmedData.IndexOf(',') + 1)..]; byte[] bytes = Convert.FromBase64String(base64); // cannot dispose of memoryStream or the BitmapImage is empty when the view trys to render @@ -127,7 +127,7 @@ private static string CleanTeamsBase64Image(string dirtyTeamsString) return sb.ToString(); } - static string base64ImageExtension(ref string base64String) + private static string base64ImageExtension(ref string base64String) { // Copied this portion of the code from https://github.com/veler/DevToys if (base64String!.StartsWith("data:image/png;base64,", StringComparison.OrdinalIgnoreCase)) diff --git a/Text-Grab/Utilities/CursorClipper.cs b/Text-Grab/Utilities/CursorClipper.cs index f9511116..9e38ded1 100644 --- a/Text-Grab/Utilities/CursorClipper.cs +++ b/Text-Grab/Utilities/CursorClipper.cs @@ -17,7 +17,7 @@ public static bool ClipCursor(FrameworkElement element) { const double dpi96 = 96.0; - var topLeft = element.PointToScreen(new Point(0, 0)); + Point topLeft = element.PointToScreen(new Point(0, 0)); PresentationSource source = PresentationSource.FromVisual(element); if (source?.CompositionTarget == null) @@ -28,10 +28,10 @@ public static bool ClipCursor(FrameworkElement element) double dpiX = dpi96 * source.CompositionTarget.TransformToDevice.M11; double dpiY = dpi96 * source.CompositionTarget.TransformToDevice.M22; - var width = (int)((element.ActualWidth + 1) * dpiX / dpi96); - var height = (int)((element.ActualHeight + 1) * dpiY / dpi96); + int width = (int)((element.ActualWidth + 1) * dpiX / dpi96); + int height = (int)((element.ActualHeight + 1) * dpiY / dpi96); - OSInterop.RECT rect = new OSInterop.RECT + OSInterop.RECT rect = new() { left = (int)topLeft.X, top = (int)topLeft.Y, diff --git a/Text-Grab/Utilities/CustomBottomBarUtilities.cs b/Text-Grab/Utilities/CustomBottomBarUtilities.cs index 6310d034..90293561 100644 --- a/Text-Grab/Utilities/CustomBottomBarUtilities.cs +++ b/Text-Grab/Utilities/CustomBottomBarUtilities.cs @@ -3,12 +3,10 @@ using System.Reflection; using System.Text.Json; using System.Windows; -using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using Text_Grab.Controls; using Text_Grab.Models; -using Text_Grab.Properties; using Wpf.Ui.Controls; namespace Text_Grab.Utilities; diff --git a/Text-Grab/Utilities/FileUtilities.cs b/Text-Grab/Utilities/FileUtilities.cs index 4bc64d0f..280827db 100644 --- a/Text-Grab/Utilities/FileUtilities.cs +++ b/Text-Grab/Utilities/FileUtilities.cs @@ -5,7 +5,6 @@ using System.IO; using System.Text; using System.Threading.Tasks; -using Windows.Media.Streaming.Adaptive; using Windows.Storage; using Windows.Storage.Streams; @@ -37,7 +36,7 @@ public static string GetImageFilter() string imageExtensions = string.Empty; string separator = ""; ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); - Dictionary imageFilters = new Dictionary(); + Dictionary imageFilters = new(); foreach (ImageCodecInfo codec in codecs) { if (codec.FilenameExtension is not string extension) @@ -73,7 +72,7 @@ public static string GetPathToLocalFile(string imageRelativePath) return Path.Combine(dirPath, imageRelativePath); } - public async static Task GetPathToHistory() + public static async Task GetPathToHistory() { if (AppUtilities.IsPackaged()) { @@ -108,7 +107,7 @@ public static Task SaveTextFile(string textContent, string filename, FileS return SaveTextFileUnpackaged(textContent, filename, storageKind); } - private async static Task GetImageFilePackaged(string fileName, FileStorageKind storageKind) + private static async Task GetImageFilePackaged(string fileName, FileStorageKind storageKind) { StorageFolder folder = await GetStorageFolderPackaged(fileName, storageKind); @@ -122,7 +121,7 @@ public static Task SaveTextFile(string textContent, string filename, FileS return null; } } - + #pragma warning disable CS1998 private static async Task GetImageFileUnpackaged(string fileName, FileStorageKind storageKind) { @@ -134,7 +133,7 @@ public static Task SaveTextFile(string textContent, string filename, FileS return new Bitmap(filePath); } - private async static Task GetTextFilePackaged(string fileName, FileStorageKind storageKind) + private static async Task GetTextFilePackaged(string fileName, FileStorageKind storageKind) { try { @@ -290,8 +289,8 @@ private static async Task SaveTextFileUnpackaged(string textContent, strin return true; } #pragma warning restore CS1998 - - public async static void TryDeleteHistoryDirectory() + + public static async void TryDeleteHistoryDirectory() { FileStorageKind historyFolderKind = FileStorageKind.WithHistory; if (AppUtilities.IsPackaged()) diff --git a/Text-Grab/Utilities/HotKeyManager.cs b/Text-Grab/Utilities/HotKeyManager.cs index 05eee7b6..0f2d0e06 100644 --- a/Text-Grab/Utilities/HotKeyManager.cs +++ b/Text-Grab/Utilities/HotKeyManager.cs @@ -3,7 +3,6 @@ using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; -using System.Windows.Input; using Text_Grab.Models; namespace Text_Grab.Utilities; @@ -37,8 +36,9 @@ public static void UnregisterHotKey(int id) _wnd?.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id); } - delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key); - delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id); + private delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key); + + private delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id); private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key) { @@ -60,10 +60,10 @@ private static void OnHotKeyPressed(HotKeyEventArgs e) private static volatile MessageWindow? _wnd; private static volatile IntPtr _hwnd; - private static ManualResetEvent? _windowReadyEvent = new ManualResetEvent(false); + private static ManualResetEvent? _windowReadyEvent = new(false); static HotKeyManager() { - Thread messageLoop = new Thread(delegate () + Thread messageLoop = new(delegate () { Application.Run(new MessageWindow()); }); @@ -85,7 +85,7 @@ protected override void WndProc(ref Message m) { if (m.Msg == WM_HOTKEY) { - HotKeyEventArgs e = new HotKeyEventArgs(m.LParam); + HotKeyEventArgs e = new(m.LParam); HotKeyManager.OnHotKeyPressed(e); } diff --git a/Text-Grab/Utilities/IoUtilities.cs b/Text-Grab/Utilities/IoUtilities.cs index ac40632c..f0544214 100644 --- a/Text-Grab/Utilities/IoUtilities.cs +++ b/Text-Grab/Utilities/IoUtilities.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Threading.Tasks; diff --git a/Text-Grab/Utilities/LanguageUtilities.cs b/Text-Grab/Utilities/LanguageUtilities.cs index 285340e5..faa9a7c0 100644 --- a/Text-Grab/Utilities/LanguageUtilities.cs +++ b/Text-Grab/Utilities/LanguageUtilities.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Windows.Input; -using Text_Grab.Properties; using Windows.Globalization; using Windows.Media.Ocr; diff --git a/Text-Grab/Utilities/NotificationUtilities.cs b/Text-Grab/Utilities/NotificationUtilities.cs index 00e5f335..cab4437b 100644 --- a/Text-Grab/Utilities/NotificationUtilities.cs +++ b/Text-Grab/Utilities/NotificationUtilities.cs @@ -12,17 +12,17 @@ internal static void ShowToast(string copiedText) // changed to using base64 // the padding '=' will be encoded as '%3D' in the toast XML, so remove them - string encodedString = Convert.ToBase64String(plainTextBytes).TrimEnd('='); + string encodedString = Convert.ToBase64String(plainTextBytes).TrimEnd('='); // truncate toast body text first, if it is too long string toastBody; if (copiedText.Length > 150) - toastBody = copiedText.Substring(0, 150) + "..."; + toastBody = copiedText[..150] + "..."; else toastBody = copiedText; // build the toast XML - var toast = new ToastContentBuilder() + ToastContentBuilder toast = new ToastContentBuilder() .AddArgument("text", encodedString) .AddText("Text Grab") .AddText(toastBody); diff --git a/Text-Grab/Utilities/NotifyIconUtilities.cs b/Text-Grab/Utilities/NotifyIconUtilities.cs index 5f45bd2b..968e5d86 100644 --- a/Text-Grab/Utilities/NotifyIconUtilities.cs +++ b/Text-Grab/Utilities/NotifyIconUtilities.cs @@ -49,7 +49,7 @@ private static void trayIcon_Disposed(object? sender, EventArgs e) UnregisterHotkeys(app); } - static void HotKeyManager_HotKeyPressed(object? sender, HotKeyEventArgs e) + private static void HotKeyManager_HotKeyPressed(object? sender, HotKeyEventArgs e) { if (!AppUtilities.TextGrabSettings.GlobalHotkeysEnabled) return; diff --git a/Text-Grab/Utilities/OcrUtilities.cs b/Text-Grab/Utilities/OcrUtilities.cs index 2de33ef1..11008941 100644 --- a/Text-Grab/Utilities/OcrUtilities.cs +++ b/Text-Grab/Utilities/OcrUtilities.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; -using System.Runtime.Intrinsics.Arm; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -14,11 +12,9 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using Text_Grab.Controls; -using Text_Grab.Extensions; using Text_Grab.Models; using Text_Grab.Properties; using Text_Grab.Services; -using Text_Grab.Views; using Windows.Globalization; using Windows.Graphics.Imaging; using Windows.Media.Ocr; @@ -30,7 +26,7 @@ namespace Text_Grab.Utilities; public static class OcrUtilities { - private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; + private static readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; public static void GetTextFromOcrLine(this OcrLine ocrLine, bool isSpaceJoiningOCRLang, StringBuilder text) { @@ -97,7 +93,7 @@ public static async Task GetRegionsTextAsync(Window passedWindow, Rectan Rectangle correctedRegion = new(thisCorrectedLeft, thisCorrectedTop, selectedRegion.Width, selectedRegion.Height); Bitmap bmp = ImageMethods.GetRegionOfScreenAsBitmap(correctedRegion); - return GetStringFromOcrOutputs( await GetTextFromImageAsync(bmp, language, languageTag)); + return GetStringFromOcrOutputs(await GetTextFromImageAsync(bmp, language, languageTag)); } public static async Task GetRegionsTextAsTableAsync(Window passedWindow, Rectangle selectedRegion, Language language) @@ -129,7 +125,7 @@ public static async Task GetRegionsTextAsTableAsync(Window passedWindow, return (ocrResult, scale); } - public async static Task GetOcrFromStreamAsync(MemoryStream memoryStream, Language language) + public static async Task GetOcrFromStreamAsync(MemoryStream memoryStream, Language language) { using WrappingStream wrapper = new(memoryStream); wrapper.Position = 0; @@ -141,7 +137,7 @@ public async static Task GetOcrFromStreamAsync(MemoryStream memoryStr return await GetOcrResultFromImageAsync(softwareBmp, language); } - public async static Task GetOcrFromStreamAsync(IRandomAccessStream stream, Language language) + public static async Task GetOcrFromStreamAsync(IRandomAccessStream stream, Language language) { BitmapDecoder bmpDecoder = await BitmapDecoder.CreateAsync(stream); using SoftwareBitmap softwareBmp = await bmpDecoder.GetSoftwareBitmapAsync(); @@ -149,13 +145,13 @@ public async static Task GetOcrFromStreamAsync(IRandomAccessStream st return await GetOcrResultFromImageAsync(softwareBmp, language); } - public async static Task GetOcrResultFromImageAsync(BitmapImage scaledBitmap, Language language) + public static async Task GetOcrResultFromImageAsync(BitmapImage scaledBitmap, Language language) { Bitmap bitmap = ImageMethods.BitmapImageToBitmap(scaledBitmap); return await GetOcrResultFromImageAsync(bitmap, language); } - public async static Task GetOcrResultFromImageAsync(SoftwareBitmap scaledBitmap, Language language) + public static async Task GetOcrResultFromImageAsync(SoftwareBitmap scaledBitmap, Language language) { OcrEngine ocrEngine = OcrEngine.TryCreateFromLanguage(language); @@ -165,7 +161,7 @@ public async static Task GetOcrResultFromImageAsync(SoftwareBitmap sc return await ocrEngine.RecognizeAsync(scaledBitmap); } - public async static Task GetOcrResultFromImageAsync(Bitmap scaledBitmap, Language language) + public static async Task GetOcrResultFromImageAsync(Bitmap scaledBitmap, Language language) { await using MemoryStream memory = new(); using WrappingStream wrapper = new(memory); @@ -180,7 +176,7 @@ public async static Task GetOcrResultFromImageAsync(Bitmap scaledBitm return await GetOcrResultFromImageAsync(softwareBmp, language); } - public async static void GetCopyTextFromPreviousRegion() + public static async void GetCopyTextFromPreviousRegion() { HistoryInfo? lastFsg = Singleton.Instance.GetLastFullScreenGrabInfo(); @@ -211,7 +207,7 @@ public async static void GetCopyTextFromPreviousRegion() OutputUtilities.HandleTextFromOcr(grabbedText, false, lastFsg.IsTable, null); } - public async static Task GetTextFromPreviousFullscreenRegion(TextBox? destinationTextBox = null) + public static async Task GetTextFromPreviousFullscreenRegion(TextBox? destinationTextBox = null) { HistoryInfo? lastFsg = Singleton.Instance.GetLastFullScreenGrabInfo(); @@ -242,7 +238,7 @@ public async static Task GetTextFromPreviousFullscreenRegion(TextBox? destinatio OutputUtilities.HandleTextFromOcr(grabbedText, false, lastFsg.IsTable, destinationTextBox); } - public async static Task> GetTextFromRandomAccessStream(IRandomAccessStream randomAccessStream, Language language) + public static async Task> GetTextFromRandomAccessStream(IRandomAccessStream randomAccessStream, Language language) { OcrResult ocrResult = await GetOcrFromStreamAsync(randomAccessStream, language); @@ -271,7 +267,7 @@ public static Task> GetTextFromImageAsync(SoftwareBitmap softwar // Read QR Codes from software bitmaps } - public async static Task> GetTextFromImageAsync(BitmapImage bitmapImage, Language language) + public static async Task> GetTextFromImageAsync(BitmapImage bitmapImage, Language language) { Bitmap bitmap = ImageMethods.BitmapImageToBitmap(bitmapImage); return await GetTextFromImageAsync(bitmap, language); @@ -287,12 +283,12 @@ public static Task> GetTextFromStreamAsync(IRandomAccessStream s throw new NotImplementedException(); } - public async static Task> GetTextFromImageAsync(Bitmap bitmap, Language language, string tessTag = "") + public static async Task> GetTextFromImageAsync(Bitmap bitmap, Language language, string tessTag = "") { List outputs = new(); - if (DefaultSettings.UseTesseract - && TesseractHelper.CanLocateTesseractExe() + if (DefaultSettings.UseTesseract + && TesseractHelper.CanLocateTesseractExe() && !string.IsNullOrEmpty(tessTag)) { OcrOutput tesseractOutput = await TesseractHelper.GetOcrOutputFromBitmap(bitmap, language, tessTag); @@ -403,14 +399,14 @@ private static string GetTextFromClickedWord(Point singlePoint, OcrResult ocrRes return string.Empty; } - public async static Task GetIdealScaleFactorForOcrAsync(SoftwareBitmap bitmap, Language selectedLanguage) + public static async Task GetIdealScaleFactorForOcrAsync(SoftwareBitmap bitmap, Language selectedLanguage) { OcrResult ocrResult = await OcrUtilities.GetOcrResultFromImageAsync(bitmap, selectedLanguage); return GetIdealScaleFactorForOcrResult(ocrResult, bitmap.PixelHeight, bitmap.PixelWidth); } - public async static Task GetIdealScaleFactorForOcrAsync(Bitmap bitmap, Language selectedLanguage) + public static async Task GetIdealScaleFactorForOcrAsync(Bitmap bitmap, Language selectedLanguage) { OcrResult ocrResult = await OcrUtilities.GetOcrResultFromImageAsync(bitmap, selectedLanguage); diff --git a/Text-Grab/Utilities/OutputUtilities.cs b/Text-Grab/Utilities/OutputUtilities.cs index d6978487..20475866 100644 --- a/Text-Grab/Utilities/OutputUtilities.cs +++ b/Text-Grab/Utilities/OutputUtilities.cs @@ -1,6 +1,5 @@ using System.Windows; using System.Windows.Controls; -using Text_Grab.Properties; namespace Text_Grab.Utilities; diff --git a/Text-Grab/Utilities/RegistryMonitor.cs b/Text-Grab/Utilities/RegistryMonitor.cs index bd8a4766..0b907263 100644 --- a/Text-Grab/Utilities/RegistryMonitor.cs +++ b/Text-Grab/Utilities/RegistryMonitor.cs @@ -43,7 +43,8 @@ namespace RegistryUtils; /// } /// /// -public class RegistryMonitor : IDisposable { +public class RegistryMonitor : IDisposable +{ #region P/Invoke [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] @@ -90,7 +91,8 @@ private static extern int RegNotifyChangeKeyValue(IntPtr hKey, bool bWatchSubtre /// the base class's method. /// /// - protected virtual void OnRegChanged() { + protected virtual void OnRegChanged() + { RegChanged?.Invoke(this, new EventArgs()); } @@ -112,7 +114,8 @@ protected virtual void OnRegChanged() { /// the base class's method. /// /// - protected virtual void OnError(Exception e) { + protected virtual void OnError(Exception e) + { Error?.Invoke(this, new ErrorEventArgs(e)); } @@ -136,7 +139,8 @@ protected virtual void OnError(Exception e) { /// Initializes a new instance of the class. /// /// The registry key to monitor. - public RegistryMonitor(RegistryKey registryKey) { + public RegistryMonitor(RegistryKey registryKey) + { InitRegistryKey(registryKey.Name); } @@ -144,7 +148,8 @@ public RegistryMonitor(RegistryKey registryKey) { /// Initializes a new instance of the class. /// /// The name. - public RegistryMonitor(string name) { + public RegistryMonitor(string name) + { if (name == null || name.Length == 0) throw new ArgumentNullException(nameof(name)); @@ -156,14 +161,16 @@ public RegistryMonitor(string name) { /// /// The registry hive. /// The sub key. - public RegistryMonitor(RegistryHive registryHive, string subKey) { + public RegistryMonitor(RegistryHive registryHive, string subKey) + { InitRegistryKey(registryHive, subKey); } /// /// Disposes this object. /// - public void Dispose() { + public void Dispose() + { Stop(); _disposed = true; GC.SuppressFinalize(this); @@ -172,10 +179,13 @@ public void Dispose() { /// /// Gets or sets the RegChangeNotifyFilter. /// - public RegChangeNotifyFilter RegChangeNotifyFilter { + public RegChangeNotifyFilter RegChangeNotifyFilter + { get { return _regFilter; } - set { - lock (_threadLock) { + set + { + lock (_threadLock) + { if (IsMonitoring) throw new InvalidOperationException("Monitoring thread is already running"); @@ -186,8 +196,10 @@ public RegChangeNotifyFilter RegChangeNotifyFilter { #region Initialization - private void InitRegistryKey(RegistryHive hive, string name) { - _registryHive = hive switch { + private void InitRegistryKey(RegistryHive hive, string name) + { + _registryHive = hive switch + { RegistryHive.ClassesRoot => HKEY_CLASSES_ROOT, RegistryHive.CurrentConfig => HKEY_CURRENT_CONFIG, RegistryHive.CurrentUser => HKEY_CURRENT_USER, @@ -199,7 +211,8 @@ private void InitRegistryKey(RegistryHive hive, string name) { _registrySubName = name; } - private void InitRegistryKey(string name) { + private void InitRegistryKey(string name) + { string[] nameParts = name.Split('\\'); switch (nameParts[0]) @@ -241,21 +254,26 @@ private void InitRegistryKey(string name) { /// true if this object is currently monitoring; /// otherwise, false. /// - public bool IsMonitoring { + public bool IsMonitoring + { get { return _thread != null; } } /// /// Start monitoring. /// - public void Start() { + public void Start() + { if (_disposed) throw new ObjectDisposedException(null, "This instance is already disposed"); - lock (_threadLock) { - if (!IsMonitoring) { + lock (_threadLock) + { + if (!IsMonitoring) + { _eventTerminate.Reset(); - _thread = new Thread(new ThreadStart(MonitorThread)) { + _thread = new Thread(new ThreadStart(MonitorThread)) + { IsBackground = true }; _thread.Start(); @@ -266,29 +284,36 @@ public void Start() { /// /// Stops the monitoring thread. /// - public void Stop() { + public void Stop() + { if (_disposed) throw new ObjectDisposedException(null, "This instance is already disposed"); - lock (_threadLock) { - if (_thread is Thread thread) { + lock (_threadLock) + { + if (_thread is Thread thread) + { _eventTerminate.Set(); thread.Join(); } } } - private void MonitorThread() { - try { + private void MonitorThread() + { + try + { ThreadLoop(); } - catch (Exception e) { + catch (Exception e) + { OnError(e); } _thread = null; } - private void ThreadLoop() { + private void ThreadLoop() + { if (_registryHive is null || _registrySubName is null) return; @@ -300,10 +325,12 @@ private void ThreadLoop() { if (result != 0) throw new Win32Exception(result); - try { + try + { AutoResetEvent _eventNotify = new(false); WaitHandle[] waitHandles = new WaitHandle[] { _eventNotify, _eventTerminate }; - while (!_eventTerminate.WaitOne(0, true)) { + while (!_eventTerminate.WaitOne(0, true)) + { result = RegNotifyChangeKeyValue(registryKey, true, _regFilter, @@ -312,13 +339,16 @@ private void ThreadLoop() { if (result != 0) throw new Win32Exception(result); - if (WaitHandle.WaitAny(waitHandles) == 0) { + if (WaitHandle.WaitAny(waitHandles) == 0) + { OnRegChanged(); } } } - finally { - if (registryKey != IntPtr.Zero) { + finally + { + if (registryKey != IntPtr.Zero) + { RegCloseKey(registryKey); } } @@ -329,7 +359,8 @@ private void ThreadLoop() { /// Filter for notifications reported by . /// [Flags] -public enum RegChangeNotifyFilter { +public enum RegChangeNotifyFilter +{ /// Notify the caller if a subkey is added or deleted. Key = 1, /// Notify the caller of changes to the attributes of the key, diff --git a/Text-Grab/Utilities/ShortcutKeysUtilities.cs b/Text-Grab/Utilities/ShortcutKeysUtilities.cs index 8f5c12cd..5e1f133c 100644 --- a/Text-Grab/Utilities/ShortcutKeysUtilities.cs +++ b/Text-Grab/Utilities/ShortcutKeysUtilities.cs @@ -4,7 +4,6 @@ using System.Text.Json; using System.Windows.Input; using Text_Grab.Models; -using Text_Grab.Properties; namespace Text_Grab.Utilities; @@ -40,7 +39,7 @@ public static IEnumerable GetShortcutKeySetsFromSettings() if (shortcutKeySets is null || shortcutKeySets.Count == 0) return defaultKeys; - var actionsList = shortcutKeySets.Select(x => x.Action).ToList(); + List actionsList = shortcutKeySets.Select(x => x.Action).ToList(); return shortcutKeySets.Concat(defaultKeys.Where(x => !actionsList.Contains(x.Action)).ToList()).ToList(); } diff --git a/Text-Grab/Utilities/Singleton.cs b/Text-Grab/Utilities/Singleton.cs index 8f6d0776..42f56e64 100644 --- a/Text-Grab/Utilities/Singleton.cs +++ b/Text-Grab/Utilities/Singleton.cs @@ -5,7 +5,7 @@ namespace Text_Grab.Utilities; internal static class Singleton where T : new() { - private static ConcurrentDictionary _instances = new ConcurrentDictionary(); + private static ConcurrentDictionary _instances = new(); public static T Instance { diff --git a/Text-Grab/Utilities/StreamWrapper.cs b/Text-Grab/Utilities/StreamWrapper.cs index 14dbe850..460e1507 100644 --- a/Text-Grab/Utilities/StreamWrapper.cs +++ b/Text-Grab/Utilities/StreamWrapper.cs @@ -131,8 +131,7 @@ public override void EndWrite(IAsyncResult asyncResult) { ThrowIfDisposed(); - if (m_streamBase is not null) - m_streamBase.EndWrite(asyncResult); + m_streamBase?.EndWrite(asyncResult); } /// @@ -142,8 +141,7 @@ public override void Flush() { ThrowIfDisposed(); - if (m_streamBase is not null) - m_streamBase.Flush(); + m_streamBase?.Flush(); } /// @@ -197,8 +195,7 @@ public override void SetLength(long value) { ThrowIfDisposed(); - if (m_streamBase is not null) - m_streamBase.SetLength(value); + m_streamBase?.SetLength(value); } /// @@ -209,8 +206,7 @@ public override void Write(byte[] buffer, int offset, int count) { ThrowIfDisposed(); - if (m_streamBase is not null) - m_streamBase.Write(buffer, offset, count); + m_streamBase?.Write(buffer, offset, count); } /// @@ -220,8 +216,7 @@ public override void WriteByte(byte value) { ThrowIfDisposed(); - if (m_streamBase is not null) - m_streamBase.WriteByte(value); + m_streamBase?.WriteByte(value); } /// @@ -253,5 +248,6 @@ private void ThrowIfDisposed() if (m_streamBase == null) throw new ObjectDisposedException(GetType().Name); } - Stream? m_streamBase; + + private Stream? m_streamBase; } \ No newline at end of file diff --git a/Text-Grab/Utilities/StringMethods.cs b/Text-Grab/Utilities/StringMethods.cs index d53ed248..686d111d 100644 --- a/Text-Grab/Utilities/StringMethods.cs +++ b/Text-Grab/Utilities/StringMethods.cs @@ -507,7 +507,7 @@ private static string ShortenRegexPattern(this string pattern) return possibleShortenedPatterns.First(); } - static IEnumerable Split(string str, int chunkSize) + private static IEnumerable Split(string str, int chunkSize) { return Enumerable.Range(0, str.Length / chunkSize) .Select(i => str.Substring(i * chunkSize, chunkSize)); @@ -662,7 +662,7 @@ public static string LimitCharactersPerLine(this string stringToEdit, int charac continue; } - if (spotInLine== SpotInLine.Beginning) + if (spotInLine == SpotInLine.Beginning) returnStringBuilder.AppendLine(line[..lineLimit]); else returnStringBuilder.AppendLine(line.Substring(line.Length - (lineLimit), lineLimit)); @@ -683,7 +683,7 @@ public static bool IsBasicLatin(this char c) { // Basic Latin characters are those with Unicode code points // in the range U+0000 to U+007F (inclusive) - return c >= '\u0000' && c <= '\u007F'; + return c is >= '\u0000' and <= '\u007F'; } public static string GetCharactersToLeftOfNewLine(ref string mainString, int index, int numberOfCharacters) diff --git a/Text-Grab/Utilities/SystemThemeUtility.cs b/Text-Grab/Utilities/SystemThemeUtility.cs index 9147419d..f9706875 100644 --- a/Text-Grab/Utilities/SystemThemeUtility.cs +++ b/Text-Grab/Utilities/SystemThemeUtility.cs @@ -1,10 +1,5 @@ -using Microsoft.Toolkit.Uwp.Notifications; -using Microsoft.Win32; +using Microsoft.Win32; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Text_Grab.Utilities; @@ -26,7 +21,7 @@ public static bool IsLightTheme() if (o.ToString() == "1") return true; - + return false; } catch (Exception) diff --git a/Text-Grab/Utilities/TesseractHelper.cs b/Text-Grab/Utilities/TesseractHelper.cs index fa01e2ee..8594ba31 100644 --- a/Text-Grab/Utilities/TesseractHelper.cs +++ b/Text-Grab/Utilities/TesseractHelper.cs @@ -30,7 +30,7 @@ public static class TesseractHelper private const string rawProgramsPath = @"%LOCALAPPDATA%\Programs\Tesseract-OCR\tesseract.exe"; private const string basicPath = @"C:\Program Files\Tesseract-OCR\tesseract.exe"; - private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; + private static readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; public static bool CanLocateTesseractExe() @@ -184,7 +184,7 @@ public static string TempImagePath() return $"{exePath}\\tempImage.png"; } - public async static Task> TesseractLanguagesAsStrings() + public static async Task> TesseractLanguagesAsStrings() { List languageStrings = new(); @@ -217,7 +217,7 @@ public async static Task> TesseractLanguagesAsStrings() return languageStrings; } - public async static Task> TesseractLanguages() + public static async Task> TesseractLanguages() { List languageStrings = await TesseractLanguagesAsStrings(); List tesseractLanguages = new(); diff --git a/Text-Grab/Utilities/WindowResizer.cs b/Text-Grab/Utilities/WindowResizer.cs index 86e07fc1..d2c793fd 100644 --- a/Text-Grab/Utilities/WindowResizer.cs +++ b/Text-Grab/Utilities/WindowResizer.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; @@ -41,7 +40,7 @@ public class WindowResizer /// /// The last calculated available screen size /// - private Rect mScreenSize = new Rect(); + private Rect mScreenSize = new(); /// /// How close to the edge the window has to be to be detected as at the edge of the screen @@ -69,13 +68,13 @@ public class WindowResizer [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] - static extern bool GetCursorPos(out POINT lpPoint); + private static extern bool GetCursorPos(out POINT lpPoint); [DllImport("user32.dll")] - static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); + private static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); [DllImport("user32.dll", SetLastError = true)] - static extern IntPtr MonitorFromPoint(POINT pt, MonitorOptions dwFlags); + private static extern IntPtr MonitorFromPoint(POINT pt, MonitorOptions dwFlags); #endregion @@ -122,7 +121,7 @@ public WindowResizer(Window window) private void GetTransform() { // Get the visual source - var source = PresentationSource.FromVisual(mWindow); + PresentationSource source = PresentationSource.FromVisual(mWindow); // Reset the transform to default mTransformToDevice = default(Matrix); @@ -143,8 +142,8 @@ private void GetTransform() private void Window_SourceInitialized(object? sender, System.EventArgs e) { // Get the handle of this window - var handle = (new WindowInteropHelper(mWindow)).Handle; - var handleSource = HwndSource.FromHwnd(handle); + nint handle = (new WindowInteropHelper(mWindow)).Handle; + HwndSource handleSource = HwndSource.FromHwnd(handle); // If not found, end if (handleSource == null) @@ -171,26 +170,26 @@ private void Window_SizeChanged(object sender, SizeChangedEventArgs e) return; // Get the WPF size - var size = e.NewSize; + Size size = e.NewSize; // Get window rectangle - var top = mWindow.Top; - var left = mWindow.Left; - var bottom = top + size.Height; - var right = left + mWindow.Width; + double top = mWindow.Top; + double left = mWindow.Left; + double bottom = top + size.Height; + double right = left + mWindow.Width; // Get window position/size in device pixels - var windowTopLeft = mTransformToDevice.Transform(new Point(left, top)); - var windowBottomRight = mTransformToDevice.Transform(new Point(right, bottom)); + Point windowTopLeft = mTransformToDevice.Transform(new Point(left, top)); + Point windowBottomRight = mTransformToDevice.Transform(new Point(right, bottom)); // Check for edges docked - var edgedTop = windowTopLeft.Y <= (mScreenSize.Top + mEdgeTolerance); - var edgedLeft = windowTopLeft.X <= (mScreenSize.Left + mEdgeTolerance); - var edgedBottom = windowBottomRight.Y >= (mScreenSize.Bottom - mEdgeTolerance); - var edgedRight = windowBottomRight.X >= (mScreenSize.Right - mEdgeTolerance); + bool edgedTop = windowTopLeft.Y <= (mScreenSize.Top + mEdgeTolerance); + bool edgedLeft = windowTopLeft.X <= (mScreenSize.Left + mEdgeTolerance); + bool edgedBottom = windowBottomRight.Y >= (mScreenSize.Bottom - mEdgeTolerance); + bool edgedRight = windowBottomRight.X >= (mScreenSize.Right - mEdgeTolerance); // Get docked position - var dock = WindowDockPosition.Undocked; + WindowDockPosition dock = WindowDockPosition.Undocked; // Left docking if (edgedTop && edgedBottom && edgedLeft) @@ -234,7 +233,7 @@ private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, re break; } - return (IntPtr)0; + return 0; } #endregion @@ -255,15 +254,15 @@ private void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) GetCursorPos(out lMousePosition); // Get the primary monitor at cursor position 0,0 - var lPrimaryScreen = MonitorFromPoint(new POINT(0, 0), MonitorOptions.MONITOR_DEFAULTTOPRIMARY); + nint lPrimaryScreen = MonitorFromPoint(new POINT(0, 0), MonitorOptions.MONITOR_DEFAULTTOPRIMARY); // Try and get the primary screen information - var lPrimaryScreenInfo = new MONITORINFO(); + MONITORINFO lPrimaryScreenInfo = new(); if (!GetMonitorInfo(lPrimaryScreen, lPrimaryScreenInfo)) return; // Now get the current screen - var lCurrentScreen = MonitorFromPoint(lMousePosition, MonitorOptions.MONITOR_DEFAULTTONEAREST); + nint lCurrentScreen = MonitorFromPoint(lMousePosition, MonitorOptions.MONITOR_DEFAULTTONEAREST); // If this has changed from the last one, update the transform if (lCurrentScreen != mLastScreen || mTransformToDevice == default(Matrix)) @@ -273,11 +272,11 @@ private void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) mLastScreen = lCurrentScreen; // Get min/max structure to fill with information - var lMmiTmp = (MINMAXINFO?)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); + MINMAXINFO? lMmiTmp = (MINMAXINFO?)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); if (lMmiTmp == null) return; - var lMmi = lMmiTmp.Value; + MINMAXINFO lMmi = lMmiTmp.Value; lMmi.ptMaxPosition.X = lPrimaryScreenInfo.rcWork.Left; lMmi.ptMaxPosition.Y = lPrimaryScreenInfo.rcWork.Top; @@ -285,7 +284,7 @@ private void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) lMmi.ptMaxSize.Y = lPrimaryScreenInfo.rcWork.Bottom - lPrimaryScreenInfo.rcWork.Top; // Set min size - var minSize = mTransformToDevice.Transform(new Point(mWindow.MinWidth, mWindow.MinHeight)); + Point minSize = mTransformToDevice.Transform(new Point(mWindow.MinWidth, mWindow.MinHeight)); lMmi.ptMinTrackSize.X = (int)minSize.X; lMmi.ptMinTrackSize.Y = (int)minSize.Y; @@ -300,7 +299,7 @@ private void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) #region Dll Helper Structures -enum MonitorOptions : uint +internal enum MonitorOptions : uint { MONITOR_DEFAULTTONULL = 0x00000000, MONITOR_DEFAULTTOPRIMARY = 0x00000001, @@ -312,8 +311,8 @@ enum MonitorOptions : uint public class MONITORINFO { public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); - public Rectangle rcMonitor = new Rectangle(); - public Rectangle rcWork = new Rectangle(); + public Rectangle rcMonitor = new(); + public Rectangle rcWork = new(); public int dwFlags = 0; } diff --git a/Text-Grab/Utilities/WindowUtilities.cs b/Text-Grab/Utilities/WindowUtilities.cs index eefae058..0210fc92 100644 --- a/Text-Grab/Utilities/WindowUtilities.cs +++ b/Text-Grab/Utilities/WindowUtilities.cs @@ -242,7 +242,7 @@ private static void TryInjectModifierKeyUp(ref List inputs, VirtualKeySho // Most significant bit is set if key is down if ((GetAsyncKeyState((int)modifier) & 0x8000) != 0) { - var inputEvent = default(INPUT); + INPUT inputEvent = default(INPUT); inputEvent.Type = OSInterop.InputType.INPUT_KEYBOARD; inputEvent.U.Ki.WVk = modifier; inputEvent.U.Ki.DwFlags = KEYEVENTF.KEYUP; @@ -299,7 +299,7 @@ public static void ShouldShutDown() if (shouldShutDown) Application.Current.Shutdown(); } - + public static bool GetMousePosition(out Point mousePosition) { if (GetCursorPos(out POINT point)) @@ -327,7 +327,7 @@ public static bool IsMouseInWindow(this Window window) [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] - static extern bool GetCursorPos(out POINT lpPoint); + private static extern bool GetCursorPos(out POINT lpPoint); #endregion } \ No newline at end of file diff --git a/Text-Grab/Views/EditTextWindow.xaml.cs b/Text-Grab/Views/EditTextWindow.xaml.cs index 3699d038..f6e1378a 100644 --- a/Text-Grab/Views/EditTextWindow.xaml.cs +++ b/Text-Grab/Views/EditTextWindow.xaml.cs @@ -50,7 +50,7 @@ public partial class EditTextWindow : Wpf.Ui.Controls.FluentWindow public static RoutedCommand UnstackCmd = new(); public static RoutedCommand UnstackGroupCmd = new(); public bool LaunchedFromNotification = false; - CancellationTokenSource? cancellationTokenForDirOCR; + private CancellationTokenSource? cancellationTokenForDirOCR; private string historyId = string.Empty; private int numberOfContextMenuItems; private string? OpenedFilePath; @@ -718,8 +718,8 @@ private void EditTextWindow_PreviewKeyDown(object sender, System.Windows.Input.K // D9 is 43 // D0 is 34 - if (keyNumberPressed < -1 - || keyNumberPressed > 8) + if (keyNumberPressed is < (-1) + or > 8) return; // since D9 is next to D0 it makes sense @@ -894,8 +894,8 @@ private void InsertSelectionOnEveryLine(object? sender = null, ExecutedRoutedEve int selectionPositionInLine = PassedTextControl.SelectionStart; for (int i = initialSelectionStart; i >= 0; i--) { - if (PassedTextControl.Text[i] == '\n' - || PassedTextControl.Text[i] == '\r') + if (PassedTextControl.Text[i] is '\n' + or '\r') { selectionPositionInLine = initialSelectionStart - i - 1; break; @@ -1184,7 +1184,7 @@ private void DuplicateSelectedLine(object sender, ExecutedRoutedEventArgs e) SelectLine(); string lineText = PassedTextControl.SelectedText; bool lineEndsInNewLine = lineText.EndsWithNewline(); - PassedTextControl.SelectedText = $"{ lineText}{(lineEndsInNewLine ? "" : Environment.NewLine)}{ lineText}"; + PassedTextControl.SelectedText = $"{lineText}{(lineEndsInNewLine ? "" : Environment.NewLine)}{lineText}"; int length = lineText.Length; if (!lineEndsInNewLine) length += Environment.NewLine.Length; @@ -2101,12 +2101,12 @@ private void WrapTextCHBOX_Checked(object sender, RoutedEventArgs e) if (!IsLoaded) return; - if ((bool)WrapTextMenuItem.IsChecked) + if (WrapTextMenuItem.IsChecked) PassedTextControl.TextWrapping = TextWrapping.Wrap; else PassedTextControl.TextWrapping = TextWrapping.NoWrap; - DefaultSettings.EditWindowIsWordWrapOn = (bool)WrapTextMenuItem.IsChecked; + DefaultSettings.EditWindowIsWordWrapOn = WrapTextMenuItem.IsChecked; } #endregion Methods } diff --git a/Text-Grab/Views/FirstRunWindow.xaml.cs b/Text-Grab/Views/FirstRunWindow.xaml.cs index 6c4cf31d..b4b4f78b 100644 --- a/Text-Grab/Views/FirstRunWindow.xaml.cs +++ b/Text-Grab/Views/FirstRunWindow.xaml.cs @@ -113,7 +113,7 @@ private void OkayButton_Click(object sender, RoutedEventArgs e) { int windowsCount = Application.Current.Windows.Count; - if (windowsCount == 2 || windowsCount == 1) + if (windowsCount is 2 or 1) { TextGrabMode defaultLaunchSetting = Enum.Parse(DefaultSettings.DefaultLaunch, true); switch (defaultLaunchSetting) diff --git a/Text-Grab/Views/FullscreenGrab.xaml.cs b/Text-Grab/Views/FullscreenGrab.xaml.cs index 84557286..7087ae44 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml.cs +++ b/Text-Grab/Views/FullscreenGrab.xaml.cs @@ -39,8 +39,8 @@ public partial class FullscreenGrab : Window private double xShiftDelta; private double yShiftDelta; private HistoryInfo? historyInfo; - bool usingTesseract; - private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; + private bool usingTesseract; + private static readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; #endregion Fields @@ -232,7 +232,7 @@ private async void FreezeUnfreeze(bool Activate) RegionClickCanvas.ContextMenu.IsOpen = false; await Task.Delay(150); SetImageToBackground(); - + if (this.IsMouseInWindow()) TopButtonsStackPanel.Visibility = Visibility.Visible; } diff --git a/Text-Grab/Views/GrabFrame.xaml.cs b/Text-Grab/Views/GrabFrame.xaml.cs index b6529676..2a37b046 100644 --- a/Text-Grab/Views/GrabFrame.xaml.cs +++ b/Text-Grab/Views/GrabFrame.xaml.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Linq.Expressions; using System.Runtime.InteropServices; using System.Text; using System.Text.Json; @@ -72,7 +71,7 @@ public partial class GrabFrame : Window private bool wasAltHeld = false; private double windowFrameImageScale = 1; private ObservableCollection wordBorders = new(); - private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; + private static readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; private ScrollBehavior scrollBehavior = ScrollBehavior.Resize; #endregion Fields @@ -1363,7 +1362,7 @@ private void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e) // Source: StackOverflow, read on Sep. 10, 2021 // https://stackoverflow.com/a/53698638/7438031 - if (WindowState == WindowState.Maximized + if (WindowState == WindowState.Maximized || scrollBehavior == ScrollBehavior.None) return; diff --git a/Text-Grab/Views/QuickSimpleLookup.xaml.cs b/Text-Grab/Views/QuickSimpleLookup.xaml.cs index c5045ca7..0b85f879 100644 --- a/Text-Grab/Views/QuickSimpleLookup.xaml.cs +++ b/Text-Grab/Views/QuickSimpleLookup.xaml.cs @@ -30,7 +30,7 @@ public partial class QuickSimpleLookup : Wpf.Ui.Controls.FluentWindow private LookupItem? lastSelection; private int rowCount = 0; private string valueUnderEdit = string.Empty; - private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; + private static readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; #endregion Fields @@ -57,12 +57,12 @@ public QuickSimpleLookup() private static LookupItem ParseStringToLookupItem(char splitChar, string row) { List cells = row.Split(splitChar).ToList(); - LookupItem newRow = new LookupItem(); + LookupItem newRow = new(); if (cells.FirstOrDefault() is String firstCell) newRow.shortValue = firstCell; newRow.longValue = ""; - if (cells.Count > 1 && cells[1] is String) + if (cells.Count > 1 && cells[1] is not null) newRow.longValue = String.Join(" ", cells.Skip(1).ToArray()); return newRow; } @@ -186,9 +186,7 @@ private void FluentWindow_Closed(object sender, EventArgs e) private List GetMainDataGridSelection() { - var selectedItems = MainDataGrid.SelectedItems as List; - - if (selectedItems is null || selectedItems.Count == 0) + if (MainDataGrid.SelectedItems is not List selectedItems || selectedItems.Count == 0) { selectedItems = new List(); if (MainDataGrid.SelectedItem is not LookupItem selectedLookupItem) @@ -236,7 +234,7 @@ private void MainDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEv if (e.EditAction == DataGridEditAction.Cancel) return; - var child = VisualTreeHelper.GetChild(e.EditingElement, 0); + DependencyObject child = VisualTreeHelper.GetChild(e.EditingElement, 0); if (child is TextBox editedBox && valueUnderEdit != editedBox.Text) { @@ -283,7 +281,7 @@ private void ParseBTN_Click(object sender, RoutedEventArgs e) private async void ParseCSVFileMenuItem_Click(object sender, RoutedEventArgs e) { // Create OpenFileDialog - Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog(); + Microsoft.Win32.OpenFileDialog dlg = new(); // Set filter for file extension and default file extension dlg.DefaultExt = ".csv"; @@ -324,7 +322,7 @@ private async void PickSaveLocation_Click(object sender, RoutedEventArgs e) dlg.FileName = Path.GetFileName(DefaultSettings.LookupFileLocation); } - var result = dlg.ShowDialog(); + bool? result = dlg.ShowDialog(); if (result is false) return; @@ -399,7 +397,7 @@ private async void PutValueIntoClipboard(KeyboardModifiersDown? keysDown = null) if (selectedLookupItems.FirstOrDefault() is not LookupItem lookupItem) return; - if (Uri.TryCreate(lookupItem.longValue, UriKind.Absolute, out var uri)) + if (Uri.TryCreate(lookupItem.longValue, UriKind.Absolute, out Uri? uri)) { Process.Start(new ProcessStartInfo(lookupItem.longValue) { UseShellExecute = true }); this.Close(); @@ -567,7 +565,7 @@ private async Task ReadCsvFileIntoQuickSimpleLookup(string csvToOpenPath) private void RowDeleted() { - var currentItemSource = MainDataGrid.ItemsSource; + System.Collections.IEnumerable currentItemSource = MainDataGrid.ItemsSource; if (currentItemSource is not List filteredLookupList) return; @@ -652,14 +650,14 @@ private async void SearchBox_TextChanged(object sender, TextChangedEventArgs e) List searchArray = SearchBox.Text.ToLower().Split().ToList(); searchArray.Sort(); - List filteredList = new List(); + List filteredList = new(); foreach (LookupItem lItem in ItemsDictionary) { string lItemAsString = lItem.ToString().ToLower(); bool matchAllSearchWords = true; - foreach (var searchWord in searchArray) + foreach (string searchWord in searchArray) { if (!lItemAsString.Contains(searchWord)) matchAllSearchWords = false; diff --git a/Text-Grab/WPFExtensionMethods.cs b/Text-Grab/WPFExtensionMethods.cs index cdb79b79..8c3f6a0b 100644 --- a/Text-Grab/WPFExtensionMethods.cs +++ b/Text-Grab/WPFExtensionMethods.cs @@ -1,10 +1,9 @@ using System; +using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; -using System.Runtime.InteropServices; - -static class WPFExtensionMethods +internal static class WPFExtensionMethods { public static Point GetAbsolutePosition(this Window w) { @@ -15,15 +14,15 @@ public static Point GetAbsolutePosition(this Window w) bool multimonSupported = OSInterop.GetSystemMetrics(OSInterop.SM_CMONITORS) != 0; if (!multimonSupported) { - OSInterop.RECT rc = new OSInterop.RECT(); + OSInterop.RECT rc = new(); OSInterop.SystemParametersInfo(48, 0, ref rc, 0); r = new Int32Rect(rc.left, rc.top, rc.width, rc.height); } else { - WindowInteropHelper helper = new WindowInteropHelper(w); + WindowInteropHelper helper = new(w); IntPtr hmonitor = OSInterop.MonitorFromWindow(new HandleRef(null, helper.EnsureHandle()), 2); - OSInterop.MONITORINFOEX info = new OSInterop.MONITORINFOEX(); + OSInterop.MONITORINFOEX info = new(); OSInterop.GetMonitorInfo(new HandleRef(null, hmonitor), info); r = new Int32Rect(info.rcMonitor.left, info.rcMonitor.top, info.rcMonitor.width, info.rcMonitor.height); } From 93f7adb5912ceb228887c8d06423139e2f8030ba Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sun, 13 Oct 2024 21:02:38 -0500 Subject: [PATCH 11/30] Update packages and WinSDK Package version --- Tests/Tests.csproj | 2 +- Text-Grab/Text-Grab.csproj | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index a982867c..e199dd04 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -10,7 +10,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Text-Grab/Text-Grab.csproj b/Text-Grab/Text-Grab.csproj index 258c20d8..8efc6bd0 100644 --- a/Text-Grab/Text-Grab.csproj +++ b/Text-Grab/Text-Grab.csproj @@ -3,6 +3,7 @@ WinExe net8.0-windows10.0.20348.0 + 10.0.20348.48 Text_Grab enable true @@ -68,9 +69,9 @@ - + - + From 4a2ab969c1f7f6cec2834b2d2268d7e01fdd76c8 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sun, 27 Oct 2024 21:25:26 -0500 Subject: [PATCH 12/30] Update packages --- Tests/Tests.csproj | 2 +- Text-Grab/Text-Grab.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index e199dd04..c72a359a 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -11,7 +11,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Text-Grab/Text-Grab.csproj b/Text-Grab/Text-Grab.csproj index 8efc6bd0..84352a5b 100644 --- a/Text-Grab/Text-Grab.csproj +++ b/Text-Grab/Text-Grab.csproj @@ -67,7 +67,7 @@ - + From 8eceb005884985f8e82e9beb13c909c59b1eaed8 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sun, 27 Oct 2024 21:40:35 -0500 Subject: [PATCH 13/30] Add split after command in ETW --- Text-Grab/Views/EditTextWindow.xaml | 8 ++++++++ Text-Grab/Views/EditTextWindow.xaml.cs | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/Text-Grab/Views/EditTextWindow.xaml b/Text-Grab/Views/EditTextWindow.xaml index 5176c32b..31482b5a 100644 --- a/Text-Grab/Views/EditTextWindow.xaml +++ b/Text-Grab/Views/EditTextWindow.xaml @@ -75,6 +75,10 @@ CanExecute="SplitOnSelectionCmdCanExecute" Command="{x:Static local:EditTextWindow.SplitOnSelectionCmd}" Executed="SplitOnSelectionCmdExecuted" /> + + Date: Sun, 27 Oct 2024 22:48:52 -0500 Subject: [PATCH 14/30] Add GUID correction method --- Tests/Images/GUIDs.png | Bin 0 -> 63668 bytes Tests/StringMethodTests.cs | 35 ++++++++++++++++++++++++- Text-Grab/Utilities/StringMethods.cs | 19 ++++++++++++++ Text-Grab/Views/EditTextWindow.xaml | 4 +++ Text-Grab/Views/EditTextWindow.xaml.cs | 12 +++++++++ 5 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 Tests/Images/GUIDs.png diff --git a/Tests/Images/GUIDs.png b/Tests/Images/GUIDs.png new file mode 100644 index 0000000000000000000000000000000000000000..2146bfad3493bb6bb3340cd7645dd247adf1d617 GIT binary patch literal 63668 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
A>+strlGiov^QlUK7E(Y^DhwDPwbWy)3kc8Z=2 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
gC}YKhnCa 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 GuidCorrections = new() + { + {'o', '0'}, {'O', '0'}, {'i', '1'}, {'l', '1'}, {'I', '1'}, + {'h', '4'}, {'z', '2'}, {'Z', '2'}, {'g', '9'}, {'G', '9'}, + {'s', '5'}, {'S', '5'}, {'Ø', '0'}, {'#', 'f'}, {'@', '0'}, + {'Q', '0'}, {'¥', 'f'}, {'£', 'f'}, {'/', '7'} + }; + public static string ReplaceWithDictionary(this string str, Dictionary dict) { StringBuilder sb = new(); @@ -74,6 +82,17 @@ public static string ReplaceGreekOrCyrillicWithLatin(this string str) return str.ReplaceWithDictionary(GreekCyrillicLatinMap); } + public static string CorrectCommonGuidErrors(this string guid) + { + // remove all spaces + guid = guid.Replace(" ", ""); + // if a line ends with a dash remove the newline after the dash + guid = guid.Replace("-\r\n", "-"); + // if a line begins with a dash remove the newline before the dash + guid = guid.Replace("\r\n-", "-"); + return guid.ReplaceWithDictionary(GuidCorrections); + } + public static IEnumerable AllIndexesOf(this string str, string searchString) { int minIndex = str.IndexOf(searchString); diff --git a/Text-Grab/Views/EditTextWindow.xaml b/Text-Grab/Views/EditTextWindow.xaml index 31482b5a..7414d604 100644 --- a/Text-Grab/Views/EditTextWindow.xaml +++ b/Text-Grab/Views/EditTextWindow.xaml @@ -215,6 +215,10 @@ x:Name="TryToAlphaMenuItem" Click="TryToAlphaMenuItem_Click" Header="Try To Make _Letters" /> + Date: Thu, 7 Nov 2024 22:29:36 -0600 Subject: [PATCH 15/30] Add web search actions --- Text-Grab/Views/EditTextWindow.xaml | 24 +++++++++++++++++++++ Text-Grab/Views/EditTextWindow.xaml.cs | 30 +++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Text-Grab/Views/EditTextWindow.xaml b/Text-Grab/Views/EditTextWindow.xaml index 7414d604..85b4aa98 100644 --- a/Text-Grab/Views/EditTextWindow.xaml +++ b/Text-Grab/Views/EditTextWindow.xaml @@ -127,6 +127,18 @@ CanExecute="MakeQrCodeCanExecute" Command="{x:Static local:EditTextWindow.MakeQrCodeCmd}" Executed="MakeQrCodeExecuted" /> + + + @@ -252,6 +264,18 @@ x:Name="FindAndReplaceMenuItem" Click="FindAndReplaceMenuItem_Click" Header="Find and Replace" /> + + + GetRoutedCommands() {nameof(DeleteAllSelectionPatternCmd), DeleteAllSelectionPatternCmd}, {nameof(InsertSelectionOnEveryLineCmd), InsertSelectionOnEveryLineCmd}, {nameof(OcrPasteCommand), OcrPasteCommand}, - {nameof(MakeQrCodeCmd), MakeQrCodeCmd} + {nameof(MakeQrCodeCmd), MakeQrCodeCmd}, + {nameof(GoogleSearchCmd), GoogleSearchCmd}, + {nameof(BingSearchCmd), BingSearchCmd}, + {nameof(DuckDuckGoSearchCmd), DuckDuckGoSearchCmd} }; } @@ -958,6 +965,27 @@ private void IsolateSelectionCmdExecuted(object sender, ExecutedRoutedEventArgs PassedTextControl.Text = PassedTextControl.SelectedText; } + private async void GoogleSearchExecuted(object sender, ExecutedRoutedEventArgs e) + { + string possibleSearch = PassedTextControl.SelectedText; + string searchStringUrlSafe = WebUtility.UrlEncode(possibleSearch); + _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://www.google.com/search?q={searchStringUrlSafe}"))); + } + + private async void BingSearchExecuted(object sender, ExecutedRoutedEventArgs e) + { + string possibleSearch = PassedTextControl.SelectedText; + string searchStringUrlSafe = WebUtility.UrlEncode(possibleSearch); + _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://www.bing.com/search?q={searchStringUrlSafe}"))); + } + + private async void DuckDuckGoSearchExecuted(object sender, ExecutedRoutedEventArgs e) + { + string possibleSearch = PassedTextControl.SelectedText; + string searchStringUrlSafe = WebUtility.UrlEncode(possibleSearch); + _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://duckduckgo.com/?va=d&t=he&q={searchStringUrlSafe}&ia=web"))); + } + private void keyedCtrlF(object sender, ExecutedRoutedEventArgs e) { WindowUtilities.LaunchFullScreenGrab(PassedTextControl); From 092129a66bc4eb32e2d37fcb699a88e8cd440132 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Thu, 7 Nov 2024 22:37:48 -0600 Subject: [PATCH 16/30] Add web searches to bottom bar options --- Text-Grab/Models/ButtonInfo.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Text-Grab/Models/ButtonInfo.cs b/Text-Grab/Models/ButtonInfo.cs index c9cdc626..1835865f 100644 --- a/Text-Grab/Models/ButtonInfo.cs +++ b/Text-Grab/Models/ButtonInfo.cs @@ -198,6 +198,30 @@ public ButtonInfo(string buttonText, string symbolText, string background, strin SymbolIcon = SymbolRegular.Search24 }, new() + { + OrderNumber = 1.7, + ButtonText = "Google...", + SymbolText = "", + Command = "GoogleSearchCmd", + SymbolIcon = SymbolRegular.GlobeSearch24 + }, + new() + { + OrderNumber = 1.8, + ButtonText = "Bing...", + SymbolText = "", + Command = "BingSearchCmd", + SymbolIcon = SymbolRegular.GlobeSearch24 + }, + new() + { + OrderNumber = 1.8, + ButtonText = "Duck Duck Go...", + SymbolText = "", + Command = "DuckDuckGoSearchCmd", + SymbolIcon = SymbolRegular.GlobeSearch24 + }, + new() { OrderNumber = 2.1, ButtonText = "Open Settings", From a76869ebd68daa2a31173eb069ad5e6fa9f2a49b Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Thu, 7 Nov 2024 22:57:12 -0600 Subject: [PATCH 17/30] Initial work on basic word count --- Text-Grab/Utilities/StringMethods.cs | 16 ++++++++++++++++ Text-Grab/Views/EditTextWindow.xaml.cs | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Text-Grab/Utilities/StringMethods.cs b/Text-Grab/Utilities/StringMethods.cs index 79ce69c8..11c162c5 100644 --- a/Text-Grab/Utilities/StringMethods.cs +++ b/Text-Grab/Utilities/StringMethods.cs @@ -767,4 +767,20 @@ public static bool EndsWithNewline(this string s) { return Regex.IsMatch(s, @"\n$"); } + + public static string RemoveNonWordChars(this string strIn) + { + // Replace invalid characters with empty strings. + try + { + return Regex.Replace(strIn, @"[^\w\s]", "", + RegexOptions.None, TimeSpan.FromSeconds(5)); + } + // If we timeout when replacing invalid characters, + // we should return Empty. + catch (RegexMatchTimeoutException) + { + return String.Empty; + } + } } diff --git a/Text-Grab/Views/EditTextWindow.xaml.cs b/Text-Grab/Views/EditTextWindow.xaml.cs index da033e65..093e3306 100644 --- a/Text-Grab/Views/EditTextWindow.xaml.cs +++ b/Text-Grab/Views/EditTextWindow.xaml.cs @@ -2046,17 +2046,21 @@ private void UnstackGroupExecuted(object? sender = null, ExecutedRoutedEventArgs private void UpdateLineAndColumnText() { + char[] delimiters = [' ', '\r', '\n']; + if (PassedTextControl.SelectionLength < 1) { int lineNumber = PassedTextControl.GetLineIndexFromCharacterIndex(PassedTextControl.CaretIndex); int columnNumber = PassedTextControl.CaretIndex - PassedTextControl.GetCharacterIndexFromLineIndex(lineNumber); + int words = PassedTextControl.Text.RemoveNonWordChars().Split(delimiters, StringSplitOptions.RemoveEmptyEntries).Length; - BottomBarText.Text = $"Ln {lineNumber + 1}, Col {columnNumber}"; + BottomBarText.Text = $"Wrds {words}, Ln {lineNumber + 1}, Col {columnNumber}"; } else { int selectionStartIndex = PassedTextControl.SelectionStart; int selectionStopIndex = PassedTextControl.SelectionStart + PassedTextControl.SelectionLength; + int words = PassedTextControl.Text.Split(delimiters, StringSplitOptions.RemoveEmptyEntries).Length; int selStartLine = PassedTextControl.GetLineIndexFromCharacterIndex(selectionStartIndex); From 084015401f6a289297c14df5d46633cf3de6f386 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Mon, 11 Nov 2024 21:34:55 -0600 Subject: [PATCH 18/30] Add back in using windows forms because it was never really removed --- Text-Grab/Text-Grab.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Text-Grab/Text-Grab.csproj b/Text-Grab/Text-Grab.csproj index 84352a5b..757c06f9 100644 --- a/Text-Grab/Text-Grab.csproj +++ b/Text-Grab/Text-Grab.csproj @@ -7,6 +7,7 @@ Text_Grab enable true + true false TealSelect.ico Text_Grab.App From c15fbcaea02bee67bfa1b0961e9c094a83d5d095 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Mon, 11 Nov 2024 21:35:03 -0600 Subject: [PATCH 19/30] Add Search GitHub button --- Text-Grab/Models/ButtonInfo.cs | 10 +++++++++- Text-Grab/Views/EditTextWindow.xaml | 8 ++++++++ Text-Grab/Views/EditTextWindow.xaml.cs | 11 ++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Text-Grab/Models/ButtonInfo.cs b/Text-Grab/Models/ButtonInfo.cs index 1835865f..3f7cdab2 100644 --- a/Text-Grab/Models/ButtonInfo.cs +++ b/Text-Grab/Models/ButtonInfo.cs @@ -215,13 +215,21 @@ public ButtonInfo(string buttonText, string symbolText, string background, strin }, new() { - OrderNumber = 1.8, + OrderNumber = 1.9, ButtonText = "Duck Duck Go...", SymbolText = "", Command = "DuckDuckGoSearchCmd", SymbolIcon = SymbolRegular.GlobeSearch24 }, new() + { + OrderNumber = 1.91, + ButtonText = "Search GitHub...", + SymbolText = "", + Command = "GitHubSearchCmd", + SymbolIcon = SymbolRegular.GlobeSearch24 + }, + new() { OrderNumber = 2.1, ButtonText = "Open Settings", diff --git a/Text-Grab/Views/EditTextWindow.xaml b/Text-Grab/Views/EditTextWindow.xaml index 85b4aa98..cf95f750 100644 --- a/Text-Grab/Views/EditTextWindow.xaml +++ b/Text-Grab/Views/EditTextWindow.xaml @@ -139,6 +139,10 @@ CanExecute="IsolateSelectionCmdCanExecute" Command="{x:Static local:EditTextWindow.DuckDuckGoSearchCmd}" Executed="DuckDuckGoSearchExecuted" /> + @@ -276,6 +280,10 @@ x:Name="DuckSearchMenuItem" Command="{x:Static local:EditTextWindow.DuckDuckGoSearchCmd}" Header="_Duck Duck Go Selection..." /> + GetRoutedCommands() {nameof(MakeQrCodeCmd), MakeQrCodeCmd}, {nameof(GoogleSearchCmd), GoogleSearchCmd}, {nameof(BingSearchCmd), BingSearchCmd}, - {nameof(DuckDuckGoSearchCmd), DuckDuckGoSearchCmd} + {nameof(DuckDuckGoSearchCmd), DuckDuckGoSearchCmd}, + {nameof(GitHubSearchCmd), GitHubSearchCmd}, }; } @@ -986,6 +988,13 @@ private async void DuckDuckGoSearchExecuted(object sender, ExecutedRoutedEventAr _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://duckduckgo.com/?va=d&t=he&q={searchStringUrlSafe}&ia=web"))); } + private async void GitHubSearchExecuted(object sender, ExecutedRoutedEventArgs e) + { + string possibleSearch = PassedTextControl.SelectedText; + string searchStringUrlSafe = WebUtility.UrlEncode(possibleSearch); + _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://github.com/search?q={searchStringUrlSafe}"))); + } + private void keyedCtrlF(object sender, ExecutedRoutedEventArgs e) { WindowUtilities.LaunchFullScreenGrab(PassedTextControl); From fa5ba1da5972d687c7fa0fb2330f3777b97f93cd Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Mon, 11 Nov 2024 21:49:53 -0600 Subject: [PATCH 20/30] Update version --- Text-Grab-Package/Package.appxmanifest | 2 +- Text-Grab-Package/Text-Grab-Package.wapproj | 2 +- Text-Grab/Pages/GeneralSettings.xaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Text-Grab-Package/Package.appxmanifest b/Text-Grab-Package/Package.appxmanifest index 1955af12..d8206dcf 100644 --- a/Text-Grab-Package/Package.appxmanifest +++ b/Text-Grab-Package/Package.appxmanifest @@ -11,7 +11,7 @@ + Version="4.6.0.0" /> Text Grab diff --git a/Text-Grab-Package/Text-Grab-Package.wapproj b/Text-Grab-Package/Text-Grab-Package.wapproj index d6b6e0c3..fa97345d 100644 --- a/Text-Grab-Package/Text-Grab-Package.wapproj +++ b/Text-Grab-Package/Text-Grab-Package.wapproj @@ -63,7 +63,7 @@ SHA256 False True - x86|x64 + x86|x64|arm64 0 diff --git a/Text-Grab/Pages/GeneralSettings.xaml b/Text-Grab/Pages/GeneralSettings.xaml index 17d06dbd..ae144ccf 100644 --- a/Text-Grab/Pages/GeneralSettings.xaml +++ b/Text-Grab/Pages/GeneralSettings.xaml @@ -27,7 +27,7 @@ x:Name="VersionTextblock" VerticalAlignment="Center" Style="{StaticResource TextBodyNormal}" - Text="Version 4.5.1" /> + Text="Version 4.6.0" /> Date: Wed, 13 Nov 2024 21:28:26 -0600 Subject: [PATCH 21/30] update package --- Text-Grab/Text-Grab.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Text-Grab/Text-Grab.csproj b/Text-Grab/Text-Grab.csproj index 757c06f9..710271a8 100644 --- a/Text-Grab/Text-Grab.csproj +++ b/Text-Grab/Text-Grab.csproj @@ -72,7 +72,7 @@ - + From 4985c6b6f382ae9914d46012c053284bbd806fe4 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 20 Nov 2024 22:39:13 -0600 Subject: [PATCH 22/30] Update packages --- Tests/Tests.csproj | 2 +- Text-Grab-Package/Text-Grab-Package.wapproj | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index c72a359a..e5b17420 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -9,7 +9,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Text-Grab-Package/Text-Grab-Package.wapproj b/Text-Grab-Package/Text-Grab-Package.wapproj index fa97345d..ccba0d23 100644 --- a/Text-Grab-Package/Text-Grab-Package.wapproj +++ b/Text-Grab-Package/Text-Grab-Package.wapproj @@ -161,5 +161,10 @@ True + + + + + \ No newline at end of file From f0d62abc7fdb8fcd195a2bd0b21768c725699160 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 20 Nov 2024 23:07:29 -0600 Subject: [PATCH 23/30] Add initial idea of post capture actions --- Text-Grab/Views/FullscreenGrab.xaml | 25 +++++++++++++++++++ Text-Grab/Views/FullscreenGrab.xaml.cs | 34 ++++++++++++++------------ 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Text-Grab/Views/FullscreenGrab.xaml b/Text-Grab/Views/FullscreenGrab.xaml index 63fa6daa..dc73238d 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml +++ b/Text-Grab/Views/FullscreenGrab.xaml @@ -222,6 +222,31 @@ + + + + + + + + + + + + (); - destinationTextBox = etw.PassedTextControl; - } - - OutputUtilities.HandleTextFromOcr( - TextFromOCR, - isSingleLine, - isTable, - destinationTextBox); - WindowUtilities.CloseAllFullscreenGrabs(); - } - else + if (string.IsNullOrWhiteSpace(TextFromOCR)) { BackgroundBrush.Opacity = .2; TopButtonsStackPanel.Visibility = Visibility.Visible; + return; } + + if (GuidFixMenuItem.IsChecked is true) + TextFromOCR = TextFromOCR.CorrectCommonGuidErrors(); + + if (SendToEditTextToggleButton.IsChecked is true && destinationTextBox is null) + { + EditTextWindow etw = WindowUtilities.OpenOrActivateWindow(); + destinationTextBox = etw.PassedTextControl; + } + + OutputUtilities.HandleTextFromOcr( + TextFromOCR, + isSingleLine, + isTable, + destinationTextBox); + WindowUtilities.CloseAllFullscreenGrabs(); } private void SendToEditTextToggleButton_Click(object sender, RoutedEventArgs e) From 73c644dea967638f0f094456f66490ce1e76f77c Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 20 Nov 2024 23:13:43 -0600 Subject: [PATCH 24/30] Add Bing search as a post action --- Text-Grab/Views/FullscreenGrab.xaml | 3 ++- Text-Grab/Views/FullscreenGrab.xaml.cs | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Text-Grab/Views/FullscreenGrab.xaml b/Text-Grab/Views/FullscreenGrab.xaml index dc73238d..c1e8c3a4 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml +++ b/Text-Grab/Views/FullscreenGrab.xaml @@ -237,7 +237,8 @@ IsCheckable="True" StaysOpenOnClick="True" /> (); destinationTextBox = etw.PassedTextControl; From 917f055c085ee3291f6c6ee4b7dba16236c0c8b9 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Thu, 28 Nov 2024 10:20:24 -0500 Subject: [PATCH 25/30] Add ctrl shortcut to ETW bottom bar buttons --- Text-Grab/Utilities/CustomBottomBarUtilities.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Text-Grab/Utilities/CustomBottomBarUtilities.cs b/Text-Grab/Utilities/CustomBottomBarUtilities.cs index 90293561..a070db7b 100644 --- a/Text-Grab/Utilities/CustomBottomBarUtilities.cs +++ b/Text-Grab/Utilities/CustomBottomBarUtilities.cs @@ -71,6 +71,8 @@ public static List GetBottomBarButtons(EditTextWindow editTex List methods = GetMethods(editTextWindow); Dictionary routedCommands = EditTextWindow.GetRoutedCommands(); + int index = 1; + foreach (ButtonInfo buttonItem in GetCustomBottomBarItemsSetting()) { CollapsibleButton button = new() @@ -78,7 +80,7 @@ public static List GetBottomBarButtons(EditTextWindow editTex ButtonText = buttonItem.ButtonText, IsSymbol = buttonItem.IsSymbol, CustomButton = buttonItem, - ToolTip = buttonItem.ButtonText, + ToolTip = $"{buttonItem.ButtonText} (ctrl + {index})", ButtonSymbol = buttonItem.SymbolIcon }; @@ -97,6 +99,7 @@ public static List GetBottomBarButtons(EditTextWindow editTex button.Command = routedCommand; bottomBarButtons.Add(button); + index++; } return bottomBarButtons; From eaaad2e962d54a639c0c05a1583796fa711a0b93 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sun, 1 Dec 2024 16:10:42 -0600 Subject: [PATCH 26/30] Use ctrl + num to enable post grab actions --- Text-Grab/Views/FullscreenGrab.xaml | 18 ++++++++++---- Text-Grab/Views/FullscreenGrab.xaml.cs | 34 +++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Text-Grab/Views/FullscreenGrab.xaml b/Text-Grab/Views/FullscreenGrab.xaml index c1e8c3a4..fb1559e8 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml +++ b/Text-Grab/Views/FullscreenGrab.xaml @@ -225,26 +225,34 @@ + Margin="2,0" + Background="{StaticResource Teal}" + IsDefault="True"> - + + StaysOpenOnClick="False" /> + StaysOpenOnClick="False" /> + StaysOpenOnClick="False" /> diff --git a/Text-Grab/Views/FullscreenGrab.xaml.cs b/Text-Grab/Views/FullscreenGrab.xaml.cs index 5f36f238..15b2c40d 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml.cs +++ b/Text-Grab/Views/FullscreenGrab.xaml.cs @@ -183,8 +183,23 @@ internal void KeyPressed(Key key, bool? isActive = null) case Key.D8: case Key.D9: int numberPressed = (int)key - 34; // D1 casts to 35, D2 to 36, etc. - int numberOfLanguages = LanguagesComboBox.Items.Count; + if (KeyboardExtensions.IsCtrlDown()) + { + if (NextStepDropDownButton.Flyout is not ContextMenu flyoutMenu + || !flyoutMenu.HasItems + || numberPressed - 1 >= flyoutMenu.Items.Count + || flyoutMenu.Items[numberPressed - 1] is not MenuItem selectedItem) + { + return; + } + + selectedItem.IsChecked = !selectedItem.IsChecked; + CheckIfAnyPostActionsSelcted(); + return; + } + + int numberOfLanguages = LanguagesComboBox.Items.Count; if (numberPressed <= numberOfLanguages && numberPressed - 1 >= 0 && numberPressed - 1 != LanguagesComboBox.SelectedIndex @@ -196,6 +211,23 @@ internal void KeyPressed(Key key, bool? isActive = null) } } + private void CheckIfAnyPostActionsSelcted() + { + if (NextStepDropDownButton.Flyout is not ContextMenu flyoutMenu || !flyoutMenu.HasItems) + return; + + foreach (MenuItem item in flyoutMenu.Items) + { + if (item.IsChecked) + { + NextStepDropDownButton.Background = new SolidColorBrush(Colors.LightGreen); + return; + } + } + + NextStepDropDownButton.Background = new SolidColorBrush(Colors.Black); + } + private static bool CheckIfCheckingOrUnchecking(object? sender) { bool isActive = false; From d618630dc1467060761ca1b4a37842ee254e4daa Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sun, 1 Dec 2024 18:25:43 -0600 Subject: [PATCH 27/30] Catch IndexOutOfRangeEx when picking word bound --- Text-Grab/Utilities/StringMethods.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Text-Grab/Utilities/StringMethods.cs b/Text-Grab/Utilities/StringMethods.cs index 11c162c5..d9a7b39e 100644 --- a/Text-Grab/Utilities/StringMethods.cs +++ b/Text-Grab/Utilities/StringMethods.cs @@ -122,6 +122,15 @@ public static (int, int) CursorWordBoundaries(this string input, int cursorPosit if (cursorPosition < 0) cursorPosition = 0; + try + { + char check = input[cursorPosition]; + } + catch (IndexOutOfRangeException) + { + return (cursorPosition, 0); + } + // Check if the cursor is at a space if (char.IsWhiteSpace(input[cursorPosition])) cursorPosition = FindNearestLetterIndex(input, cursorPosition); From 436edeae1982ebe67d41f904d2785ec6d683a875 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sun, 1 Dec 2024 18:25:54 -0600 Subject: [PATCH 28/30] Add more post capture actions --- Text-Grab/Views/FullscreenGrab.xaml | 28 +++++++++++++++++++----- Text-Grab/Views/FullscreenGrab.xaml.cs | 30 ++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/Text-Grab/Views/FullscreenGrab.xaml b/Text-Grab/Views/FullscreenGrab.xaml index fb1559e8..52136ac5 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml +++ b/Text-Grab/Views/FullscreenGrab.xaml @@ -226,8 +226,8 @@ x:Name="NextStepDropDownButton" Height="34" Margin="2,0" - Background="{StaticResource Teal}" - IsDefault="True"> + IsDefault="True" + ToolTip="Actions to perform after grabbing text..."> @@ -238,21 +238,39 @@ PreviewKeyDown="FullscreenGrab_KeyDown"> + + diff --git a/Text-Grab/Views/FullscreenGrab.xaml.cs b/Text-Grab/Views/FullscreenGrab.xaml.cs index 15b2c40d..7f698c57 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml.cs +++ b/Text-Grab/Views/FullscreenGrab.xaml.cs @@ -220,12 +220,14 @@ private void CheckIfAnyPostActionsSelcted() { if (item.IsChecked) { - NextStepDropDownButton.Background = new SolidColorBrush(Colors.LightGreen); + if (FindResource("DarkTeal") is SolidColorBrush tealButtonStyle) + NextStepDropDownButton.Background = tealButtonStyle; return; } } - NextStepDropDownButton.Background = new SolidColorBrush(Colors.Black); + if (FindResource("ControlFillColorDefaultBrush") is SolidColorBrush SymbolButtonStyle) + NextStepDropDownButton.Background = SymbolButtonStyle; } private static bool CheckIfCheckingOrUnchecking(object? sender) @@ -680,6 +682,22 @@ private async void RegionClickCanvas_MouseUp(object sender, MouseButtonEventArgs if (GuidFixMenuItem.IsChecked is true) TextFromOCR = TextFromOCR.CorrectCommonGuidErrors(); + if (TrimEachLineMenuItem.IsChecked is true) + { + string workingString = TextFromOCR; + string[] stringSplit = workingString.Split(Environment.NewLine); + + string finalString = ""; + foreach (string line in stringSplit) + if (!string.IsNullOrWhiteSpace(line)) + finalString += line.Trim() + Environment.NewLine; + + TextFromOCR = finalString; + } + + if (RemoveDuplicatesMenuItem.IsChecked is true) + TextFromOCR = TextFromOCR.RemoveDuplicateLines(); + if (BingSearchPostCapture.IsChecked is true) { string searchStringUrlSafe = WebUtility.UrlEncode(TextFromOCR); @@ -700,6 +718,9 @@ private async void RegionClickCanvas_MouseUp(object sender, MouseButtonEventArgs isTable, destinationTextBox); WindowUtilities.CloseAllFullscreenGrabs(); + + if (InsertPostCapture.IsChecked is true && !DefaultSettings.TryInsert) + await WindowUtilities.TryInsertString(TextFromOCR); } private void SendToEditTextToggleButton_Click(object sender, RoutedEventArgs e) @@ -848,5 +869,10 @@ private void TableToggleButton_Click(object? sender = null, RoutedEventArgs? e = WindowUtilities.FullscreenKeyDown(Key.T, isActive); SelectSingleToggleButton(sender); } + + private void PostActionMenuItem_Click(object sender, RoutedEventArgs e) + { + CheckIfAnyPostActionsSelcted(); + } #endregion Methods } From c9acdb4f74568f92684a8f29c0b93607142bf801 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Tue, 3 Dec 2024 16:25:09 -0600 Subject: [PATCH 29/30] Add Google and Duck Duck Go to Post action search --- Text-Grab/Views/FullscreenGrab.xaml | 16 +++++++++++++++- Text-Grab/Views/FullscreenGrab.xaml.cs | 16 ++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/Text-Grab/Views/FullscreenGrab.xaml b/Text-Grab/Views/FullscreenGrab.xaml index 52136ac5..0fc042fe 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml +++ b/Text-Grab/Views/FullscreenGrab.xaml @@ -264,11 +264,25 @@ InputGestureText="CTRL + 4" IsCheckable="True" StaysOpenOnClick="False" /> + + diff --git a/Text-Grab/Views/FullscreenGrab.xaml.cs b/Text-Grab/Views/FullscreenGrab.xaml.cs index 7f698c57..dd7210cf 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml.cs +++ b/Text-Grab/Views/FullscreenGrab.xaml.cs @@ -216,9 +216,9 @@ private void CheckIfAnyPostActionsSelcted() if (NextStepDropDownButton.Flyout is not ContextMenu flyoutMenu || !flyoutMenu.HasItems) return; - foreach (MenuItem item in flyoutMenu.Items) + foreach (object anyItem in flyoutMenu.Items) { - if (item.IsChecked) + if (anyItem is MenuItem item && item.IsChecked) { if (FindResource("DarkTeal") is SolidColorBrush tealButtonStyle) NextStepDropDownButton.Background = tealButtonStyle; @@ -704,6 +704,18 @@ private async void RegionClickCanvas_MouseUp(object sender, MouseButtonEventArgs _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://www.bing.com/search?q={searchStringUrlSafe}"))); } + if (GoogleSearchPostCapture.IsChecked is true) + { + string searchStringUrlSafe = WebUtility.UrlEncode(TextFromOCR); + _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://www.google.com/search?q={searchStringUrlSafe}"))); + } + + if (DuckSearchPostCapture.IsChecked is true) + { + string searchStringUrlSafe = WebUtility.UrlEncode(TextFromOCR); + _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://duckduckgo.com/?va=d&t=he&q={searchStringUrlSafe}&ia=web"))); + } + if (SendToEditTextToggleButton.IsChecked is true && destinationTextBox is null && BingSearchPostCapture.IsChecked is false) From 43f2767a1ded320cfa6369de6c20b24cf30d4587 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Tue, 3 Dec 2024 16:48:47 -0600 Subject: [PATCH 30/30] Make websearches a single line before searching --- Text-Grab/Views/FullscreenGrab.xaml.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Text-Grab/Views/FullscreenGrab.xaml.cs b/Text-Grab/Views/FullscreenGrab.xaml.cs index dd7210cf..72bc321c 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml.cs +++ b/Text-Grab/Views/FullscreenGrab.xaml.cs @@ -700,19 +700,19 @@ private async void RegionClickCanvas_MouseUp(object sender, MouseButtonEventArgs if (BingSearchPostCapture.IsChecked is true) { - string searchStringUrlSafe = WebUtility.UrlEncode(TextFromOCR); + string searchStringUrlSafe = WebUtility.UrlEncode(TextFromOCR.MakeStringSingleLine()); _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://www.bing.com/search?q={searchStringUrlSafe}"))); } if (GoogleSearchPostCapture.IsChecked is true) { - string searchStringUrlSafe = WebUtility.UrlEncode(TextFromOCR); + string searchStringUrlSafe = WebUtility.UrlEncode(TextFromOCR.MakeStringSingleLine()); _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://www.google.com/search?q={searchStringUrlSafe}"))); } if (DuckSearchPostCapture.IsChecked is true) { - string searchStringUrlSafe = WebUtility.UrlEncode(TextFromOCR); + string searchStringUrlSafe = WebUtility.UrlEncode(TextFromOCR.MakeStringSingleLine()); _ = await Windows.System.Launcher.LaunchUriAsync(new Uri(string.Format($"https://duckduckgo.com/?va=d&t=he&q={searchStringUrlSafe}&ia=web"))); }