csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
4.7 KiB
134 lines
4.7 KiB
// 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
|
|
{
|
|
/// <summary>
|
|
/// Handles keyboard navigation for a window.
|
|
/// </summary>
|
|
public class KeyboardNavigationHandler : IKeyboardNavigationHandler
|
|
{
|
|
/// <summary>
|
|
/// The window to which the handler belongs.
|
|
/// </summary>
|
|
private IInputRoot _owner;
|
|
|
|
/// <summary>
|
|
/// Sets the owner of the keyboard navigation handler.
|
|
/// </summary>
|
|
/// <param name="owner">The owner.</param>
|
|
/// <remarks>
|
|
/// This method can only be called once, typically by the owner itself on creation.
|
|
/// </remarks>
|
|
public void SetOwner(IInputRoot owner)
|
|
{
|
|
Contract.Requires<ArgumentNullException>(owner != null);
|
|
|
|
if (_owner != null)
|
|
{
|
|
throw new InvalidOperationException("AccessKeyHandler owner has already been set.");
|
|
}
|
|
|
|
_owner = owner;
|
|
|
|
_owner.AddHandler(InputElement.KeyDownEvent, OnKeyDown);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the next control in the specified navigation direction.
|
|
/// </summary>
|
|
/// <param name="element">The element.</param>
|
|
/// <param name="direction">The navigation direction.</param>
|
|
/// <returns>
|
|
/// The next element in the specified direction, or null if <paramref name="element"/>
|
|
/// was the last in therequested direction.
|
|
/// </returns>
|
|
public static IInputElement GetNext(
|
|
IInputElement element,
|
|
NavigationDirection direction)
|
|
{
|
|
Contract.Requires<ArgumentNullException>(element != null);
|
|
|
|
var customHandler = element.GetSelfAndVisualAncestors()
|
|
.OfType<ICustomKeyboardNavigation>()
|
|
.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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Moves the focus in the specified direction.
|
|
/// </summary>
|
|
/// <param name="element">The current element.</param>
|
|
/// <param name="direction">The direction to move.</param>
|
|
/// <param name="modifiers">Any input modifiers active at the time of focus.</param>
|
|
public void Move(
|
|
IInputElement element,
|
|
NavigationDirection direction,
|
|
InputModifiers modifiers = InputModifiers.None)
|
|
{
|
|
Contract.Requires<ArgumentNullException>(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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the Tab key being pressed in the window.
|
|
/// </summary>
|
|
/// <param name="sender">The event sender.</param>
|
|
/// <param name="e">The event args.</param>
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|