using System; using System.Collections.Generic; using System.Linq; using Avalonia.Input; using Avalonia.Interactivity; namespace Avalonia.Controls { /// /// Handles access keys within a /// internal class MenuItemAccessKeyHandler : IAccessKeyHandler { /// /// The registered access keys. /// private readonly List<(string AccessKey, IInputElement Element)> _registered = new(); /// /// The window to which the handler belongs. /// private IInputRoot? _owner; /// /// Gets or sets the window's main menu. /// /// /// This property is ignored as a menu item cannot have a main menu. /// public IMainMenu? MainMenu { get; set; } /// /// Sets the owner of the access key handler. /// /// The owner. /// /// This method can only be called once, typically by the owner itself on creation. /// public void SetOwner(IInputRoot owner) { _ = owner ?? throw new ArgumentNullException(nameof(owner)); if (_owner != null) { throw new InvalidOperationException("AccessKeyHandler owner has already been set."); } _owner = owner; _owner.AddHandler(InputElement.TextInputEvent, OnTextInput); } /// /// Registers an input element to be associated with an access key. /// /// The access key. /// The input element. public void Register(char accessKey, IInputElement element) { var existing = _registered.FirstOrDefault(x => x.Item2 == element); if (existing != default) { _registered.Remove(existing); } _registered.Add((accessKey.ToString().ToUpperInvariant(), element)); } /// /// Unregisters the access keys associated with the input element. /// /// The input element. public void Unregister(IInputElement element) { foreach (var i in _registered.Where(x => x.Item2 == element).ToList()) { _registered.Remove(i); } } /// /// Handles a key being pressed in the menu. /// /// The event sender. /// The event args. protected virtual void OnTextInput(object? sender, TextInputEventArgs e) { if (!string.IsNullOrWhiteSpace(e.Text)) { var text = e.Text; var focus = _registered .FirstOrDefault(x => string.Equals(x.AccessKey, text, StringComparison.OrdinalIgnoreCase) && x.Element.IsEffectivelyVisible).Element; focus?.RaiseEvent(new RoutedEventArgs(AccessKeyHandler.AccessKeyPressedEvent)); e.Handled = true; } } } }