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.
 
 
 

130 lines
4.5 KiB

using System;
using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Input.TextInput;
namespace Avalonia.Android.Platform.Input
{
internal class TextEditBuffer
{
private readonly IAndroidInputMethod _textInputMethod;
private readonly TopLevelImpl _topLevel;
private TextSelection? _composition;
public TextEditBuffer(IAndroidInputMethod textInputMethod, TopLevelImpl topLevel)
{
_textInputMethod = textInputMethod;
_topLevel = topLevel;
}
public bool HasComposition => Composition is { } composition && composition.Start != composition.End;
public TextSelection Selection
{
get
{
var selection = _textInputMethod.Client?.Selection ?? default;
return new TextSelection(Math.Min(selection.Start, selection.End), Math.Max(selection.Start, selection.End));
}
set
{
if (_textInputMethod.Client is { } client)
client.Selection = value;
}
}
public TextSelection? Composition
{
get => _composition; set
{
if (value is { } v)
{
var text = Text;
var start = Math.Clamp(v.Start, 0, text.Length);
var end = Math.Clamp(v.End, 0, text.Length);
_composition = new TextSelection(Math.Min(start, end), Math.Max(start, end));
}
else
_composition = null;
}
}
public string? SelectedText
{
get
{
if(_textInputMethod.Client is not { } client || Selection.Start < 0 || Selection.End >= client.SurroundingText.Length)
{
return "";
}
var selection = Selection;
return client.SurroundingText.Substring(selection.Start, selection.End - selection.Start);
}
}
public string? ComposingText
{
get => !HasComposition ? null : Text?.Substring(Composition!.Value.Start, Composition!.Value.End - Composition!.Value.Start); set
{
if (HasComposition)
{
var start = Composition!.Value.Start;
Replace(Composition!.Value.Start, Composition!.Value.End, value ?? "");
Composition = new TextSelection(start, start + (value?.Length ?? 0));
}
else
{
var selection = Selection;
Replace(selection.Start, selection.End, value ?? "");
Composition = new TextSelection(selection.Start, selection.Start + (value?.Length ?? 0));
}
}
}
public string Text => _textInputMethod.Client?.SurroundingText ?? "";
public ExtractedText? ExtractedText => new ExtractedText
{
Flags = Text.Contains('\n') ? 0 : ExtractedTextFlags.SingleLine,
PartialStartOffset = -1,
PartialEndOffset = Text.Length,
SelectionStart = Selection.Start,
SelectionEnd = Selection.End,
StartOffset = 0,
Text = new Java.Lang.String(Text)
};
internal void Remove(int index, int length)
{
if (_textInputMethod.Client is { } client)
{
client.Selection = new TextSelection(index, index + length);
if (length > 0)
_textInputMethod?.View.DispatchKeyEvent(new KeyEvent(KeyEventActions.Down, Keycode.ForwardDel));
}
}
internal void Replace(int start, int end, string text)
{
if (_textInputMethod.Client is { } client)
{
var realStart = Math.Min(start, end);
var realEnd = Math.Max(start, end);
if (realEnd > realStart)
{
client.Selection = new TextSelection(realStart, realEnd);
_textInputMethod?.View.DispatchKeyEvent(new KeyEvent(KeyEventActions.Down, Keycode.ForwardDel));
}
_topLevel.TextInput(text);
var index = realStart + text.Length;
client.Selection = new TextSelection(index, index);
Composition = null;
}
}
}
}