实现类似WPF的KeyBoard,命名为Input类。
代码如下
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Interactivity;
using Avalonia.Threading;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Shares.Avalonia
{
public class Input
{
public static event EventHandler<KeyEventArgs>? PreviewKeyDown;
public static event EventHandler<KeyEventArgs>? KeyDown;
public static event EventHandler<KeyEventArgs>? PreviewKeyUp;
public static event EventHandler<KeyEventArgs>? KeyUp;
public static event EventHandler<TextInputEventArgs>? PreTextInput;
public static event EventHandler<TextInputEventArgs>? TextInput;
private static readonly HashSet<Key> keysDown = new();
private static readonly HashSet<Key> keysUp = new();
private static FocusManager? focusManager = AvaloniaExtensions.GetService<FocusManager>();
private static IDisposable? subsription;
private static RoutingStrategies route;
public static RoutingStrategies Route
{
get
{
return route;
}
set
{
if (subsription != null)
subsription.Dispose();
string routing = "PreProcess";
if (value.HasFlag(RoutingStrategies.Bubble))
routing = "PostProcess";
else if (value.HasFlag(RoutingStrategies.Direct))
routing = "Process";
var process = inputManager?.GetPropertyValue<IObservable<RawInputEventArgs>?>(routing);
subsription = process?.Subscribe(OnRawEvent);
route = value;
}
}
public static KeyModifiers KeyModifiers { get; private set; }
public static bool IsRepeat { get; private set; }
public static bool IsToggled { get; private set; }
private static KeyboardDevice? device;
private static IInputManager? inputManager;
static Input()
{
device = AvaloniaExtensions.GetService<KeyboardDevice>();
inputManager = device?.GetPropertyValue<IInputManager?>("InputManager");
}
private static void OnRawEvent(RawInputEventArgs e)
{
switch (e)
{
case RawKeyEventArgs keyEvent:
HandleKeyEvent(keyEvent);
break;
case RawTextInputEventArgs textInputEvent:
HandleTextInputEvent(textInputEvent);
break;
}
}
private static void HandleKeyEvent(RawKeyEventArgs e)
{
var type = e.GetPropertyValue<RawKeyEventType>("Type");
var key = e.GetPropertyValue<Key>("Key");
var physicalKey = e.GetPropertyValue<PhysicalKey>("PhysicalKey");
var keySymbol = e.GetPropertyValue<string?>("KeySymbol");
var keyDeviceType = e.GetPropertyValue<KeyDeviceType>("KeyDeviceType");
var source = GetFocus();
KeyModifiers = (KeyModifiers)e.GetPropertyValue<RawInputModifiers>("Modifiers");
var previewArgs = new KeyEventArgs()
{
Key = key,
KeyModifiers = KeyModifiers,
PhysicalKey = physicalKey,
KeySymbol = keySymbol,
KeyDeviceType = keyDeviceType,
Handled = false,
Source = source,
Route = Route
};
switch (type)
{
case RawKeyEventType.KeyDown:
{
keysUp.Remove(key);
previewArgs.RoutedEvent = InputElement.KeyDownEvent;
IsRepeat = !keysDown.Add(key);
if (key == Key.CapsLock || key == Key.NumLock || key == Key.Scroll)
IsToggled = !IsToggled;
PreviewKeyDown?.Invoke(source, previewArgs);
if (!previewArgs.Handled)
{
KeyDown?.Invoke(source, previewArgs);
}
}
break;
case RawKeyEventType.KeyUp:
{
keysDown.Remove(key);
previewArgs.RoutedEvent = InputElement.KeyUpEvent;
IsRepeat = !keysUp.Add(key);
PreviewKeyUp?.Invoke(source, previewArgs);
if (!previewArgs.Handled)
{
KeyUp?.Invoke(source, previewArgs);
}
}
break;
}
e.SetPropertyValue<bool>("Handled", previewArgs.Handled);
}
private static void HandleTextInputEvent(RawTextInputEventArgs e)
{
var text = e.GetPropertyValue<string>("Text");
var source = GetFocus();
var previewArgs = new TextInputEventArgs()
{
Text = text,
RoutedEvent = InputElement.TextInputEvent,
Handled = false,
Source = source,
Route = Route
};
PreTextInput?.Invoke(source, previewArgs);
if (!previewArgs.Handled)
{
TextInput?.Invoke(source, previewArgs);
}
e.SetPropertyValue<bool>("Handled", previewArgs.Handled);
}
public static bool IsKeyDown(Key key)
{
return keysDown.Contains(key);
}
public static bool IsKeyUp(Key key)
{
return keysUp.Contains(key);
}
public static IInputElement? GetFocus()
{
return focusManager?.InvokeMethod<IInputElement>("GetFocusedElement");
}
public static bool SetFocus(IInputElement inputElement)
{
return (bool)(focusManager?.InvokeMethod("Focus",
new object[] { inputElement, NavigationMethod.Unspecified, KeyModifiers.None })!);
}
public static void ClearFocus()
{
focusManager?.InvokeMethod("ClearFocus");
}
}
}
KeyModifiers.axaml代码
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="300" Width="300" x:Class="AvaloniaUI.KeyModifiers" Title="KeyModifiers"> <StackPanel Margin="5"> <TextBox KeyDown="KeyEvent"></TextBox> <TextBlock Name="lblInfo"></TextBlock> <Button Click="CheckShift">Check Current Shift State</Button> </StackPanel> </Window>
KeyModifiers.axaml.cs代码
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Shares.Avalonia;
using System;
using System.Threading.Tasks;
namespace AvaloniaUI;
public partial class KeyModifiers : Window
{
public KeyModifiers()
{
InitializeComponent();
Input.Route = RoutingStrategies.Tunnel;
}
private void KeyEvent(object? sender, KeyEventArgs e)
{
lblInfo.Text = $"Modifiers: " + e.KeyModifiers.ToString();
if (e.KeyModifiers.HasFlag(Avalonia.Input.KeyModifiers.Control))
{
lblInfo.Text += "\r\nYou held the Control key.";
}
}
private void CheckShift(object? sender, RoutedEventArgs e)
{
if (Input.IsKeyDown(Key.LeftShift))
lblInfo.Text = "The left Shift is held down.";
else
lblInfo.Text = "The left Shift is not held down.";
}
}
运行效果

浙公网安备 33010602011771号