A cross-platform UI framework for .NET
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.
 
 
 

101 lines
3.4 KiB

using System;
using Avalonia.VisualTree;
namespace Avalonia.Input.TextInput
{
internal class TextInputMethodManager
{
private ITextInputMethodImpl? _im;
private IInputElement? _focusedElement;
private ITextInputMethodClient? _client;
private readonly TransformTrackingHelper _transformTracker = new TransformTrackingHelper();
public TextInputMethodManager() => _transformTracker.MatrixChanged += UpdateCursorRect;
private ITextInputMethodClient? Client
{
get => _client;
set
{
if(_client == value)
return;
if (_client != null)
{
_client.CursorRectangleChanged -= OnCursorRectangleChanged;
_client.TextViewVisualChanged -= OnTextViewVisualChanged;
}
_client = value;
if (_client != null)
{
_client.CursorRectangleChanged += OnCursorRectangleChanged;
_client.TextViewVisualChanged += OnTextViewVisualChanged;
var optionsQuery = new TextInputOptionsQueryEventArgs
{
RoutedEvent = InputElement.TextInputOptionsQueryEvent
};
_focusedElement?.RaiseEvent(optionsQuery);
_im?.Reset();
_im?.SetOptions(optionsQuery);
_transformTracker?.SetVisual(_client?.TextViewVisual);
UpdateCursorRect();
_im?.SetActive(true);
}
else
{
_im?.SetActive(false);
_transformTracker.SetVisual(null);
}
}
}
private void OnTextViewVisualChanged(object sender, EventArgs e)
=> _transformTracker.SetVisual(_client?.TextViewVisual);
private void UpdateCursorRect()
{
if (_im == null || _client == null || _focusedElement?.VisualRoot == null)
return;
var transform = _focusedElement.TransformToVisual(_focusedElement.VisualRoot);
if (transform == null)
_im.SetCursorRect(default);
else
_im.SetCursorRect(_client.CursorRectangle.TransformToAABB(transform.Value));
}
private void OnCursorRectangleChanged(object sender, EventArgs e)
{
if (sender == _client)
UpdateCursorRect();
}
public void SetFocusedElement(IInputElement? element)
{
if(_focusedElement == element)
return;
_focusedElement = element;
var inputMethod = (element?.VisualRoot as ITextInputMethodRoot)?.InputMethod;
if(_im != inputMethod)
_im?.SetActive(false);
_im = inputMethod;
if (_focusedElement == null || _im == null)
{
Client = null;
_im?.SetActive(false);
return;
}
var clientQuery = new TextInputMethodClientRequestedEventArgs
{
RoutedEvent = InputElement.TextInputMethodClientRequestedEvent
};
_focusedElement.RaiseEvent(clientQuery);
Client = clientQuery.Client;
}
}
}