From 2fbc2f4eaf4464da6523ead84dcb3722b8ed04d4 Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Mon, 27 May 2024 15:31:07 +1200 Subject: [PATCH 01/10] Adding KeyGestureFormatInfo to hold platform specific Key/Modifier Strings when performing KeyGesture.ToString() --- .../Input/Platform/KeyGestureFormatInfo.cs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs diff --git a/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs b/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs new file mode 100644 index 00000000000..27ff0716f9e --- /dev/null +++ b/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Input.Platform +{ + public sealed class KeyGestureFormatInfo(Dictionary? platformKeyOverrides = null, + string meta = "Cmd", + string ctrl = "Ctrl", + string alt = "Alt", + string shift = "Shift") : IFormatProvider + { + public static KeyGestureFormatInfo Invariant { get; } = new(); + + public string Meta { get; } = meta; + + public string Ctrl { get; } = ctrl; + + public string Alt { get; } = alt; + + public string Shift { get; } = shift; + + public object? GetFormat(Type? formatType) => formatType == typeof(KeyGestureFormatInfo) ? this : null; + + public static KeyGestureFormatInfo GetInstance(IFormatProvider? formatProvider) + => formatProvider?.GetFormat(typeof(KeyGestureFormatInfo)) as KeyGestureFormatInfo + ?? AvaloniaLocator.Current.GetService() + ?? Invariant; + + /* A dictionary of the common platform Key overrides. These are used as a fallback + * if platformKeyOverrides doesn't contain the Key in question. + */ + private static readonly Dictionary s_commonKeyOverrides = new() + { + { Key.Add , "+" }, + { Key.D0 , "0" }, + { Key.D1 , "1" }, + { Key.D2 , "2" }, + { Key.D3 , "3" }, + { Key.D4 , "4" }, + { Key.D5 , "5" }, + { Key.D6 , "6" }, + { Key.D7 , "7" }, + { Key.D8 , "8" }, + { Key.D9 , "9" }, + { Key.Decimal , "." }, + { Key.Divide , "/" }, + { Key.Multiply , "*" }, + { Key.OemBackslash , "\\" }, + { Key.OemCloseBrackets , "]" }, + { Key.OemComma , "," }, + { Key.OemMinus , "-" }, + { Key.OemOpenBrackets , "[" }, + { Key.OemPeriod , "." }, + { Key.OemPipe , "|" }, + { Key.OemPlus , "+" }, + { Key.OemQuestion , "/" }, + { Key.OemQuotes , "\"" }, + { Key.OemSemicolon , ";" }, + { Key.OemTilde , "`" }, + { Key.Separator , "/" }, + { Key.Subtract , "-" } + }; + + public string FormatKey(Key key) + { + /* + * The absence of an Overrides dictionary indicates this is the invariant, and + * so should just return the default ToString() value. + */ + if (platformKeyOverrides == null) + return key.ToString(); + + return platformKeyOverrides.TryGetValue(key, out string? result) ? result : + s_commonKeyOverrides.TryGetValue(key, out string? cresult) ? cresult : + key.ToString() ; + + } + + + } +} From 590d27045847ed1b5983f62820b3a6ef68a3c539 Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Mon, 27 May 2024 15:49:06 +1200 Subject: [PATCH 02/10] Implementing KeyGesture IFormattable using new KeyGestureFormatInfo --- src/Avalonia.Base/Input/KeyGesture.cs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Base/Input/KeyGesture.cs b/src/Avalonia.Base/Input/KeyGesture.cs index 9ee8ae97110..224ef787608 100644 --- a/src/Avalonia.Base/Input/KeyGesture.cs +++ b/src/Avalonia.Base/Input/KeyGesture.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Text; +using Avalonia.Input.Platform; using Avalonia.Utilities; namespace Avalonia.Input @@ -9,7 +10,7 @@ namespace Avalonia.Input /// /// Defines a keyboard input combination. /// - public sealed class KeyGesture : IEquatable + public sealed class KeyGesture : IEquatable, IFormattable { private static readonly Dictionary s_keySynonyms = new Dictionary { @@ -95,8 +96,17 @@ public static KeyGesture Parse(string gesture) return new KeyGesture(key, keyModifiers); } - public override string ToString() + public override string ToString() => ToString(null, null); + + public string ToString(string? format, IFormatProvider? formatProvider) { + var formatInfo = format switch + { + null or "" or "g" => KeyGestureFormatInfo.Invariant, + "p" => KeyGestureFormatInfo.GetInstance(formatProvider), + _ => throw new FormatException("Unknown format specifier") + }; + var s = StringBuilderCache.Acquire(); static void Plus(StringBuilder s) @@ -109,29 +119,29 @@ static void Plus(StringBuilder s) if (KeyModifiers.HasAllFlags(KeyModifiers.Control)) { - s.Append("Ctrl"); + s.Append(formatInfo.Ctrl); } if (KeyModifiers.HasAllFlags(KeyModifiers.Shift)) { Plus(s); - s.Append("Shift"); + s.Append(formatInfo.Shift); } if (KeyModifiers.HasAllFlags(KeyModifiers.Alt)) { Plus(s); - s.Append("Alt"); + s.Append(formatInfo.Alt); } if (KeyModifiers.HasAllFlags(KeyModifiers.Meta)) { Plus(s); - s.Append("Cmd"); + s.Append(formatInfo.Meta); } Plus(s); - s.Append(Key); + s.Append(formatInfo.FormatKey(Key)); return StringBuilderCache.GetStringAndRelease(s); } From 3f7b0dd081294b3136e7f0d49a0286c8c64a93ec Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Mon, 27 May 2024 16:18:41 +1200 Subject: [PATCH 03/10] Adding platform specific registrations of KeyGestureFormatInfo --- src/Android/Avalonia.Android/AndroidPlatform.cs | 5 +++++ src/Avalonia.Native/AvaloniaNativePlatform.cs | 10 +++++++++- src/Avalonia.X11/X11Platform.cs | 5 +++++ src/Browser/Avalonia.Browser/WindowingPlatform.cs | 5 +++++ .../Avalonia.Headless/AvaloniaHeadlessPlatform.cs | 7 ++++++- .../LinuxFramebufferPlatform.cs | 7 ++++++- src/Tizen/Avalonia.Tizen/TizenPlatform.cs | 5 +++++ src/Windows/Avalonia.Win32/Win32Platform.cs | 5 +++++ src/iOS/Avalonia.iOS/Platform.cs | 9 ++++++++- 9 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs index d9f34198508..85e7534feb8 100644 --- a/src/Android/Avalonia.Android/AndroidPlatform.cs +++ b/src/Android/Avalonia.Android/AndroidPlatform.cs @@ -88,6 +88,11 @@ public static void Initialize() .Bind().ToSingleton() .Bind().ToConstant(new ChoreographerTimer()) .Bind().ToSingleton() + .Bind().ToConstant(new KeyGestureFormatInfo(new() + { + { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, + { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } + })) .Bind().ToConstant(new AndroidActivatableLifetime()); var graphics = InitializeGraphics(Options); diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index d8ab8363b58..52f1f49dee6 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.InteropServices; using Avalonia.Compatibility; using Avalonia.Controls.ApplicationLifetimes; @@ -124,6 +124,14 @@ void DoInitialize(AvaloniaNativePlatformOptions options) AvaloniaLocator.CurrentMutable.Bind().ToConstant(hotkeys); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new KeyGestureFormatInfo(new() + { + { Key.Back , "⌫" }, { Key.Down , "↓" }, { Key.End , "↘" }, { Key.Escape , "⎋" }, + { Key.Home , "↖" }, { Key.Left , "←" }, { Key.Return , "↩" }, { Key.PageDown , "⇞" }, + { Key.PageUp , "⇟" }, { Key.Right , "→" }, { Key.Space , "␣" }, { Key.Tab , "⇥" }, + { Key.Up , "↑" } + }, ctrl: "⌃", meta: "⌘", shift: "⇧", alt: "⌥")); + foreach (var mode in _options.RenderingMode) { if (mode == AvaloniaNativeRenderingMode.OpenGl) diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index e89a5088206..420938c799f 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -81,6 +81,11 @@ public void Initialize(X11PlatformOptions options) .Bind().ToConstant(new X11PlatformThreading(this)) .Bind().ToConstant(timer) .Bind().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Control)) + .Bind().ToConstant(new KeyGestureFormatInfo(new() + { + { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, + { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } + }, meta: "Super")) .Bind().ToFunc(() => KeyboardDevice) .Bind().ToConstant(new X11CursorFactory(Display)) .Bind().ToConstant(new X11Clipboard(this)) diff --git a/src/Browser/Avalonia.Browser/WindowingPlatform.cs b/src/Browser/Avalonia.Browser/WindowingPlatform.cs index e344db3d73c..f2de4dfeea3 100644 --- a/src/Browser/Avalonia.Browser/WindowingPlatform.cs +++ b/src/Browser/Avalonia.Browser/WindowingPlatform.cs @@ -70,6 +70,11 @@ public static void Register() .Bind().ToConstant(instance) .Bind().ToSingleton() .Bind().ToSingleton() + .Bind().ToConstant(new KeyGestureFormatInfo(new() + { + { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, + { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } + })) .Bind().ToSingleton(); AvaloniaLocator.CurrentMutable.Bind().ToSingleton(); diff --git a/src/Headless/Avalonia.Headless/AvaloniaHeadlessPlatform.cs b/src/Headless/Avalonia.Headless/AvaloniaHeadlessPlatform.cs index 9bb587c9b1a..8fcd1e6a558 100644 --- a/src/Headless/Avalonia.Headless/AvaloniaHeadlessPlatform.cs +++ b/src/Headless/Avalonia.Headless/AvaloniaHeadlessPlatform.cs @@ -76,7 +76,12 @@ internal static void Initialize(AvaloniaHeadlessPlatformOptions opts) .Bind().ToConstant(new KeyboardDevice()) .Bind().ToConstant(new RenderTimer(60)) .Bind().ToConstant(new HeadlessWindowingPlatform(opts.FrameBufferFormat)) - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToConstant(new KeyGestureFormatInfo(new() + { + { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, + { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } + })); Compositor = new Compositor( null); } diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs index d226a89e7d6..6143ddc7ad5 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs @@ -72,7 +72,12 @@ void Initialize() .Bind().ToConstant(new KeyboardDevice()) .Bind().ToSingleton() .Bind().ToSingleton() - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToConstant(new KeyGestureFormatInfo(new() + { + { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, + { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } + }, meta: "Super")); Compositor = new Compositor(AvaloniaLocator.Current.GetService()); } diff --git a/src/Tizen/Avalonia.Tizen/TizenPlatform.cs b/src/Tizen/Avalonia.Tizen/TizenPlatform.cs index c3824a04ada..70084ad48ff 100644 --- a/src/Tizen/Avalonia.Tizen/TizenPlatform.cs +++ b/src/Tizen/Avalonia.Tizen/TizenPlatform.cs @@ -40,6 +40,11 @@ public static void Initialize() .Bind().ToSingleton() .Bind().ToConstant(new TizenRenderTimer()) .Bind().ToSingleton() + .Bind().ToConstant(new KeyGestureFormatInfo(new() + { + { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, + { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } + })) .Bind().ToConstant(GlPlatform = new NuiGlPlatform()); Compositor = new Compositor(AvaloniaLocator.Current.GetService()); diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index d923f382754..789441977cc 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -101,6 +101,11 @@ public static void Initialize(Win32PlatformOptions options) new KeyGesture(Key.F10, KeyModifiers.Shift) } }) + .Bind().ToConstant(new KeyGestureFormatInfo(new() + { + { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, + { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } + }, meta: "Win")) .Bind().ToConstant(s_instance) .Bind().ToConstant(NonPumpingWaitHelperImpl.Instance) .Bind().ToConstant(new WindowsMountedVolumeInfoProvider()) diff --git a/src/iOS/Avalonia.iOS/Platform.cs b/src/iOS/Avalonia.iOS/Platform.cs index 80066394060..f4c300c4e5c 100644 --- a/src/iOS/Avalonia.iOS/Platform.cs +++ b/src/iOS/Avalonia.iOS/Platform.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Avalonia.Controls.ApplicationLifetimes; @@ -83,6 +83,13 @@ public static void Register(IAvaloniaAppDelegate? appDelegate) .Bind().ToSingleton() .Bind().ToConstant(new PlatformIconLoaderStub()) .Bind().ToSingleton() + .Bind().ToConstant(new KeyGestureFormatInfo(new() + { + { Key.Back , "⌫" }, { Key.Down , "↓" }, { Key.End , "↘" }, { Key.Escape , "⎋" }, + { Key.Home , "↖" }, { Key.Left , "←" }, { Key.Return , "↩" }, { Key.PageDown , "⇞" }, + { Key.PageUp , "⇟" }, { Key.Right , "→" }, { Key.Space , "␣" }, { Key.Tab , "⇥" }, + { Key.Up , "↑" } + }, ctrl: "⌃", meta: "⌘", shift: "⇧", alt: "⌥")) .Bind().ToConstant(Timer) .Bind().ToConstant(DispatcherImpl.Instance) .Bind().ToConstant(keyboard); From 648083089b7a2b722049e82e727ef782b6fe6081 Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Mon, 27 May 2024 16:34:11 +1200 Subject: [PATCH 04/10] Using KeyGesture's new IFormattable interface to use platform specific formatting. --- .../Converters/PlatformKeyGestureConverter.cs | 161 +----------------- 1 file changed, 2 insertions(+), 159 deletions(-) diff --git a/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs b/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs index 0fa43809acc..bdb3b6d2443 100644 --- a/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs +++ b/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs @@ -22,7 +22,7 @@ public class PlatformKeyGestureConverter : IValueConverter } else if (value is KeyGesture gesture && targetType == typeof(string)) { - return ToPlatformString(gesture); + return gesture.ToString("p", null); } else { @@ -34,163 +34,6 @@ public class PlatformKeyGestureConverter : IValueConverter { throw new NotImplementedException(); } - - /// - /// Converts a to a string, formatting it according to the current - /// platform's style guidelines. - /// - /// The gesture. - /// The gesture formatted according to the current platform. - public static string ToPlatformString(KeyGesture gesture) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return ToString(gesture, "Win"); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return ToString(gesture, "Super"); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return ToOSXString(gesture); - } - else - { - return gesture.ToString(); - } - } - - private static string ToString(KeyGesture gesture, string meta) - { - var s = StringBuilderCache.Acquire(); - - static void Plus(StringBuilder s) - { - if (s.Length > 0) - { - s.Append("+"); - } - } - - if (gesture.KeyModifiers.HasAllFlags(KeyModifiers.Control)) - { - s.Append("Ctrl"); - } - - if (gesture.KeyModifiers.HasAllFlags(KeyModifiers.Shift)) - { - Plus(s); - s.Append("Shift"); - } - - if (gesture.KeyModifiers.HasAllFlags(KeyModifiers.Alt)) - { - Plus(s); - s.Append("Alt"); - } - - if (gesture.KeyModifiers.HasAllFlags(KeyModifiers.Meta)) - { - Plus(s); - s.Append(meta); - } - - Plus(s); - s.Append(ToString(gesture.Key)); - - return StringBuilderCache.GetStringAndRelease(s); - } - - private static string ToOSXString(KeyGesture gesture) - { - var s = StringBuilderCache.Acquire(); - - if (gesture.KeyModifiers.HasAllFlags(KeyModifiers.Control)) - { - s.Append('⌃'); - } - - if (gesture.KeyModifiers.HasAllFlags(KeyModifiers.Alt)) - { - s.Append('⌥'); - } - - if (gesture.KeyModifiers.HasAllFlags(KeyModifiers.Shift)) - { - s.Append('⇧'); - } - - if (gesture.KeyModifiers.HasAllFlags(KeyModifiers.Meta)) - { - s.Append('⌘'); - } - - s.Append(ToOSXString(gesture.Key)); - - return StringBuilderCache.GetStringAndRelease(s); - } - - private static string ToString(Key key) - { - return key switch - { - Key.Add => "+", - Key.Back => "Backspace", - Key.D0 => "0", - Key.D1 => "1", - Key.D2 => "2", - Key.D3 => "3", - Key.D4 => "4", - Key.D5 => "5", - Key.D6 => "6", - Key.D7 => "7", - Key.D8 => "8", - Key.D9 => "9", - Key.Decimal => ".", - Key.Divide => "/", - Key.Down => "Down Arrow", - Key.Left => "Left Arrow", - Key.Multiply => "*", - Key.OemBackslash => "\\", - Key.OemCloseBrackets => "]", - Key.OemComma => ",", - Key.OemMinus => "-", - Key.OemOpenBrackets => "[", - Key.OemPeriod=> ".", - Key.OemPipe => "|", - Key.OemPlus => "+", - Key.OemQuestion => "/", - Key.OemQuotes => "\"", - Key.OemSemicolon => ";", - Key.OemTilde => "`", - Key.Right => "Right Arrow", - Key.Separator => "/", - Key.Subtract => "-", - Key.Up => "Up Arrow", - _ => key.ToString(), - }; - } - - private static string ToOSXString(Key key) - { - return key switch - { - Key.Back => "⌫", - Key.Down => "↓", - Key.End => "↘", - Key.Escape => "⎋", - Key.Home => "↖", - Key.Left => "←", - Key.Return => "↩", - Key.PageDown => "⇞", - Key.PageUp => "⇟", - Key.Right => "→", - Key.Space => "␣", - Key.Tab => "⇥", - Key.Up => "↑", - _ => ToString(key), - }; - } + } } From c57137a4a1cb29a5389f2ffa372fc818bdf829c0 Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Tue, 28 May 2024 09:16:09 +1200 Subject: [PATCH 05/10] Documenting changes. --- src/Avalonia.Base/Input/KeyGesture.cs | 11 ++++ .../Input/Platform/KeyGestureFormatInfo.cs | 56 +++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Base/Input/KeyGesture.cs b/src/Avalonia.Base/Input/KeyGesture.cs index 224ef787608..f9d6f407876 100644 --- a/src/Avalonia.Base/Input/KeyGesture.cs +++ b/src/Avalonia.Base/Input/KeyGesture.cs @@ -98,6 +98,17 @@ public static KeyGesture Parse(string gesture) public override string ToString() => ToString(null, null); + /// + /// Returns the current KeyGesture as a string formatted according to the format string and appropriate IFormatProvider + /// + /// The format to use. + /// + /// null or "" or "g"The Invariant format, uses Enum.ToString() to format Keys. + /// "p"Use platform specific formatting as registerd. + /// + /// The IFormatProvider to use. If null, uses the appropriate provider registered in the Avalonia Locator, or Invariant. + /// The formatted string. + /// Thrown if the format string is not in the above table. public string ToString(string? format, IFormatProvider? formatProvider) { var formatInfo = format switch diff --git a/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs b/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs index 27ff0716f9e..a87705e91af 100644 --- a/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs +++ b/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs @@ -6,32 +6,68 @@ namespace Avalonia.Input.Platform { + + /// + /// Provides platform specific formatting information for the KeyGesture class + /// + /// A dictionary of Key to String overrides for specific characters, for example Key.Left to "Left Arrow" or "←" on Mac. + /// A null value is assumed to be the Invariant, so the included set of common overrides will be skipped if this is null. If only the common overrides are + /// desired, pass an empty Dictionary instead. + /// The string to use for the Meta modifier, defaults to "Cmd" + /// The string to use for the Ctrl modifier, defaults to "Ctrl" + /// The string to use for the Alt modifier, defaults to "Alt" + /// The string to use for the Shift modifier, defaults to "Shift" public sealed class KeyGestureFormatInfo(Dictionary? platformKeyOverrides = null, string meta = "Cmd", string ctrl = "Ctrl", string alt = "Alt", string shift = "Shift") : IFormatProvider { + /// + /// The Invariant format. Only uses strings straight from the appropriate Enums. + /// public static KeyGestureFormatInfo Invariant { get; } = new(); + /// + /// The string used to represent Meta on the appropriate platform. Defaults to "Cmd". + /// public string Meta { get; } = meta; - + + /// + /// The string used to represent Ctrl on the appropriate platform. Defaults to "Ctrl". + /// public string Ctrl { get; } = ctrl; - + + /// + /// The string used to represent Alt on the appropriate platform. Defaults to "Alt". + /// public string Alt { get; } = alt; - + + /// + /// The string used to represent Shift on the appropriate platform. Defaults to "Shift". + /// public string Shift { get; } = shift; public object? GetFormat(Type? formatType) => formatType == typeof(KeyGestureFormatInfo) ? this : null; + /// + /// Gets the most appropriate KeyGestureFormatInfo for the IFormatProvider requested. This will be, in order: + /// 1. The provided IFormatProvider as a KeyGestureFormatInfo + /// 2. The currently registered platform specific KeyGestureFormatInfo, if present. + /// 3. The Invariant otherwise. + /// + /// The IFormatProvider to get a KeyGestureFormatInfo for. + /// public static KeyGestureFormatInfo GetInstance(IFormatProvider? formatProvider) => formatProvider?.GetFormat(typeof(KeyGestureFormatInfo)) as KeyGestureFormatInfo ?? AvaloniaLocator.Current.GetService() ?? Invariant; - /* A dictionary of the common platform Key overrides. These are used as a fallback - * if platformKeyOverrides doesn't contain the Key in question. - */ + /// + /// A dictionary of the common platform Key overrides. These are used as a fallback + /// if platformKeyOverrides doesn't contain the Key in question. + /// + private static readonly Dictionary s_commonKeyOverrides = new() { { Key.Add , "+" }, @@ -64,6 +100,14 @@ public static KeyGestureFormatInfo GetInstance(IFormatProvider? formatProvider) { Key.Subtract , "-" } }; + /// + /// Checks the platformKeyOverrides and s_commonKeyOverrides Dictionaries, in order, for the appropriate + /// string to represent the given Key on this platform. + /// NOTE: If platformKeyOverrides is null, this is assumed to be the Invariant and the Dictionaries are not checked. + /// The plain Enum string is returned instead. + /// + /// The Key to format. + /// The appropriate platform specific or common override if present, key.ToString() if not or this is the Invariant. public string FormatKey(Key key) { /* From 448f947c4dce5c0fb99f6656caa3de073589d24a Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Tue, 28 May 2024 09:16:09 +1200 Subject: [PATCH 06/10] Documenting changes. --- src/Avalonia.Base/Input/KeyGesture.cs | 11 ++++ .../Input/Platform/KeyGestureFormatInfo.cs | 56 +++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Base/Input/KeyGesture.cs b/src/Avalonia.Base/Input/KeyGesture.cs index 224ef787608..122176a1272 100644 --- a/src/Avalonia.Base/Input/KeyGesture.cs +++ b/src/Avalonia.Base/Input/KeyGesture.cs @@ -98,6 +98,17 @@ public static KeyGesture Parse(string gesture) public override string ToString() => ToString(null, null); + /// + /// Returns the current KeyGesture as a string formatted according to the format string and appropriate IFormatProvider + /// + /// The format to use. + /// + /// null or "" or "g"The Invariant format, uses Enum.ToString() to format Keys. + /// "p"Use platform specific formatting as registerd. + /// + /// The IFormatProvider to use. If null, uses the appropriate provider registered in the Avalonia Locator, or Invariant. + /// The formatted string. + /// Thrown if the format string is not null, "", "g", or "p" public string ToString(string? format, IFormatProvider? formatProvider) { var formatInfo = format switch diff --git a/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs b/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs index 27ff0716f9e..a87705e91af 100644 --- a/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs +++ b/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs @@ -6,32 +6,68 @@ namespace Avalonia.Input.Platform { + + /// + /// Provides platform specific formatting information for the KeyGesture class + /// + /// A dictionary of Key to String overrides for specific characters, for example Key.Left to "Left Arrow" or "←" on Mac. + /// A null value is assumed to be the Invariant, so the included set of common overrides will be skipped if this is null. If only the common overrides are + /// desired, pass an empty Dictionary instead. + /// The string to use for the Meta modifier, defaults to "Cmd" + /// The string to use for the Ctrl modifier, defaults to "Ctrl" + /// The string to use for the Alt modifier, defaults to "Alt" + /// The string to use for the Shift modifier, defaults to "Shift" public sealed class KeyGestureFormatInfo(Dictionary? platformKeyOverrides = null, string meta = "Cmd", string ctrl = "Ctrl", string alt = "Alt", string shift = "Shift") : IFormatProvider { + /// + /// The Invariant format. Only uses strings straight from the appropriate Enums. + /// public static KeyGestureFormatInfo Invariant { get; } = new(); + /// + /// The string used to represent Meta on the appropriate platform. Defaults to "Cmd". + /// public string Meta { get; } = meta; - + + /// + /// The string used to represent Ctrl on the appropriate platform. Defaults to "Ctrl". + /// public string Ctrl { get; } = ctrl; - + + /// + /// The string used to represent Alt on the appropriate platform. Defaults to "Alt". + /// public string Alt { get; } = alt; - + + /// + /// The string used to represent Shift on the appropriate platform. Defaults to "Shift". + /// public string Shift { get; } = shift; public object? GetFormat(Type? formatType) => formatType == typeof(KeyGestureFormatInfo) ? this : null; + /// + /// Gets the most appropriate KeyGestureFormatInfo for the IFormatProvider requested. This will be, in order: + /// 1. The provided IFormatProvider as a KeyGestureFormatInfo + /// 2. The currently registered platform specific KeyGestureFormatInfo, if present. + /// 3. The Invariant otherwise. + /// + /// The IFormatProvider to get a KeyGestureFormatInfo for. + /// public static KeyGestureFormatInfo GetInstance(IFormatProvider? formatProvider) => formatProvider?.GetFormat(typeof(KeyGestureFormatInfo)) as KeyGestureFormatInfo ?? AvaloniaLocator.Current.GetService() ?? Invariant; - /* A dictionary of the common platform Key overrides. These are used as a fallback - * if platformKeyOverrides doesn't contain the Key in question. - */ + /// + /// A dictionary of the common platform Key overrides. These are used as a fallback + /// if platformKeyOverrides doesn't contain the Key in question. + /// + private static readonly Dictionary s_commonKeyOverrides = new() { { Key.Add , "+" }, @@ -64,6 +100,14 @@ public static KeyGestureFormatInfo GetInstance(IFormatProvider? formatProvider) { Key.Subtract , "-" } }; + /// + /// Checks the platformKeyOverrides and s_commonKeyOverrides Dictionaries, in order, for the appropriate + /// string to represent the given Key on this platform. + /// NOTE: If platformKeyOverrides is null, this is assumed to be the Invariant and the Dictionaries are not checked. + /// The plain Enum string is returned instead. + /// + /// The Key to format. + /// The appropriate platform specific or common override if present, key.ToString() if not or this is the Invariant. public string FormatKey(Key key) { /* From 7550c24cf3fcc6b6c03960f934ac8f468cf00aad Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Tue, 28 May 2024 10:16:45 +1200 Subject: [PATCH 07/10] Putting back ToPlatformString() so I don't break the API. --- .../Converters/PlatformKeyGestureConverter.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs b/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs index bdb3b6d2443..03b3706588b 100644 --- a/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs +++ b/src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs @@ -34,6 +34,14 @@ public class PlatformKeyGestureConverter : IValueConverter { throw new NotImplementedException(); } + + /// + /// Converts a to a string, formatting it according to the current + /// platform's style guidelines. + /// + /// The gesture. + /// The gesture formatted according to the current platform. + public static string ToPlatformString(KeyGesture gesture) => gesture.ToString("p", null); } } From 7a7685b937515b3330bd0b4c1a580385efe85924 Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Tue, 28 May 2024 14:11:27 +1200 Subject: [PATCH 08/10] Swapping Page Up and Page Down symbols on Apple platforms. --- src/Avalonia.Native/AvaloniaNativePlatform.cs | 4 ++-- src/iOS/Avalonia.iOS/Platform.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index 52f1f49dee6..29f26baf62c 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -127,8 +127,8 @@ void DoInitialize(AvaloniaNativePlatformOptions options) AvaloniaLocator.CurrentMutable.Bind().ToConstant(new KeyGestureFormatInfo(new() { { Key.Back , "⌫" }, { Key.Down , "↓" }, { Key.End , "↘" }, { Key.Escape , "⎋" }, - { Key.Home , "↖" }, { Key.Left , "←" }, { Key.Return , "↩" }, { Key.PageDown , "⇞" }, - { Key.PageUp , "⇟" }, { Key.Right , "→" }, { Key.Space , "␣" }, { Key.Tab , "⇥" }, + { Key.Home , "↖" }, { Key.Left , "←" }, { Key.Return , "↩" }, { Key.PageDown , "⇟" }, + { Key.PageUp , "⇞" }, { Key.Right , "→" }, { Key.Space , "␣" }, { Key.Tab , "⇥" }, { Key.Up , "↑" } }, ctrl: "⌃", meta: "⌘", shift: "⇧", alt: "⌥")); diff --git a/src/iOS/Avalonia.iOS/Platform.cs b/src/iOS/Avalonia.iOS/Platform.cs index f4c300c4e5c..bb4cceebfbb 100644 --- a/src/iOS/Avalonia.iOS/Platform.cs +++ b/src/iOS/Avalonia.iOS/Platform.cs @@ -86,8 +86,8 @@ public static void Register(IAvaloniaAppDelegate? appDelegate) .Bind().ToConstant(new KeyGestureFormatInfo(new() { { Key.Back , "⌫" }, { Key.Down , "↓" }, { Key.End , "↘" }, { Key.Escape , "⎋" }, - { Key.Home , "↖" }, { Key.Left , "←" }, { Key.Return , "↩" }, { Key.PageDown , "⇞" }, - { Key.PageUp , "⇟" }, { Key.Right , "→" }, { Key.Space , "␣" }, { Key.Tab , "⇥" }, + { Key.Home , "↖" }, { Key.Left , "←" }, { Key.Return , "↩" }, { Key.PageDown , "⇟" }, + { Key.PageUp , "⇞" }, { Key.Right , "→" }, { Key.Space , "␣" }, { Key.Tab , "⇥" }, { Key.Up , "↑" } }, ctrl: "⌃", meta: "⌘", shift: "⇧", alt: "⌥")) .Bind().ToConstant(Timer) From 2a31f076fba147b39d561d9e728f5740e30e8682 Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Thu, 30 May 2024 09:50:23 +1200 Subject: [PATCH 09/10] Changing KeyGestureFormatInfo constructor Dictionary parameter to IReadOnlyDictionary along with moving Arrow key and Backspace key overrides to the common dictionary. Only Apple platforms are now overriding Keys explicitly. --- src/Android/Avalonia.Android/AndroidPlatform.cs | 6 +----- src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs | 9 +++++++-- src/Avalonia.Native/AvaloniaNativePlatform.cs | 3 ++- src/Avalonia.X11/X11Platform.cs | 6 +----- src/Browser/Avalonia.Browser/WindowingPlatform.cs | 7 ++----- .../Avalonia.Headless/AvaloniaHeadlessPlatform.cs | 7 ++----- .../LinuxFramebufferPlatform.cs | 7 ++----- src/Tizen/Avalonia.Tizen/TizenPlatform.cs | 6 +----- src/Windows/Avalonia.Win32/Win32Platform.cs | 7 ++----- src/iOS/Avalonia.iOS/Platform.cs | 2 +- 10 files changed, 21 insertions(+), 39 deletions(-) diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs index 85e7534feb8..0d2ae2c1ca5 100644 --- a/src/Android/Avalonia.Android/AndroidPlatform.cs +++ b/src/Android/Avalonia.Android/AndroidPlatform.cs @@ -88,11 +88,7 @@ public static void Initialize() .Bind().ToSingleton() .Bind().ToConstant(new ChoreographerTimer()) .Bind().ToSingleton() - .Bind().ToConstant(new KeyGestureFormatInfo(new() - { - { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, - { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } - })) + .Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary() { })) .Bind().ToConstant(new AndroidActivatableLifetime()); var graphics = InitializeGraphics(Options); diff --git a/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs b/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs index a87705e91af..9eb95bf3f85 100644 --- a/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs +++ b/src/Avalonia.Base/Input/Platform/KeyGestureFormatInfo.cs @@ -17,7 +17,7 @@ namespace Avalonia.Input.Platform /// The string to use for the Ctrl modifier, defaults to "Ctrl" /// The string to use for the Alt modifier, defaults to "Alt" /// The string to use for the Shift modifier, defaults to "Shift" - public sealed class KeyGestureFormatInfo(Dictionary? platformKeyOverrides = null, + public sealed class KeyGestureFormatInfo(IReadOnlyDictionary? platformKeyOverrides = null, string meta = "Cmd", string ctrl = "Ctrl", string alt = "Alt", @@ -97,7 +97,12 @@ public static KeyGestureFormatInfo GetInstance(IFormatProvider? formatProvider) { Key.OemSemicolon , ";" }, { Key.OemTilde , "`" }, { Key.Separator , "/" }, - { Key.Subtract , "-" } + { Key.Subtract , "-" }, + { Key.Back , "Backspace" }, + { Key.Down , "Down Arrow" }, + { Key.Left , "Left Arrow" }, + { Key.Right , "Right Arrow" }, + { Key.Up , "Up Arrow" } }; /// diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index 29f26baf62c..41cc6edd36c 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using Avalonia.Compatibility; using Avalonia.Controls.ApplicationLifetimes; @@ -124,7 +125,7 @@ void DoInitialize(AvaloniaNativePlatformOptions options) AvaloniaLocator.CurrentMutable.Bind().ToConstant(hotkeys); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new KeyGestureFormatInfo(new() + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary() { { Key.Back , "⌫" }, { Key.Down , "↓" }, { Key.End , "↘" }, { Key.Escape , "⎋" }, { Key.Home , "↖" }, { Key.Left , "←" }, { Key.Return , "↩" }, { Key.PageDown , "⇟" }, diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 420938c799f..26046402a16 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -81,11 +81,7 @@ public void Initialize(X11PlatformOptions options) .Bind().ToConstant(new X11PlatformThreading(this)) .Bind().ToConstant(timer) .Bind().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Control)) - .Bind().ToConstant(new KeyGestureFormatInfo(new() - { - { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, - { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } - }, meta: "Super")) + .Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary() { }, meta: "Super")) .Bind().ToFunc(() => KeyboardDevice) .Bind().ToConstant(new X11CursorFactory(Display)) .Bind().ToConstant(new X11Clipboard(this)) diff --git a/src/Browser/Avalonia.Browser/WindowingPlatform.cs b/src/Browser/Avalonia.Browser/WindowingPlatform.cs index f2de4dfeea3..bcc0a4a8017 100644 --- a/src/Browser/Avalonia.Browser/WindowingPlatform.cs +++ b/src/Browser/Avalonia.Browser/WindowingPlatform.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Reflection; using System.Threading; using Avalonia.Browser.Interop; @@ -70,11 +71,7 @@ public static void Register() .Bind().ToConstant(instance) .Bind().ToSingleton() .Bind().ToSingleton() - .Bind().ToConstant(new KeyGestureFormatInfo(new() - { - { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, - { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } - })) + .Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary() { })) .Bind().ToSingleton(); AvaloniaLocator.CurrentMutable.Bind().ToSingleton(); diff --git a/src/Headless/Avalonia.Headless/AvaloniaHeadlessPlatform.cs b/src/Headless/Avalonia.Headless/AvaloniaHeadlessPlatform.cs index 8fcd1e6a558..0dbb9e845e5 100644 --- a/src/Headless/Avalonia.Headless/AvaloniaHeadlessPlatform.cs +++ b/src/Headless/Avalonia.Headless/AvaloniaHeadlessPlatform.cs @@ -8,6 +8,7 @@ using Avalonia.Rendering; using Avalonia.Rendering.Composition; using Avalonia.Threading; +using System.Collections.Generic; namespace Avalonia.Headless { @@ -77,11 +78,7 @@ internal static void Initialize(AvaloniaHeadlessPlatformOptions opts) .Bind().ToConstant(new RenderTimer(60)) .Bind().ToConstant(new HeadlessWindowingPlatform(opts.FrameBufferFormat)) .Bind().ToSingleton() - .Bind().ToConstant(new KeyGestureFormatInfo(new() - { - { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, - { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } - })); + .Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary() { })); Compositor = new Compositor( null); } diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs index 6143ddc7ad5..2bddc4ce29d 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; @@ -73,11 +74,7 @@ void Initialize() .Bind().ToSingleton() .Bind().ToSingleton() .Bind().ToSingleton() - .Bind().ToConstant(new KeyGestureFormatInfo(new() - { - { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, - { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } - }, meta: "Super")); + .Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary() { }, meta: "Super")); Compositor = new Compositor(AvaloniaLocator.Current.GetService()); } diff --git a/src/Tizen/Avalonia.Tizen/TizenPlatform.cs b/src/Tizen/Avalonia.Tizen/TizenPlatform.cs index 70084ad48ff..ff083389e3a 100644 --- a/src/Tizen/Avalonia.Tizen/TizenPlatform.cs +++ b/src/Tizen/Avalonia.Tizen/TizenPlatform.cs @@ -40,11 +40,7 @@ public static void Initialize() .Bind().ToSingleton() .Bind().ToConstant(new TizenRenderTimer()) .Bind().ToSingleton() - .Bind().ToConstant(new KeyGestureFormatInfo(new() - { - { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, - { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } - })) + .Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary() { })) .Bind().ToConstant(GlPlatform = new NuiGlPlatform()); Compositor = new Compositor(AvaloniaLocator.Current.GetService()); diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index 789441977cc..85add81344b 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -18,6 +18,7 @@ using Avalonia.Win32.Input; using Avalonia.Win32.Interop; using static Avalonia.Win32.Interop.UnmanagedMethods; +using System.Collections.Generic; namespace Avalonia { @@ -101,11 +102,7 @@ public static void Initialize(Win32PlatformOptions options) new KeyGesture(Key.F10, KeyModifiers.Shift) } }) - .Bind().ToConstant(new KeyGestureFormatInfo(new() - { - { Key.Back , "Backspace" }, { Key.Down , "Down Arrow" }, { Key.Left , "Left Arrow" }, - { Key.Right , "Right Arrow" }, { Key.Up , "Up Arrow" } - }, meta: "Win")) + .Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary() { }, meta: "Win")) .Bind().ToConstant(s_instance) .Bind().ToConstant(NonPumpingWaitHelperImpl.Instance) .Bind().ToConstant(new WindowsMountedVolumeInfoProvider()) diff --git a/src/iOS/Avalonia.iOS/Platform.cs b/src/iOS/Avalonia.iOS/Platform.cs index bb4cceebfbb..e2ce25010f0 100644 --- a/src/iOS/Avalonia.iOS/Platform.cs +++ b/src/iOS/Avalonia.iOS/Platform.cs @@ -83,7 +83,7 @@ public static void Register(IAvaloniaAppDelegate? appDelegate) .Bind().ToSingleton() .Bind().ToConstant(new PlatformIconLoaderStub()) .Bind().ToSingleton() - .Bind().ToConstant(new KeyGestureFormatInfo(new() + .Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary() { { Key.Back , "⌫" }, { Key.Down , "↓" }, { Key.End , "↘" }, { Key.Escape , "⎋" }, { Key.Home , "↖" }, { Key.Left , "←" }, { Key.Return , "↩" }, { Key.PageDown , "⇟" }, From 0ad8ef65a2310c82d19a884910b2c9ab386f2881 Mon Sep 17 00:00:00 2001 From: Ian Rawley Date: Thu, 30 May 2024 09:51:58 +1200 Subject: [PATCH 10/10] Undoing addition to MenuPage that was never intended to be committed. --- samples/ControlCatalog/Pages/MenuPage.xaml | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/MenuPage.xaml b/samples/ControlCatalog/Pages/MenuPage.xaml index ab696fe448b..bbcc759ca70 100644 --- a/samples/ControlCatalog/Pages/MenuPage.xaml +++ b/samples/ControlCatalog/Pages/MenuPage.xaml @@ -16,7 +16,6 @@ -