From d6d6d1dfa4b0eb2b551e8213ace3018bd366fc3b Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sun, 21 Jan 2024 18:40:33 -0600 Subject: [PATCH 1/2] Add some tests and extensions to make opening a window on every screen --- .editorconfig | 233 +++++++++++++++++++++++- Tests/ScreenLayoutTests.cs | 80 ++++++++ Text-Grab/Extensions/ShapeExtensions.cs | 7 + Text-Grab/Utilities/WindowUtilities.cs | 66 +++---- 4 files changed, 342 insertions(+), 44 deletions(-) create mode 100644 Tests/ScreenLayoutTests.cs diff --git a/.editorconfig b/.editorconfig index a7def194..0f2641df 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,12 +1,231 @@ -[*.cs] +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true -# IDE0011: Add braces +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true +dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = true +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false:suggestion +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 + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true + +# Modifier preferences +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +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 + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_inlined_variable_declaration = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = true +csharp_style_prefer_tuple_swap = true +csharp_style_prefer_utf8_string_literals = true +csharp_style_throw_expression = true +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 + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true +csharp_style_allow_embedded_statements_on_same_line_experimental = true + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +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.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.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 = -# IDE0045: Convert to conditional expression -dotnet_style_prefer_conditional_expression_over_assignment = false +# Naming styles -# Default severity for analyzer diagnostics with category 'Style' -dotnet_analyzer_diagnostic.category-Style.severity = none +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_diagnostic.CA1416.severity = none \ No newline at end of file +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.capitalization = pascal_case diff --git a/Tests/ScreenLayoutTests.cs b/Tests/ScreenLayoutTests.cs new file mode 100644 index 00000000..7dd1a079 --- /dev/null +++ b/Tests/ScreenLayoutTests.cs @@ -0,0 +1,80 @@ +using System.Windows; +using Text_Grab; + +namespace Tests; +public class ScreenLayoutTests +{ + /* + DISPLAY1 X=0,Y=0,Width=3440,Height=1400 + DISPLAY2 X=3440,Y=-1163,Width=2400,Height=3760 + DISPLAY3 X=-1920,Y=387,Width=1920,Height=1030 + */ + private static Rect display1 = new(0, 0, 3440, 1400); + private static Rect display2 = new(3440, -1163, 2400, 3760); + private static Rect display3 = new(-1920, 387, 1920, 1030); + + [Fact] + public void ShouldFindCenterOfEachRect() + { + Point center1 = display1.CenterPoint(); + Point center2 = display2.CenterPoint(); + Point center3 = display3.CenterPoint(); + + Assert.True(display1.Contains(center1)); + Assert.True(display2.Contains(center2)); + Assert.True(display3.Contains(center3)); + + Assert.False(display1.Contains(center3)); + Assert.False(display1.Contains(center2)); + + Assert.False(display2.Contains(center1)); + Assert.False(display2.Contains(center3)); + + Assert.False(display3.Contains(center1)); + Assert.False(display3.Contains(center2)); + } + + [Fact] + public void SmallRectanglesContained() + { + /* + FullscreenGrab fullScreenGrab = allFullscreenGrab[count]; + fullScreenGrab.WindowStartupLocation = WindowStartupLocation.Manual; + fullScreenGrab.Width = 40; + fullScreenGrab.Height = 40; + fullScreenGrab.DestinationTextBox = destinationTextBox; + fullScreenGrab.WindowState = WindowState.Normal; + + Point screenCenterPoint = screen.GetCenterPoint(); + Point windowCenterPoint = fullScreenGrab.GetWindowCenter(); + + fullScreenGrab.Left = screenCenterPoint.X - windowCenterPoint.X; + fullScreenGrab.Top = screenCenterPoint.Y - windowCenterPoint.Y; + */ + + int sideLength = 40; + + double smallLeft1 = display1.CenterPoint().X - (sideLength / 2); + double smallTop1 = display1.CenterPoint().Y - (sideLength / 2); + Rect smallRect1 = new(smallLeft1, smallTop1, sideLength, sideLength); + Assert.True(display1.Contains(smallRect1)); + Assert.False(display2.Contains(smallRect1)); + Assert.False(display3.Contains(smallRect1)); + + double smallLeft2 = display2.CenterPoint().X - (sideLength / 2); + double smallTop2 = display2.CenterPoint().Y - (sideLength / 2); + Rect smallRect2 = new(smallLeft2, smallTop2, sideLength, sideLength); + + Assert.True(display2.Contains(smallRect2)); + Assert.False(display1.Contains(smallRect2)); + Assert.False(display3.Contains(smallRect2)); + + double smallLeft3 = display3.CenterPoint().X - (sideLength / 2); + double smallTop3 = display3.CenterPoint().Y - (sideLength / 2); + Rect smallRect3 = new(smallLeft3, smallTop3, sideLength, sideLength); + + Assert.True(display3.Contains(smallRect3)); + Assert.False(display1.Contains(smallRect3)); + Assert.False(display2.Contains(smallRect3)); + } +} diff --git a/Text-Grab/Extensions/ShapeExtensions.cs b/Text-Grab/Extensions/ShapeExtensions.cs index 8c05c5de..22827206 100644 --- a/Text-Grab/Extensions/ShapeExtensions.cs +++ b/Text-Grab/Extensions/ShapeExtensions.cs @@ -74,4 +74,11 @@ public static bool IsGood(this Rect rect) return true; } + + public static System.Windows.Point CenterPoint(this Rect rect) + { + double x = rect.Left + (rect.Width / 2); + double y = rect.Top + (rect.Height / 2); + return new(x, y); + } } \ No newline at end of file diff --git a/Text-Grab/Utilities/WindowUtilities.cs b/Text-Grab/Utilities/WindowUtilities.cs index 199db596..00a859dd 100644 --- a/Text-Grab/Utilities/WindowUtilities.cs +++ b/Text-Grab/Utilities/WindowUtilities.cs @@ -1,10 +1,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; using System.Linq; -using System.Security.Permissions; -using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; @@ -30,26 +26,26 @@ public static void AddTextToOpenWindow(string textToAdd) public static void SetWindowPosition(Window passedWindow) { - string storedPostionString = ""; + string storedPositionString = ""; if (passedWindow is EditTextWindow) - storedPostionString = Properties.Settings.Default.EditTextWindowSizeAndPosition; + storedPositionString = Settings.Default.EditTextWindowSizeAndPosition; if (passedWindow is GrabFrame) - storedPostionString = Properties.Settings.Default.GrabFrameWindowSizeAndPosition; + storedPositionString = Settings.Default.GrabFrameWindowSizeAndPosition; - List storedPostion = new(storedPostionString.Split(',')); + List storedPosition = new(storedPositionString.Split(',')); bool isStoredRectWithinScreen = false; - if (storedPostion != null - && storedPostion.Count == 4) + if (storedPosition != null + && storedPosition.Count == 4) { bool couldParseAll = false; - couldParseAll = double.TryParse(storedPostion[0], out double parsedX); - couldParseAll = double.TryParse(storedPostion[1], out double parsedY); - couldParseAll = double.TryParse(storedPostion[2], out double parsedWid); - couldParseAll = double.TryParse(storedPostion[3], out double parsedHei); + 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); Rect storedSize = new((int)parsedX, (int)parsedY, (int)parsedWid, (int)parsedHei); IEnumerable allScreens = Screen.AllScreens; WindowCollection allWindows = Application.Current.Windows; @@ -83,8 +79,8 @@ public static void LaunchFullScreenGrab(TextBox? destinationTextBox = null) int numberOfScreens = allScreens.Count(); foreach (Window window in allWindows) - if (window is FullscreenGrab) - allFullscreenGrab.Add((FullscreenGrab)window); + if (window is FullscreenGrab grab) + allFullscreenGrab.Add(grab); int numberOfFullscreenGrabWindowsToCreate = numberOfScreens - allFullscreenGrab.Count; @@ -95,34 +91,30 @@ public static void LaunchFullScreenGrab(TextBox? destinationTextBox = null) int count = 0; + double sideLength = 40; + foreach (Screen screen in allScreens) { - FullscreenGrab fullscreenGrab = allFullscreenGrab[count]; - fullscreenGrab.WindowStartupLocation = WindowStartupLocation.Manual; - fullscreenGrab.Width = 400; - fullscreenGrab.Height = 200; - fullscreenGrab.DestinationTextBox = destinationTextBox; - fullscreenGrab.WindowState = WindowState.Normal; - - System.Windows.Point screenCenterPoint = screen.GetCenterPoint(); - System.Windows.Point windowCenterPoint = fullscreenGrab.GetWindowCenter(); + FullscreenGrab fullScreenGrab = allFullscreenGrab[count]; + fullScreenGrab.WindowStartupLocation = WindowStartupLocation.Manual; + fullScreenGrab.Width = sideLength; + fullScreenGrab.Height = sideLength; + fullScreenGrab.DestinationTextBox = destinationTextBox; + fullScreenGrab.WindowState = WindowState.Normal; - double virtualScreenTop = SystemParameters.VirtualScreenTop; - double virtualScreenLeft = SystemParameters.VirtualScreenLeft; - double virtualScreenWidth = SystemParameters.VirtualScreenWidth; - double virtualScreenHeight = SystemParameters.VirtualScreenHeight; + Point screenCenterPoint = screen.GetCenterPoint(); - fullscreenGrab.Left = screenCenterPoint.X - windowCenterPoint.X; - fullscreenGrab.Top = screenCenterPoint.Y - windowCenterPoint.Y; + fullScreenGrab.Left = screenCenterPoint.X - (sideLength / 2); + fullScreenGrab.Top = screenCenterPoint.Y - (sideLength / 2); - fullscreenGrab.Show(); - fullscreenGrab.Activate(); + fullScreenGrab.Show(); + fullScreenGrab.Activate(); count++; } } - public static System.Windows.Point GetCenterPoint(this Screen screen) + public static Point GetCenterPoint(this Screen screen) { double x = screen.WpfBounds.Left + (screen.WpfBounds.Width / 2); double y = screen.WpfBounds.Top + (screen.WpfBounds.Height / 2); @@ -164,7 +156,7 @@ internal static async void CloseAllFullscreenGrabs() if (fsg.DestinationTextBox is not null) { - // TODO 3.0 Find out how to re normaize an ETW when FSG had it minimzed + // TODO 3.0 Find out how to re normalize an ETW when FSG had it minimized isFromEditWindow = true; // if (fsg.EditWindow.WindowState == WindowState.Minimized) // fsg.EditWindow.WindowState = WindowState.Normal; @@ -201,7 +193,7 @@ internal static async Task TryInsertString(string stringToInsert) { await Task.Delay(TimeSpan.FromSeconds(Settings.Default.InsertDelay)); - List inputs = new List(); + List inputs = new(); // make sure keys are up. TryInjectModifierKeyUp(ref inputs, VirtualKeyShort.LCONTROL); TryInjectModifierKeyUp(ref inputs, VirtualKeyShort.RCONTROL); @@ -264,7 +256,7 @@ private static void TryInjectModifierKeyUp(ref List inputs, VirtualKeySho } // No Window Found, open a new one - T newWindow = new T(); + T newWindow = new(); newWindow.Show(); return newWindow; } From 1001ab0211378d6b2ba2daa7e89440637f8d6033 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Wed, 7 Feb 2024 12:38:24 -0600 Subject: [PATCH 2/2] Add another display configuration to test --- Tests/ScreenLayoutTests.cs | 57 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Tests/ScreenLayoutTests.cs b/Tests/ScreenLayoutTests.cs index 7dd1a079..c095a3f3 100644 --- a/Tests/ScreenLayoutTests.cs +++ b/Tests/ScreenLayoutTests.cs @@ -13,16 +13,34 @@ public class ScreenLayoutTests private static Rect display2 = new(3440, -1163, 2400, 3760); private static Rect display3 = new(-1920, 387, 1920, 1030); + /* + Param Display 1 Display 6 Display 5 + X 0 1920 3840 + Y 0 -460 -468 + Width 1920 1920 3840 + Height 1152 1032 2040 + */ + private static Rect display4 = new(0, 0, 1920, 1152); + private static Rect display5 = new(3840, -468, 3840, 2040); + private static Rect display6 = new(1920, -460, 1920, 1032); + + [Fact] public void ShouldFindCenterOfEachRect() { Point center1 = display1.CenterPoint(); Point center2 = display2.CenterPoint(); Point center3 = display3.CenterPoint(); + Point center4 = display4.CenterPoint(); + Point center5 = display5.CenterPoint(); + Point center6 = display6.CenterPoint(); Assert.True(display1.Contains(center1)); Assert.True(display2.Contains(center2)); Assert.True(display3.Contains(center3)); + Assert.True(display4.Contains(center4)); + Assert.True(display5.Contains(center5)); + Assert.True(display6.Contains(center6)); Assert.False(display1.Contains(center3)); Assert.False(display1.Contains(center2)); @@ -32,6 +50,16 @@ public void ShouldFindCenterOfEachRect() Assert.False(display3.Contains(center1)); Assert.False(display3.Contains(center2)); + + + Assert.False(display4.Contains(center5)); + Assert.False(display4.Contains(center6)); + + Assert.False(display5.Contains(center4)); + Assert.False(display5.Contains(center6)); + + Assert.False(display6.Contains(center4)); + Assert.False(display6.Contains(center5)); } [Fact] @@ -77,4 +105,33 @@ public void SmallRectanglesContained() Assert.False(display1.Contains(smallRect3)); Assert.False(display2.Contains(smallRect3)); } + + [Fact] + public void SmallRectanglesContained456() + { + int sideLength = 40; + + double smallLeft4 = display4.CenterPoint().X - (sideLength / 2); + double smallTop4 = display4.CenterPoint().Y - (sideLength / 2); + Rect smallRect4 = new(smallLeft4, smallTop4, sideLength, sideLength); + Assert.True(display4.Contains(smallRect4)); + Assert.False(display5.Contains(smallRect4)); + Assert.False(display6.Contains(smallRect4)); + + double smallLeft5 = display5.CenterPoint().X - (sideLength / 2); + double smallTop5 = display5.CenterPoint().Y - (sideLength / 2); + Rect smallRect5 = new(smallLeft5, smallTop5, sideLength, sideLength); + + Assert.True(display5.Contains(smallRect5)); + Assert.False(display4.Contains(smallRect5)); + Assert.False(display6.Contains(smallRect5)); + + double smallLeft6 = display6.CenterPoint().X - (sideLength / 2); + double smallTop6 = display6.CenterPoint().Y - (sideLength / 2); + Rect smallRect6 = new(smallLeft6, smallTop6, sideLength, sideLength); + + Assert.True(display6.Contains(smallRect6)); + Assert.False(display4.Contains(smallRect6)); + Assert.False(display5.Contains(smallRect6)); + } }