Browse Source

Added PluggableTextInputMethod API

pull/19486/head
Nikita Tsukanov 7 months ago
parent
commit
57ac0cc7fb
  1. 47
      src/Avalonia.Base/Input/TextInput/InputMethodManager.cs
  2. 57
      src/Avalonia.Base/Input/TextInput/PluggableTextInputMethod.cs

47
src/Avalonia.Base/Input/TextInput/InputMethodManager.cs

@ -88,7 +88,7 @@ namespace Avalonia.Input.TextInput
{
if (ReferenceEquals(obj.Sender, _focusedElement))
{
TryFindAndApplyClient();
RediscoverInputMethodAndClient();
}
}
@ -132,42 +132,59 @@ namespace Avalonia.Input.TextInput
InputMethod.AddTextInputMethodClientRequeryRequestedHandler(_visualRoot,
TextInputMethodClientRequeryRequested);
var inputMethod = ((element as Visual)?.VisualRoot as ITextInputMethodRoot)?.InputMethod;
if (_im != inputMethod)
{
_im?.SetClient(null);
}
RediscoverInputMethodAndClient();
}
void RediscoverInputMethodAndClient()
{
var (inputMethod, inputClient) = FindInputMethodAndClient();
// Reset the previous input method and our state on input method change
if (_im != inputMethod)
Client = null;
_im = inputMethod;
TryFindAndApplyClient();
Client = inputClient;
}
private void TextInputMethodClientRequeryRequested(object? sender, RoutedEventArgs e)
{
if (_im != null)
TryFindAndApplyClient();
RediscoverInputMethodAndClient();
}
private void TryFindAndApplyClient()
private (ITextInputMethodImpl? im, TextInputMethodClient? client) FindInputMethodAndClient()
{
if (_focusedElement is not InputElement focused ||
_im == null ||
!InputMethod.GetIsInputMethodEnabled(focused))
{
Client = null;
return;
// Input method system is disabled by focused element
return (null, null);
}
// Attempt to get a user-provided input method
var imQuery = new PluggableTextInputMethodRequestedEventArgs()
{
RoutedEvent = PluggableTextInputMethod.TextInputMethodRequestedEvent
};
_focusedElement.RaiseEvent(imQuery);
// Fall back to the system provided one, if any
var im = imQuery.InputMethod?.Adapter
?? (focused.VisualRoot as ITextInputMethodRoot)?.InputMethod;
if (im == null)
return (null, null);
var clientQuery = new TextInputMethodClientRequestedEventArgs
{
RoutedEvent = InputElement.TextInputMethodClientRequestedEvent
};
_focusedElement.RaiseEvent(clientQuery);
Client = clientQuery.Client;
return (im, clientQuery.Client);
}
}
}

57
src/Avalonia.Base/Input/TextInput/PluggableTextInputMethod.cs

@ -0,0 +1,57 @@
using Avalonia.Interactivity;
namespace Avalonia.Input.TextInput;
public abstract class PluggableTextInputMethod
{
internal TextInputMethodAdapter Adapter { get; }
public PluggableTextInputMethod()
{
Adapter = new(this);
}
public virtual void SetClient(TextInputMethodClient? client)
{
}
public virtual void SetOptions(TextInputOptions options)
{
}
internal class TextInputMethodAdapter(PluggableTextInputMethod method) : ITextInputMethodImpl
{
public void SetClient(TextInputMethodClient? client)
{
method.SetClient(client);
}
public void SetCursorRect(Rect rect)
{
// No-op
}
public void SetOptions(TextInputOptions options) => method.SetOptions(options);
public void Reset()
{
// Implementations should be subscribing to reset event manually
}
}
/// <summary>
/// Defines the <see cref="TextInputMethodRequestedEvent"/> event.
/// </summary>
public static readonly RoutedEvent<TextInputMethodClientRequestedEventArgs> TextInputMethodRequestedEvent =
RoutedEvent.Register<InputElement, TextInputMethodClientRequestedEventArgs>(
nameof(PluggableTextInputMethodRequestedEventArgs),
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
}
public class PluggableTextInputMethodRequestedEventArgs : RoutedEventArgs
{
/// <summary>
/// Set this property to a valid pluggable text input method to enable its usage with the input system
/// </summary>
public PluggableTextInputMethod? InputMethod { get; set; }
}
Loading…
Cancel
Save