// Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; using System.Linq; using Avalonia.Input.Navigation; using Avalonia.VisualTree; namespace Avalonia.Input { /// /// Handles keyboard navigation for a window. /// public class KeyboardNavigationHandler : IKeyboardNavigationHandler { /// /// The window to which the handler belongs. /// private IInputRoot _owner; /// /// Sets the owner of the keyboard navigation handler. /// /// The owner. /// /// This method can only be called once, typically by the owner itself on creation. /// public void SetOwner(IInputRoot owner) { Contract.Requires(owner != null); if (_owner != null) { throw new InvalidOperationException("AccessKeyHandler owner has already been set."); } _owner = owner; _owner.AddHandler(InputElement.KeyDownEvent, OnKeyDown); } /// /// Gets the next control in the specified navigation direction. /// /// The element. /// The navigation direction. /// /// The next element in the specified direction, or null if /// was the last in therequested direction. /// public static IInputElement GetNext( IInputElement element, NavigationDirection direction) { Contract.Requires(element != null); var customHandler = element.GetSelfAndVisualAncestors() .OfType() .FirstOrDefault(); if (customHandler != null) { var (handled, next) = customHandler.GetNext(element, direction); if (handled) { if (next != null) { return next; } else if (direction == NavigationDirection.Next || direction == NavigationDirection.Previous) { return TabNavigation.GetNextInTabOrder((IInputElement)customHandler, direction, true); } else { return null; } } } if (direction == NavigationDirection.Next || direction == NavigationDirection.Previous) { return TabNavigation.GetNextInTabOrder(element, direction); } else { throw new NotSupportedException(); } } /// /// Moves the focus in the specified direction. /// /// The current element. /// The direction to move. /// Any input modifiers active at the time of focus. public void Move( IInputElement element, NavigationDirection direction, InputModifiers modifiers = InputModifiers.None) { Contract.Requires(element != null); var next = GetNext(element, direction); if (next != null) { var method = direction == NavigationDirection.Next || direction == NavigationDirection.Previous ? NavigationMethod.Tab : NavigationMethod.Directional; FocusManager.Instance.Focus(next, method, modifiers); } } /// /// Handles the Tab key being pressed in the window. /// /// The event sender. /// The event args. protected virtual void OnKeyDown(object sender, KeyEventArgs e) { var current = FocusManager.Instance.Current; if (current != null && e.Key == Key.Tab) { var direction = (e.Modifiers & InputModifiers.Shift) == 0 ? NavigationDirection.Next : NavigationDirection.Previous; Move(current, direction, e.Modifiers); e.Handled = true; } } } }