diff --git a/src/Avalonia.Base/Input/Gestures.cs b/src/Avalonia.Base/Input/Gestures.cs index 167f61eead..e9d23632b1 100644 --- a/src/Avalonia.Base/Input/Gestures.cs +++ b/src/Avalonia.Base/Input/Gestures.cs @@ -182,7 +182,7 @@ namespace Avalonia.Input s_lastPressPoint = e.GetPosition((Visual)ev.Source); s_holdCancellationToken = new CancellationTokenSource(); var token = s_holdCancellationToken.Token; - var settings = AvaloniaLocator.Current.GetService(); + var settings = ((IInputRoot?)visual.GetVisualRoot())?.PlatformSettings; if (settings != null) { @@ -221,7 +221,7 @@ namespace Avalonia.Input e.Source is Interactive i) { var point = e.GetCurrentPoint((Visual)target); - var settings = AvaloniaLocator.Current.GetService(); + var settings = ((IInputRoot?)i.GetVisualRoot())?.PlatformSettings; var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4); var tapRect = new Rect(s_lastPressPoint, new Size()) .Inflate(new Thickness(tapSize.Width, tapSize.Height)); @@ -260,10 +260,10 @@ namespace Avalonia.Input var e = (PointerEventArgs)ev; if (s_lastPress.TryGetTarget(out var target)) { - if (e.Pointer == s_lastPointer) + if (e.Pointer == s_lastPointer && ev.Source is Interactive i) { var point = e.GetCurrentPoint((Visual)target); - var settings = AvaloniaLocator.Current.GetService(); + var settings = ((IInputRoot?)i.GetVisualRoot())?.PlatformSettings; var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4); var tapRect = new Rect(s_lastPressPoint, new Size()) .Inflate(new Thickness(tapSize.Width, tapSize.Height)); @@ -273,7 +273,7 @@ namespace Avalonia.Input return; } - if (s_isHolding && ev.Source is Interactive i) + if (s_isHolding) { i.RaiseEvent(new HoldingRoutedEventArgs(HoldingState.Cancelled, s_lastPressPoint, s_lastPointer!.Type)); } diff --git a/src/Avalonia.Base/Input/IInputRoot.cs b/src/Avalonia.Base/Input/IInputRoot.cs index d0921eea2d..2be5847220 100644 --- a/src/Avalonia.Base/Input/IInputRoot.cs +++ b/src/Avalonia.Base/Input/IInputRoot.cs @@ -1,4 +1,5 @@ using Avalonia.Metadata; +using Avalonia.Platform; namespace Avalonia.Input { @@ -17,10 +18,18 @@ namespace Avalonia.Input /// Gets focus manager of the root. /// /// - /// Focus manager can be null only if application wasn't initialized yet. + /// Focus manager can be null only if window wasn't initialized yet. /// IFocusManager? FocusManager { get; } + /// + /// Represents a contract for accessing top-level platform-specific settings. + /// + /// + /// PlatformSettings can be null only if window wasn't initialized yet. + /// + IPlatformSettings? PlatformSettings { get; } + /// /// Gets or sets the input element that the pointer is currently over. /// diff --git a/src/Avalonia.Base/Input/MouseDevice.cs b/src/Avalonia.Base/Input/MouseDevice.cs index f3e77433a9..69c7a83900 100644 --- a/src/Avalonia.Base/Input/MouseDevice.cs +++ b/src/Avalonia.Base/Input/MouseDevice.cs @@ -2,9 +2,12 @@ using System; using System.Collections.Generic; using Avalonia.Reactive; using Avalonia.Input.Raw; +using Avalonia.Interactivity; using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.Utilities; +using Avalonia.VisualTree; + #pragma warning disable CS0618 namespace Avalonia.Input @@ -126,9 +129,10 @@ namespace Avalonia.Input if (source != null) { _pointer.Capture(source); - if (source != null) + + var settings = ((IInputRoot?)(source as Interactive)?.GetVisualRoot())?.PlatformSettings; + if (settings is not null) { - var settings = AvaloniaLocator.Current.GetRequiredService(); var doubleClickTime = settings.GetDoubleTapTime(PointerType.Mouse).TotalMilliseconds; var doubleClickSize = settings.GetDoubleTapSize(PointerType.Mouse); @@ -141,11 +145,12 @@ namespace Avalonia.Input _lastClickTime = timestamp; _lastClickRect = new Rect(p, new Size()) .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2)); - _lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton(); - var e = new PointerPressedEventArgs(source, _pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount); - source.RaiseEvent(e); - return e.Handled; } + + _lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton(); + var e = new PointerPressedEventArgs(source, _pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount); + source.RaiseEvent(e); + return e.Handled; } return false; diff --git a/src/Avalonia.Base/Input/PenDevice.cs b/src/Avalonia.Base/Input/PenDevice.cs index 832f32fb03..d5ccfdb18d 100644 --- a/src/Avalonia.Base/Input/PenDevice.cs +++ b/src/Avalonia.Base/Input/PenDevice.cs @@ -3,8 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using Avalonia.Input.Raw; +using Avalonia.Interactivity; using Avalonia.Metadata; using Avalonia.Platform; +using Avalonia.VisualTree; + #pragma warning disable CS0618 namespace Avalonia.Input @@ -80,19 +83,23 @@ namespace Avalonia.Input if (source != null) { pointer.Capture(source); - var settings = AvaloniaLocator.Current.GetService(); - var doubleClickTime = settings?.GetDoubleTapTime(PointerType.Pen).TotalMilliseconds ?? 500; - var doubleClickSize = settings?.GetDoubleTapSize(PointerType.Pen) ?? new Size(4, 4); - - if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime) + var settings = ((IInputRoot?)(source as Interactive)?.GetVisualRoot())?.PlatformSettings; + if (settings is not null) { - _clickCount = 0; + var doubleClickTime = settings.GetDoubleTapTime(PointerType.Pen).TotalMilliseconds; + var doubleClickSize = settings.GetDoubleTapSize(PointerType.Pen); + + if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime) + { + _clickCount = 0; + } + + ++_clickCount; + _lastClickTime = timestamp; + _lastClickRect = new Rect(p, new Size()) + .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2)); } - ++_clickCount; - _lastClickTime = timestamp; - _lastClickRect = new Rect(p, new Size()) - .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2)); _lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton(); var e = new PointerPressedEventArgs(source, pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount); source.RaiseEvent(e); diff --git a/src/Avalonia.Base/Input/Platform/PlatformHotkeyConfiguration.cs b/src/Avalonia.Base/Input/Platform/PlatformHotkeyConfiguration.cs index b87ca5eded..2eed0980fb 100644 --- a/src/Avalonia.Base/Input/Platform/PlatformHotkeyConfiguration.cs +++ b/src/Avalonia.Base/Input/Platform/PlatformHotkeyConfiguration.cs @@ -1,16 +1,20 @@ using System.Collections.Generic; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Input.Platform { - public class PlatformHotkeyConfiguration + /// + /// The PlatformHotkeyConfiguration class represents a configuration for platform-specific hotkeys in an Avalonia application. + /// + public sealed class PlatformHotkeyConfiguration { + [PrivateApi] public PlatformHotkeyConfiguration() : this(KeyModifiers.Control) { } + [PrivateApi] public PlatformHotkeyConfiguration(KeyModifiers commandModifiers, KeyModifiers selectionModifiers = KeyModifiers.Shift, KeyModifiers wholeWordTextActionModifiers = KeyModifiers.Control) diff --git a/src/Avalonia.Base/Input/TouchDevice.cs b/src/Avalonia.Base/Input/TouchDevice.cs index 78b570da14..74c5837b84 100644 --- a/src/Avalonia.Base/Input/TouchDevice.cs +++ b/src/Avalonia.Base/Input/TouchDevice.cs @@ -3,8 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using Avalonia.Input.Raw; +using Avalonia.Interactivity; using Avalonia.Metadata; using Avalonia.Platform; +using Avalonia.VisualTree; + #pragma warning disable CS0618 namespace Avalonia.Input @@ -62,19 +65,23 @@ namespace Avalonia.Input } else { - var settings = AvaloniaLocator.Current.GetRequiredService(); - var doubleClickTime = settings.GetDoubleTapTime(PointerType.Touch).TotalMilliseconds; - var doubleClickSize = settings.GetDoubleTapSize(PointerType.Touch); - - if (!_lastClickRect.Contains(args.Position) - || ev.Timestamp - _lastClickTime > doubleClickTime) + var settings = ((IInputRoot?)(target as Interactive)?.GetVisualRoot())?.PlatformSettings; + if (settings is not null) { - _clickCount = 0; + var doubleClickTime = settings.GetDoubleTapTime(PointerType.Touch).TotalMilliseconds; + var doubleClickSize = settings.GetDoubleTapSize(PointerType.Touch); + + if (!_lastClickRect.Contains(args.Position) + || ev.Timestamp - _lastClickTime > doubleClickTime) + { + _clickCount = 0; + } + + ++_clickCount; + _lastClickTime = ev.Timestamp; + _lastClickRect = new Rect(args.Position, new Size()) + .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2)); } - ++_clickCount; - _lastClickTime = ev.Timestamp; - _lastClickRect = new Rect(args.Position, new Size()) - .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2)); } target.RaiseEvent(new PointerPressedEventArgs(target, pointer, diff --git a/src/Avalonia.Base/Platform/DefaultPlatformSettings.cs b/src/Avalonia.Base/Platform/DefaultPlatformSettings.cs index 08fcdb50aa..a4d14b0084 100644 --- a/src/Avalonia.Base/Platform/DefaultPlatformSettings.cs +++ b/src/Avalonia.Base/Platform/DefaultPlatformSettings.cs @@ -1,12 +1,16 @@ using System; using Avalonia.Input; +using Avalonia.Input.Platform; using Avalonia.Media; +using Avalonia.Metadata; +using Avalonia.VisualTree; namespace Avalonia.Platform { /// /// A default implementation of for platforms. /// + [PrivateApi] public class DefaultPlatformSettings : IPlatformSettings { public virtual Size GetTapSize(PointerType type) @@ -28,7 +32,10 @@ namespace Avalonia.Platform public virtual TimeSpan GetDoubleTapTime(PointerType type) => TimeSpan.FromMilliseconds(500); public virtual TimeSpan HoldWaitDuration => TimeSpan.FromMilliseconds(300); - + + public PlatformHotkeyConfiguration HotkeyConfiguration => + AvaloniaLocator.Current.GetRequiredService(); + public virtual PlatformColorValues GetColorValues() { return new PlatformColorValues diff --git a/src/Avalonia.Base/Platform/IPlatformSettings.cs b/src/Avalonia.Base/Platform/IPlatformSettings.cs index b167cf0edc..46980c6d51 100644 --- a/src/Avalonia.Base/Platform/IPlatformSettings.cs +++ b/src/Avalonia.Base/Platform/IPlatformSettings.cs @@ -1,10 +1,15 @@ using System; using Avalonia.Input; +using Avalonia.Input.Platform; using Avalonia.Metadata; namespace Avalonia.Platform { - [Unstable] + /// + /// The interface represents a contract for accessing platform-specific settings and information. + /// Some of these settings might be changed by used globally in the OS in runtime. + /// + [NotClientImplementable] public interface IPlatformSettings { /// @@ -33,6 +38,11 @@ namespace Avalonia.Platform /// TimeSpan HoldWaitDuration { get; } + /// + /// Get a configuration for platform-specific hotkeys in an Avalonia application. + /// + PlatformHotkeyConfiguration HotkeyConfiguration { get; } + /// /// Gets current system color values including dark mode and accent colors. /// diff --git a/src/Avalonia.Base/Utilities/ThrowHelper.cs b/src/Avalonia.Base/Utilities/ThrowHelper.cs new file mode 100644 index 0000000000..e97ab754e5 --- /dev/null +++ b/src/Avalonia.Base/Utilities/ThrowHelper.cs @@ -0,0 +1,24 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Avalonia.Utilities; + +/// +/// Helper method to help inlining methods that do a throw check. +/// Equivalent of .NET6+ ArgumentNullException.ThrowIfNull() for netstandard2.0+ +/// +internal class ThrowHelper +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ThrowIfNull([NotNull] object? argument, string paramName) + { + if (argument is null) + { + ThrowArgumentNullException(paramName); + } + } + + [DoesNotReturn] + private static void ThrowArgumentNullException(string paramName) => throw new ArgumentNullException(paramName); +} diff --git a/src/Avalonia.Base/VisualTree/VisualExtensions.cs b/src/Avalonia.Base/VisualTree/VisualExtensions.cs index b3cdd70fa0..e244323ed9 100644 --- a/src/Avalonia.Base/VisualTree/VisualExtensions.cs +++ b/src/Avalonia.Base/VisualTree/VisualExtensions.cs @@ -1,7 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Runtime.CompilerServices; using Avalonia.Rendering; +using Avalonia.Utilities; namespace Avalonia.VisualTree { @@ -125,9 +128,9 @@ namespace Avalonia.VisualTree /// The visual's ancestors. public static IEnumerable GetVisualAncestors(this Visual visual) { - Visual? v = visual ?? throw new ArgumentNullException(nameof(visual)); + ThrowHelper.ThrowIfNull(visual, nameof(visual)); - v = v.VisualParent; + var v = visual.VisualParent; while (v != null) { @@ -194,7 +197,7 @@ namespace Avalonia.VisualTree /// The visual and its ancestors. public static IEnumerable GetSelfAndVisualAncestors(this Visual visual) { - _ = visual ?? throw new ArgumentNullException(nameof(visual)); + ThrowHelper.ThrowIfNull(visual, nameof(visual)); yield return visual; @@ -275,7 +278,7 @@ namespace Avalonia.VisualTree /// The visual at the requested point. public static Visual? GetVisualAt(this Visual visual, Point p) { - _ = visual ?? throw new ArgumentNullException(nameof(visual)); + ThrowHelper.ThrowIfNull(visual, nameof(visual)); return visual.GetVisualAt(p, x => x.IsVisible); } @@ -292,7 +295,7 @@ namespace Avalonia.VisualTree /// The visual at the requested point. public static Visual? GetVisualAt(this Visual visual, Point p, Func filter) { - _ = visual ?? throw new ArgumentNullException(nameof(visual)); + ThrowHelper.ThrowIfNull(visual, nameof(visual)); var root = visual.GetVisualRoot(); @@ -321,7 +324,7 @@ namespace Avalonia.VisualTree this Visual visual, Point p) { - _ = visual ?? throw new ArgumentNullException(nameof(visual)); + ThrowHelper.ThrowIfNull(visual, nameof(visual)); return visual.GetVisualsAt(p, x => x.IsVisible); } @@ -341,7 +344,7 @@ namespace Avalonia.VisualTree Point p, Func filter) { - _ = visual ?? throw new ArgumentNullException(nameof(visual)); + ThrowHelper.ThrowIfNull(visual, nameof(visual)); var root = visual.GetVisualRoot(); @@ -435,7 +438,7 @@ namespace Avalonia.VisualTree /// public static IRenderRoot? GetVisualRoot(this Visual visual) { - _ = visual ?? throw new ArgumentNullException(nameof(visual)); + ThrowHelper.ThrowIfNull(visual, nameof(visual)); return visual as IRenderRoot ?? visual.VisualRoot; } diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs index bfcd4750e3..7ade9f2437 100644 --- a/src/Avalonia.Controls.DataGrid/DataGrid.cs +++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs @@ -2660,25 +2660,25 @@ namespace Avalonia.Controls internal bool ProcessDownKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessDownKeyInternal(shift, ctrl); } internal bool ProcessEndKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessEndKey(shift, ctrl); } internal bool ProcessEnterKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessEnterKey(shift, ctrl); } internal bool ProcessHomeKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessHomeKey(shift, ctrl); } @@ -2718,25 +2718,25 @@ namespace Avalonia.Controls internal bool ProcessLeftKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessLeftKey(shift, ctrl); } internal bool ProcessNextKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessNextKey(shift, ctrl); } internal bool ProcessPriorKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessPriorKey(shift, ctrl); } internal bool ProcessRightKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessRightKey(shift, ctrl); } @@ -2854,7 +2854,7 @@ namespace Avalonia.Controls internal bool ProcessUpKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessUpKey(shift, ctrl); } @@ -3124,13 +3124,13 @@ namespace Avalonia.Controls //TODO: Ensure right button is checked for internal bool UpdateStateOnMouseRightButtonDown(PointerPressedEventArgs pointerPressedEventArgs, int columnIndex, int slot, bool allowEdit) { - KeyboardHelper.GetMetaKeyState(pointerPressedEventArgs.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, pointerPressedEventArgs.KeyModifiers, out bool ctrl, out bool shift); return UpdateStateOnMouseRightButtonDown(pointerPressedEventArgs, columnIndex, slot, allowEdit, shift, ctrl); } //TODO: Ensure left button is checked for internal bool UpdateStateOnMouseLeftButtonDown(PointerPressedEventArgs pointerPressedEventArgs, int columnIndex, int slot, bool allowEdit) { - KeyboardHelper.GetMetaKeyState(pointerPressedEventArgs.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, pointerPressedEventArgs.KeyModifiers, out bool ctrl, out bool shift); return UpdateStateOnMouseLeftButtonDown(pointerPressedEventArgs, columnIndex, slot, allowEdit, shift, ctrl); } @@ -4654,7 +4654,7 @@ namespace Avalonia.Controls private bool ProcessAKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift, out bool alt); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift, out bool alt); if (ctrl && !shift && !alt && SelectionMode == DataGridSelectionMode.Extended) { @@ -4923,7 +4923,7 @@ namespace Avalonia.Controls private bool ProcessF2Key(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); if (!shift && !ctrl && _editingColumnIndex == -1 && CurrentColumnIndex != -1 && GetRowSelection(CurrentSlot) && @@ -5280,7 +5280,7 @@ namespace Avalonia.Controls private bool ProcessTabKey(KeyEventArgs e) { - KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift); return ProcessTabKey(e, shift, ctrl); } @@ -6099,7 +6099,7 @@ namespace Avalonia.Controls /// Whether or not the DataGrid handled the key press. private bool ProcessCopyKey(KeyModifiers modifiers) { - KeyboardHelper.GetMetaKeyState(modifiers, out bool ctrl, out bool shift, out bool alt); + KeyboardHelper.GetMetaKeyState(this, modifiers, out bool ctrl, out bool shift, out bool alt); if (ctrl && !shift && !alt && ClipboardCopyMode != DataGridClipboardCopyMode.None && SelectedItems.Count > 0) { diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs index d1e1efdd85..96d072260c 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs @@ -703,7 +703,7 @@ namespace Avalonia.Controls public void ClearSort() { //InvokeProcessSort is already validating if sorting is possible - _headerCell?.InvokeProcessSort(KeyboardHelper.GetPlatformCtrlOrCmdKeyModifier()); + _headerCell?.InvokeProcessSort(KeyboardHelper.GetPlatformCtrlOrCmdKeyModifier(OwningGrid)); } /// diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs index ef1e84c745..0755864c25 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs @@ -241,7 +241,7 @@ namespace Avalonia.Controls DataGrid owningGrid = OwningGrid; DataGridSortDescription newSort; - KeyboardHelper.GetMetaKeyState(keyModifiers, out bool ctrl, out bool shift); + KeyboardHelper.GetMetaKeyState(this, keyModifiers, out bool ctrl, out bool shift); DataGridSortDescription sort = OwningColumn.GetSortDescription(); IDataGridCollectionView collectionView = owningGrid.DataConnection.CollectionView; diff --git a/src/Avalonia.Controls.DataGrid/Utils/KeyboardHelper.cs b/src/Avalonia.Controls.DataGrid/Utils/KeyboardHelper.cs index d2b1fd4b8e..bcb30888dc 100644 --- a/src/Avalonia.Controls.DataGrid/Utils/KeyboardHelper.cs +++ b/src/Avalonia.Controls.DataGrid/Utils/KeyboardHelper.cs @@ -10,23 +10,23 @@ namespace Avalonia.Controls.Utils { internal static class KeyboardHelper { - public static void GetMetaKeyState(KeyModifiers modifiers, out bool ctrlOrCmd, out bool shift) + public static void GetMetaKeyState(Control target, KeyModifiers modifiers, out bool ctrlOrCmd, out bool shift) { - ctrlOrCmd = modifiers.HasFlag(GetPlatformCtrlOrCmdKeyModifier()); + ctrlOrCmd = modifiers.HasFlag(GetPlatformCtrlOrCmdKeyModifier(target)); shift = modifiers.HasFlag(KeyModifiers.Shift); } - public static void GetMetaKeyState(KeyModifiers modifiers, out bool ctrlOrCmd, out bool shift, out bool alt) + public static void GetMetaKeyState(Control target, KeyModifiers modifiers, out bool ctrlOrCmd, out bool shift, out bool alt) { - ctrlOrCmd = modifiers.HasFlag(GetPlatformCtrlOrCmdKeyModifier()); + ctrlOrCmd = modifiers.HasFlag(GetPlatformCtrlOrCmdKeyModifier(target)); shift = modifiers.HasFlag(KeyModifiers.Shift); alt = modifiers.HasFlag(KeyModifiers.Alt); } - public static KeyModifiers GetPlatformCtrlOrCmdKeyModifier() - { - var keymap = AvaloniaLocator.Current.GetService(); - return keymap?.CommandModifiers ?? KeyModifiers.Control; + public static KeyModifiers GetPlatformCtrlOrCmdKeyModifier(Control target) + { + var keymap = TopLevel.GetTopLevel(target)!.PlatformSettings!.HotkeyConfiguration; + return keymap.CommandModifiers; } } } diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs index b98ad123f1..30791551f5 100644 --- a/src/Avalonia.Controls/Application.cs +++ b/src/Avalonia.Controls/Application.cs @@ -180,6 +180,17 @@ namespace Avalonia /// public IApplicationLifetime? ApplicationLifetime { get; set; } + /// + /// Represents a contract for accessing global platform-specific settings. + /// + /// + /// PlatformSettings can be null only if application wasn't initialized yet. + /// 's is an equivalent API + /// which should always be preferred over a global one, + /// as specific top levels might have different settings set-up. + /// + public IPlatformSettings? PlatformSettings => AvaloniaLocator.Current.GetService(); + event Action>? IGlobalStyles.GlobalStylesAdded { add => _stylesAdded += value; @@ -229,10 +240,12 @@ namespace Avalonia var focusManager = new FocusManager(); InputManager = new InputManager(); - var settings = AvaloniaLocator.Current.GetRequiredService(); - settings.ColorValuesChanged += OnColorValuesChanged; - OnColorValuesChanged(settings, settings.GetColorValues()); - + if (PlatformSettings is { } settings) + { + settings.ColorValuesChanged += OnColorValuesChanged; + OnColorValuesChanged(settings, settings.GetColorValues()); + } + AvaloniaLocator.CurrentMutable .Bind().ToTransient() .Bind().ToConstant(this) @@ -242,7 +255,7 @@ namespace Avalonia .Bind().ToConstant(InputManager) .Bind().ToTransient() .Bind().ToConstant(DragDropDevice.Instance); - + // TODO: Fix this, for now we keep this behavior since someone might be relying on it in 0.9.x if (AvaloniaLocator.Current.GetService() == null) AvaloniaLocator.CurrentMutable diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index 3dc1514667..e3a419d7b3 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -405,7 +405,7 @@ namespace Avalonia.Controls { if (IsOpen) { - var keymap = AvaloniaLocator.Current.GetService(); + var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration; if (keymap?.OpenContextMenu.Any(k => k.Matches(e)) == true && !CancelClosing()) diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index 8d140bdd62..6e0063c9ec 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -480,7 +480,7 @@ namespace Avalonia.Controls if (e.Source == this && !e.Handled) { - var keymap = AvaloniaLocator.Current.GetService()?.OpenContextMenu; + var keymap = Application.Current!.PlatformSettings?.HotkeyConfiguration.OpenContextMenu; if (keymap is null) { diff --git a/src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs b/src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs index 7fd9fad605..c3cf1f4897 100644 --- a/src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs +++ b/src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs @@ -9,6 +9,7 @@ using Avalonia.Input.Raw; using Avalonia.Layout; using Avalonia.Logging; using Avalonia.Reactive; +using Avalonia.VisualTree; namespace Avalonia.Controls.Primitives { @@ -392,7 +393,7 @@ namespace Avalonia.Controls.Primitives && IsOpen && Target?.ContextFlyout == this) { - var keymap = AvaloniaLocator.Current.GetService(); + var keymap = Application.Current!.PlatformSettings?.HotkeyConfiguration; if (keymap?.OpenContextMenu.Any(k => k.Matches(e)) == true) { diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs index f3f0b135b8..220903cc04 100644 --- a/src/Avalonia.Controls/ListBox.cs +++ b/src/Avalonia.Controls/ListBox.cs @@ -9,6 +9,7 @@ using Avalonia.Controls.Selection; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Input.Platform; +using Avalonia.VisualTree; namespace Avalonia.Controls { @@ -127,7 +128,7 @@ namespace Avalonia.Controls protected override void OnKeyDown(KeyEventArgs e) { - var hotkeys = AvaloniaLocator.Current.GetService(); + var hotkeys = Application.Current!.PlatformSettings?.HotkeyConfiguration; var ctrl = hotkeys is not null && e.KeyModifiers.HasAllFlags(hotkeys.CommandModifiers); if (!ctrl && @@ -165,7 +166,7 @@ namespace Avalonia.Controls internal bool UpdateSelectionFromPointerEvent(Control source, PointerEventArgs e) { - var hotkeys = AvaloniaLocator.Current.GetService(); + var hotkeys = Application.Current!.PlatformSettings?.HotkeyConfiguration; var toggle = hotkeys is not null && e.KeyModifiers.HasAllFlags(hotkeys.CommandModifiers); return UpdateSelectionFromEventSource( diff --git a/src/Avalonia.Controls/ListBoxItem.cs b/src/Avalonia.Controls/ListBoxItem.cs index c2044661e2..15136e5992 100644 --- a/src/Avalonia.Controls/ListBoxItem.cs +++ b/src/Avalonia.Controls/ListBoxItem.cs @@ -90,7 +90,7 @@ namespace Avalonia.Controls e.InitialPressMouseButton is MouseButton.Left or MouseButton.Right) { var point = e.GetCurrentPoint(this); - var settings = AvaloniaLocator.Current.GetService(); + var settings = TopLevel.GetTopLevel(e.Source as Visual)?.PlatformSettings; var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4); var tapRect = new Rect(_pointerDownPoint, new Size()) .Inflate(new Thickness(tapSize.Width, tapSize.Height)); diff --git a/src/Avalonia.Controls/MaskedTextBox.cs b/src/Avalonia.Controls/MaskedTextBox.cs index 4800b7b1e4..10eae5e7c0 100644 --- a/src/Avalonia.Controls/MaskedTextBox.cs +++ b/src/Avalonia.Controls/MaskedTextBox.cs @@ -7,6 +7,7 @@ using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Interactivity; using Avalonia.Styling; +using Avalonia.VisualTree; namespace Avalonia.Controls { @@ -204,7 +205,7 @@ namespace Avalonia.Controls return; } - var keymap = AvaloniaLocator.Current.GetService(); + var keymap = Application.Current!.PlatformSettings?.HotkeyConfiguration; bool Match(List gestures) => gestures.Any(g => g.Matches(e)); diff --git a/src/Avalonia.Controls/SelectableTextBlock.cs b/src/Avalonia.Controls/SelectableTextBlock.cs index 8b32638835..5e21681024 100644 --- a/src/Avalonia.Controls/SelectableTextBlock.cs +++ b/src/Avalonia.Controls/SelectableTextBlock.cs @@ -198,7 +198,7 @@ namespace Avalonia.Controls var handled = false; var modifiers = e.KeyModifiers; - var keymap = AvaloniaLocator.Current.GetRequiredService(); + var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration; bool Match(List gestures) => gestures.Any(g => g.Matches(e)); diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 7bc26bf3b0..5f3ba2ae11 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -32,20 +32,17 @@ namespace Avalonia.Controls /// /// Gets a platform-specific for the Cut action /// - public static KeyGesture? CutGesture { get; } = AvaloniaLocator.Current - .GetService()?.Cut.FirstOrDefault(); + public static KeyGesture? CutGesture => Application.Current?.PlatformSettings?.HotkeyConfiguration.Cut.FirstOrDefault(); /// /// Gets a platform-specific for the Copy action /// - public static KeyGesture? CopyGesture { get; } = AvaloniaLocator.Current - .GetService()?.Copy.FirstOrDefault(); + public static KeyGesture? CopyGesture => Application.Current?.PlatformSettings?.HotkeyConfiguration.Copy.FirstOrDefault(); /// /// Gets a platform-specific for the Paste action /// - public static KeyGesture? PasteGesture { get; } = AvaloniaLocator.Current - .GetService()?.Paste.FirstOrDefault(); + public static KeyGesture? PasteGesture => Application.Current?.PlatformSettings?.HotkeyConfiguration.Paste.FirstOrDefault(); /// /// Defines the property @@ -1103,7 +1100,7 @@ namespace Avalonia.Controls var handled = false; var modifiers = e.KeyModifiers; - var keymap = AvaloniaLocator.Current.GetRequiredService(); + var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration; bool Match(List gestures) => gestures.Any(g => g.Matches(e)); bool DetectSelection() => e.KeyModifiers.HasAllFlags(keymap.SelectionModifiers); diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 92444b9c07..a3f50876e0 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -250,7 +250,7 @@ namespace Avalonia.Controls if (e is RawKeyEventArgs rawKeyEventArgs && rawKeyEventArgs.Type == RawKeyEventType.KeyDown) { - var keymap = AvaloniaLocator.Current.GetService()?.Back; + var keymap = PlatformSettings?.HotkeyConfiguration.Back; if (keymap != null) { @@ -487,6 +487,9 @@ namespace Avalonia.Controls /// public IFocusManager? FocusManager => AvaloniaLocator.Current.GetService(); + /// + public IPlatformSettings? PlatformSettings => AvaloniaLocator.Current.GetService(); + /// Point IRenderRoot.PointToClient(PixelPoint p) { diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index a499829d4a..7bf8d3bb68 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -571,7 +571,7 @@ namespace Avalonia.Controls if (!e.Handled) { - var keymap = AvaloniaLocator.Current.GetService(); + var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration; bool Match(List? gestures) => gestures?.Any(g => g.Matches(e)) ?? false; if (this.SelectionMode == SelectionMode.Multiple && Match(keymap?.SelectAll)) @@ -652,11 +652,12 @@ namespace Avalonia.Controls if (point.Properties.IsLeftButtonPressed || point.Properties.IsRightButtonPressed) { + var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration; e.Handled = UpdateSelectionFromEventSource( e.Source, true, e.KeyModifiers.HasAllFlags(KeyModifiers.Shift), - e.KeyModifiers.HasAllFlags(AvaloniaLocator.Current.GetRequiredService().CommandModifiers), + e.KeyModifiers.HasAllFlags(keymap.CommandModifiers), point.Properties.IsRightButtonPressed); } } diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index c471cf91d2..b32382084d 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -108,20 +108,18 @@ namespace Avalonia.Native .Bind().ToConstant(this) .Bind().ToConstant(new ClipboardImpl(_factory.CreateClipboard())) .Bind().ToConstant(new DefaultRenderTimer(60)) - .Bind().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Meta, wholeWordTextActionModifiers: KeyModifiers.Alt)) .Bind().ToConstant(new MacOSMountedVolumeInfoProvider()) .Bind().ToConstant(new AvaloniaNativeDragSource(_factory)) .Bind().ToConstant(applicationPlatform) .Bind().ToConstant(new MacOSNativeMenuCommands(_factory.CreateApplicationCommands())); - - var hotkeys = AvaloniaLocator.Current.GetService(); - if (hotkeys is not null) - { - hotkeys.MoveCursorToTheStartOfLine.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers)); - hotkeys.MoveCursorToTheStartOfLineWithSelection.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); - hotkeys.MoveCursorToTheEndOfLine.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers)); - hotkeys.MoveCursorToTheEndOfLineWithSelection.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); - } + + var hotkeys = new PlatformHotkeyConfiguration(KeyModifiers.Meta, wholeWordTextActionModifiers: KeyModifiers.Alt); + hotkeys.MoveCursorToTheStartOfLine.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers)); + hotkeys.MoveCursorToTheStartOfLineWithSelection.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); + hotkeys.MoveCursorToTheEndOfLine.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers)); + hotkeys.MoveCursorToTheEndOfLineWithSelection.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); + + AvaloniaLocator.CurrentMutable.Bind().ToConstant(hotkeys); if (_options.UseGpu) { diff --git a/src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs b/src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs index a4ef15f950..a796a5704d 100644 --- a/src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs +++ b/src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs @@ -16,18 +16,12 @@ internal class SystemAccentColors : IResourceProvider public const string AccentLight2Key = "SystemAccentColorLight2"; public const string AccentLight3Key = "SystemAccentColorLight3"; - private static readonly Color s_defaultSystemAccentColor = Color.FromRgb(0, 120, 215); - private readonly IPlatformSettings? _platformSettings; + private static readonly Color s_defaultSystemAccentColor = Color.FromRgb(0, 120, 215); private bool _invalidateColors = true; private Color _systemAccentColor; private Color _systemAccentColorDark1, _systemAccentColorDark2, _systemAccentColorDark3; private Color _systemAccentColorLight1, _systemAccentColorLight2, _systemAccentColorLight3; - public SystemAccentColors() - { - _platformSettings = AvaloniaLocator.Current.GetService(); - } - public bool HasResources => true; public bool TryGetResource(object key, ThemeVariant? theme, out object? value) { @@ -96,10 +90,12 @@ internal class SystemAccentColors : IResourceProvider Owner = owner; OwnerChanged?.Invoke(this, EventArgs.Empty); - if (_platformSettings is not null) + if (GetFromOwner(owner) is { } platformSettings) { - _platformSettings.ColorValuesChanged += PlatformSettingsOnColorValuesChanged; + platformSettings.ColorValuesChanged += PlatformSettingsOnColorValuesChanged; } + + _invalidateColors = true; } } @@ -110,10 +106,12 @@ internal class SystemAccentColors : IResourceProvider Owner = null; OwnerChanged?.Invoke(this, EventArgs.Empty); - if (_platformSettings is not null) + if (GetFromOwner(owner) is { } platformSettings) { - _platformSettings.ColorValuesChanged -= PlatformSettingsOnColorValuesChanged; + platformSettings.ColorValuesChanged -= PlatformSettingsOnColorValuesChanged; } + + _invalidateColors = true; } } @@ -122,13 +120,25 @@ internal class SystemAccentColors : IResourceProvider if (_invalidateColors) { _invalidateColors = false; + + var platformSettings = GetFromOwner(Owner); - _systemAccentColor = _platformSettings?.GetColorValues().AccentColor1 ?? s_defaultSystemAccentColor; + _systemAccentColor = platformSettings?.GetColorValues().AccentColor1 ?? s_defaultSystemAccentColor; (_systemAccentColorDark1,_systemAccentColorDark2, _systemAccentColorDark3, _systemAccentColorLight1, _systemAccentColorLight2, _systemAccentColorLight3) = CalculateAccentShades(_systemAccentColor); } } + private static IPlatformSettings? GetFromOwner(IResourceHost? owner) + { + return owner switch + { + Application app => app.PlatformSettings, + Visual visual => TopLevel.GetTopLevel(visual)?.PlatformSettings, + _ => null + }; + } + public static (Color d1, Color d2, Color d3, Color l1, Color l2, Color l3) CalculateAccentShades(Color accentColor) { // dark1step = (hslAccent.L - SystemAccentColorDark1.L) * 255 diff --git a/tests/Avalonia.Base.UnitTests/Input/GesturesTests.cs b/tests/Avalonia.Base.UnitTests/Input/GesturesTests.cs index c3630c36b7..14fa242146 100644 --- a/tests/Avalonia.Base.UnitTests/Input/GesturesTests.cs +++ b/tests/Avalonia.Base.UnitTests/Input/GesturesTests.cs @@ -24,13 +24,13 @@ namespace Avalonia.Base.UnitTests.Input public void Tapped_Should_Follow_Pointer_Pressed_Released() { Border border = new Border(); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var result = new List(); - AddHandlers(decorator, border, result, false); + AddHandlers(root, border, result, false); _mouse.Click(border); @@ -41,13 +41,13 @@ namespace Avalonia.Base.UnitTests.Input public void Tapped_Should_Be_Raised_Even_When_Pressed_Released_Handled() { Border border = new Border(); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var result = new List(); - AddHandlers(decorator, border, result, true); + AddHandlers(root, border, result, true); _mouse.Click(border); @@ -58,13 +58,13 @@ namespace Avalonia.Base.UnitTests.Input public void Tapped_Should_Not_Be_Raised_For_Middle_Button() { Border border = new Border(); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.TappedEvent, (_, _) => raised = true); + root.AddHandler(Gestures.TappedEvent, (_, _) => raised = true); _mouse.Click(border, MouseButton.Middle); @@ -75,13 +75,13 @@ namespace Avalonia.Base.UnitTests.Input public void Tapped_Should_Not_Be_Raised_For_Right_Button() { Border border = new Border(); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.TappedEvent, (_, _) => raised = true); + root.AddHandler(Gestures.TappedEvent, (_, _) => raised = true); _mouse.Click(border, MouseButton.Right); @@ -92,13 +92,13 @@ namespace Avalonia.Base.UnitTests.Input public void RightTapped_Should_Be_Raised_For_Right_Button() { Border border = new Border(); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.RightTappedEvent, (_, _) => raised = true); + root.AddHandler(Gestures.RightTappedEvent, (_, _) => raised = true); _mouse.Click(border, MouseButton.Right); @@ -109,13 +109,13 @@ namespace Avalonia.Base.UnitTests.Input public void DoubleTapped_Should_Follow_Pointer_Pressed_Released_Pressed() { Border border = new Border(); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var result = new List(); - AddHandlers(decorator, border, result, false); + AddHandlers(root, border, result, false); _mouse.Click(border); _mouse.Down(border, clickCount: 2); @@ -127,13 +127,13 @@ namespace Avalonia.Base.UnitTests.Input public void DoubleTapped_Should_Be_Raised_Even_When_Pressed_Released_Handled() { Border border = new Border(); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var result = new List(); - AddHandlers(decorator, border, result, true); + AddHandlers(root, border, result, true); _mouse.Click(border); _mouse.Down(border, clickCount: 2); @@ -145,13 +145,13 @@ namespace Avalonia.Base.UnitTests.Input public void DoubleTapped_Should_Not_Be_Raised_For_Middle_Button() { Border border = new Border(); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.DoubleTappedEvent, (_, _) => raised = true); + root.AddHandler(Gestures.DoubleTappedEvent, (_, _) => raised = true); _mouse.Click(border, MouseButton.Middle); _mouse.Down(border, MouseButton.Middle, clickCount: 2); @@ -163,13 +163,13 @@ namespace Avalonia.Base.UnitTests.Input public void DoubleTapped_Should_Not_Be_Raised_For_Right_Button() { Border border = new Border(); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.DoubleTappedEvent, (_, _) => raised = true); + root.AddHandler(Gestures.DoubleTappedEvent, (_, _) => raised = true); _mouse.Click(border, MouseButton.Right); _mouse.Down(border, MouseButton.Right, clickCount: 2); @@ -191,13 +191,13 @@ namespace Avalonia.Base.UnitTests.Input Border border = new Border(); Gestures.SetIsHoldWithMouseEnabled(border, true); - var decorator = new Decorator + var root = new TestRoot { Child = border }; HoldingState holding = HoldingState.Cancelled; - decorator.AddHandler(Gestures.HoldingEvent, (_, e) => holding = e.HoldingState); + root.AddHandler(Gestures.HoldingEvent, (_, e) => holding = e.HoldingState); _mouse.Down(border); Assert.False(holding != HoldingState.Cancelled); @@ -227,13 +227,13 @@ namespace Avalonia.Base.UnitTests.Input Border border = new Border(); Gestures.SetIsHoldWithMouseEnabled(border, true); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Started); + root.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Started); _mouse.Down(border); Assert.False(raised); @@ -262,13 +262,13 @@ namespace Avalonia.Base.UnitTests.Input Border border = new Border(); Gestures.SetIsHoldWithMouseEnabled(border, true); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Completed); + root.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Completed); _mouse.Down(border); Assert.False(raised); @@ -297,13 +297,13 @@ namespace Avalonia.Base.UnitTests.Input Border border = new Border(); Gestures.SetIsHoldWithMouseEnabled(border, true); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var cancelled = false; - decorator.AddHandler(Gestures.HoldingEvent, (_, e) => cancelled = e.HoldingState == HoldingState.Cancelled); + root.AddHandler(Gestures.HoldingEvent, (_, e) => cancelled = e.HoldingState == HoldingState.Cancelled); _mouse.Down(border); Assert.False(cancelled); @@ -333,13 +333,13 @@ namespace Avalonia.Base.UnitTests.Input Border border = new Border(); Gestures.SetIsHoldWithMouseEnabled(border, true); - var decorator = new Decorator + var root = new TestRoot() { Child = border }; var cancelled = false; - decorator.AddHandler(Gestures.HoldingEvent, (_, e) => cancelled = e.HoldingState == HoldingState.Cancelled); + root.AddHandler(Gestures.HoldingEvent, (_, e) => cancelled = e.HoldingState == HoldingState.Cancelled); _mouse.Down(border); @@ -369,13 +369,13 @@ namespace Avalonia.Base.UnitTests.Input Border border = new Border(); Gestures.SetIsHoldWithMouseEnabled(border, true); - var decorator = new Decorator + var testRoot = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Completed); + testRoot.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Completed); var secondMouse = new MouseTestHelper(); @@ -392,12 +392,12 @@ namespace Avalonia.Base.UnitTests.Input } private static void AddHandlers( - Decorator decorator, + TestRoot root, Border border, IList result, bool markHandled) { - decorator.AddHandler(InputElement.PointerPressedEvent, (_, e) => + root.AddHandler(InputElement.PointerPressedEvent, (_, e) => { result.Add("dp"); @@ -407,7 +407,7 @@ namespace Avalonia.Base.UnitTests.Input } }); - decorator.AddHandler(InputElement.PointerReleasedEvent, (_, e) => + root.AddHandler(InputElement.PointerReleasedEvent, (_, e) => { result.Add("dr"); @@ -420,8 +420,8 @@ namespace Avalonia.Base.UnitTests.Input border.AddHandler(InputElement.PointerPressedEvent, (_, _) => result.Add("bp")); border.AddHandler(InputElement.PointerReleasedEvent, (_, _) => result.Add("br")); - decorator.AddHandler(Gestures.TappedEvent, (_, _) => result.Add("dt")); - decorator.AddHandler(Gestures.DoubleTappedEvent, (_, _) => result.Add("ddt")); + root.AddHandler(Gestures.TappedEvent, (_, _) => result.Add("dt")); + root.AddHandler(Gestures.DoubleTappedEvent, (_, _) => result.Add("ddt")); border.AddHandler(Gestures.TappedEvent, (_, _) => result.Add("bt")); border.AddHandler(Gestures.DoubleTappedEvent, (_, _) => result.Add("bdt")); } @@ -438,13 +438,13 @@ namespace Avalonia.Base.UnitTests.Input Background = new SolidColorBrush(Colors.Red) }; border.GestureRecognizers.Add(new PinchGestureRecognizer()); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.PinchEvent, (_, _) => raised = true); + root.AddHandler(Gestures.PinchEvent, (_, _) => raised = true); var firstPoint = new Point(5, 5); var secondPoint = new Point(10, 10); @@ -466,13 +466,13 @@ namespace Avalonia.Base.UnitTests.Input Background = new SolidColorBrush(Colors.Red) }; border.GestureRecognizers.Add(new PinchGestureRecognizer()); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.PinchEvent, (_, _) => raised = true); + root.AddHandler(Gestures.PinchEvent, (_, _) => raised = true); var firstPoint = new Point(5, 5); var secondPoint = new Point(10, 10); @@ -502,13 +502,13 @@ namespace Avalonia.Base.UnitTests.Input CanVerticallyScroll = true, ScrollStartDistance = 50 }); - var decorator = new Decorator + var root = new TestRoot { Child = border }; var raised = false; - decorator.AddHandler(Gestures.ScrollGestureEvent, (_, _) => raised = true); + root.AddHandler(Gestures.ScrollGestureEvent, (_, _) => raised = true); var firstTouch = new TouchTestHelper(); diff --git a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs index 1d62588ec0..0ddc247be6 100644 --- a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs @@ -3,9 +3,11 @@ using System.Windows.Input; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.Layout; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; +using Avalonia.Threading; using Avalonia.UnitTests; using Avalonia.VisualTree; using Moq; @@ -14,7 +16,7 @@ using MouseButton = Avalonia.Input.MouseButton; namespace Avalonia.Controls.UnitTests { - public class ButtonTests + public class ButtonTests : ScopedTestBase { private MouseTestHelper _helper = new MouseTestHelper(); @@ -139,11 +141,19 @@ namespace Avalonia.Controls.UnitTests renderer.Setup(r => r.HitTest(It.IsAny(), It.IsAny(), It.IsAny>())) .Returns>((p, r, f) => r.Bounds.Contains(p) ? new Visual[] { r } : new Visual[0]); - - var target = new TestButton(renderer.Object) + + using var _ = UnitTestApplication.Start(TestServices.StyledWindow); + + var root = new Window() { HitTesterOverride = renderer.Object }; + var target = new Button() { - Bounds = new Rect(0, 0, 100, 100) + Width = 100, + Height = 100, + VerticalAlignment = VerticalAlignment.Top, + HorizontalAlignment = HorizontalAlignment.Left }; + root.Content = target; + root.Show(); bool clicked = false; @@ -165,16 +175,13 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Button_Does_Not_Raise_Click_When_PointerReleased_Outside() { - var renderer = new Mock(); - - renderer.Setup(r => r.HitTest(It.IsAny(), It.IsAny(), It.IsAny>())) - .Returns>((p, r, f) => - r.Bounds.Contains(p) ? new Visual[] { r } : new Visual[0]); - - var target = new TestButton(renderer.Object) + var root = new TestRoot(); + var target = new Button() { - Bounds = new Rect(0, 0, 100, 100) + Width = 100, + Height = 100 }; + root.Child = target; bool clicked = false; @@ -203,12 +210,20 @@ namespace Avalonia.Controls.UnitTests .Returns>((p, r, f) => r.Bounds.Contains(p.Transform(r.RenderTransform.Value.Invert())) ? new Visual[] { r } : new Visual[0]); - - var target = new TestButton(renderer.Object) + + using var _ = UnitTestApplication.Start(TestServices.StyledWindow); + + var root = new Window() { HitTesterOverride = renderer.Object }; + var target = new Button() { - Bounds = new Rect(0, 0, 100, 100), + Width = 100, + Height = 100, + VerticalAlignment = VerticalAlignment.Top, + HorizontalAlignment = HorizontalAlignment.Left, RenderTransform = new TranslateTransform { X = 100, Y = 0 } }; + root.Content = target; + root.Show(); //actual bounds of button should be 100,0,100,100 x -> translated 100 pixels //so mouse with x=150 coordinates should trigger click @@ -381,37 +396,6 @@ namespace Avalonia.Controls.UnitTests return new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = key, Source = source }; } - private class TestButton : Button, IRenderRoot - { - public TestButton(IHitTester hit) - { - IsVisible = true; - HitTester = hit; - Renderer = new NullRenderer(); - } - - public new Rect Bounds - { - get => base.Bounds; - set => base.Bounds = value; - } - - public Size ClientSize => throw new NotImplementedException(); - - public IRenderer Renderer { get; } - public IHitTester HitTester { get; } - - public double RenderScaling => throw new NotImplementedException(); - - public IRenderTarget CreateRenderTarget() => throw new NotImplementedException(); - - public void Invalidate(Rect rect) => throw new NotImplementedException(); - - public Point PointToClient(PixelPoint p) => throw new NotImplementedException(); - - public PixelPoint PointToScreen(Point p) => throw new NotImplementedException(); - } - private void RaisePointerPressed(Button button, int clickCount, MouseButton mouseButton, Point position) { _helper.Down(button, mouseButton, position, clickCount: clickCount); diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs index ed19d1dc97..21e25a6f1c 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs @@ -34,7 +34,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Shift); Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems); @@ -60,7 +60,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); SelectionChangedEventArgs receivedArgs = null; @@ -118,7 +118,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[1]); _helper.Click(target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); _helper.Click(target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Control); @@ -152,7 +152,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[1]); _helper.Click(target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); @@ -183,7 +183,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[3]); _helper.Click(target.Presenter.Panel.Children[4], modifiers: KeyModifiers.Control); @@ -211,7 +211,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[3]); _helper.Click(target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift); @@ -239,7 +239,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[0]); _helper.Click(target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift); @@ -266,7 +266,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); SelectionChangedEventArgs receivedArgs = null; @@ -319,7 +319,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[0]); Assert.Equal(new[] { "Foo" }, target.SelectedItems); @@ -414,7 +414,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[0]); _helper.Click(target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Shift); @@ -444,7 +444,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[0]); _helper.Click(target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Shift); @@ -471,7 +471,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); root.LayoutManager.ExecuteInitialLayoutPass(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); _helper.Click(target.Presenter.Panel.Children[0]); _helper.Click(target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Control); diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs index 92ea2df2a9..f442202e26 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs @@ -49,7 +49,7 @@ namespace Avalonia.Controls.UnitTests Template = new FuncControlTemplate(CreateListBoxTemplate), ItemsSource = new[] { "Foo", "Bar", "Baz " }, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); ApplyTemplate(target); target.Presenter.Panel.Children[0].RaiseEvent(new GotFocusEventArgs @@ -79,7 +79,7 @@ namespace Avalonia.Controls.UnitTests Template = new FuncControlTemplate(CreateListBoxTemplate), ItemsSource = new[] { "Foo", "Bar", "Baz " }, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); ApplyTemplate(target); _mouse.Click(target.Presenter.Panel.Children[0]); @@ -97,7 +97,7 @@ namespace Avalonia.Controls.UnitTests Template = new FuncControlTemplate(CreateListBoxTemplate), ItemsSource = new[] { "Foo", "Bar", "Baz " }, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); ApplyTemplate(target); target.SelectedIndex = 0; @@ -118,7 +118,7 @@ namespace Avalonia.Controls.UnitTests ItemsSource = new[] { "Foo", "Bar", "Baz " }, SelectionMode = SelectionMode.Single | SelectionMode.Toggle, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); ApplyTemplate(target); _mouse.Click(target.Presenter.Panel.Children[0]); @@ -139,7 +139,7 @@ namespace Avalonia.Controls.UnitTests SelectionMode = SelectionMode.Toggle, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); ApplyTemplate(target); target.SelectedIndex = 0; @@ -160,7 +160,7 @@ namespace Avalonia.Controls.UnitTests ItemsSource = new[] { "Foo", "Bar", "Baz " }, SelectionMode = SelectionMode.Toggle | SelectionMode.AlwaysSelected, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); ApplyTemplate(target); target.SelectedIndex = 0; @@ -181,7 +181,7 @@ namespace Avalonia.Controls.UnitTests ItemsSource = new[] { "Foo", "Bar", "Baz " }, SelectionMode = SelectionMode.Single | SelectionMode.Toggle, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); ApplyTemplate(target); target.SelectedIndex = 1; diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index e456f25238..c41f3c18cb 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -1234,7 +1234,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Template = Template(), ItemsSource = new[] { "Foo", "Bar", "Baz " }, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); Prepare(target); var container = target.ContainerFromIndex(1)!; @@ -1258,7 +1258,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Template = Template(), ItemsSource = items, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); Prepare(target); _helper.Down(target.Presenter.Panel.Children[1]); @@ -1355,7 +1355,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Template = Template(), ItemsSource = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); Prepare(target); _helper.Down((Interactive)target.Presenter.Panel.Children[3]); @@ -1373,7 +1373,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Template = Template(), ItemsSource = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, }; - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new Mock().Object); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new PlatformHotkeyConfiguration()); Prepare(target); _helper.Down((Interactive)target.Presenter.Panel.Children[3]); diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index f4306f63db..11e9349ffe 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -1045,7 +1045,7 @@ namespace Avalonia.Controls.UnitTests var data = CreateTestTreeData(); var target = CreateTarget(data: data, multiSelect: true); var rootNode = data[0]; - var keymap = AvaloniaLocator.Current.GetRequiredService(); + var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration; var selectAllGesture = keymap.SelectAll.First(); var keyEvent = new KeyEventArgs @@ -1075,7 +1075,7 @@ namespace Avalonia.Controls.UnitTests ClickContainer(fromContainer, KeyModifiers.None); ClickContainer(toContainer, KeyModifiers.Shift); - var keymap = AvaloniaLocator.Current.GetRequiredService(); + var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration; var selectAllGesture = keymap.SelectAll.First(); var keyEvent = new KeyEventArgs @@ -1105,7 +1105,7 @@ namespace Avalonia.Controls.UnitTests ClickContainer(fromContainer, KeyModifiers.None); ClickContainer(toContainer, KeyModifiers.Shift); - var keymap = AvaloniaLocator.Current.GetRequiredService(); + var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration; var selectAllGesture = keymap.SelectAll.First(); var keyEvent = new KeyEventArgs diff --git a/tests/Avalonia.UnitTests/TestRoot.cs b/tests/Avalonia.UnitTests/TestRoot.cs index 569e5d114c..fcfd845602 100644 --- a/tests/Avalonia.UnitTests/TestRoot.cs +++ b/tests/Avalonia.UnitTests/TestRoot.cs @@ -67,6 +67,7 @@ namespace Avalonia.UnitTests public IKeyboardNavigationHandler KeyboardNavigationHandler => null; public IFocusManager FocusManager => AvaloniaLocator.Current.GetService(); + public IPlatformSettings PlatformSettings => AvaloniaLocator.Current.GetService(); public IInputElement PointerOverElement { get; set; } diff --git a/tests/Avalonia.UnitTests/UnitTestApplication.cs b/tests/Avalonia.UnitTests/UnitTestApplication.cs index 870e6391d0..5f7f3f20ec 100644 --- a/tests/Avalonia.UnitTests/UnitTestApplication.cs +++ b/tests/Avalonia.UnitTests/UnitTestApplication.cs @@ -77,7 +77,8 @@ namespace Avalonia.UnitTests .Bind().ToConstant(Services.DispatcherImpl) .Bind().ToConstant(Services.StandardCursorFactory) .Bind().ToConstant(Services.WindowingPlatform) - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToSingleton(); // This is a hack to make tests work, we need to refactor the way font manager is registered // See https://github.com/AvaloniaUI/Avalonia/issues/10081