Browse Source

Android - switch to full editor input connection

pull/8963/head
Benedikt Stebner 4 years ago
parent
commit
a242a10db4
  1. 19
      src/Android/Avalonia.Android/AndroidInputMethod.cs
  2. 7
      src/Android/Avalonia.Android/IInitEditorInfo.cs
  3. 154
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

19
src/Android/Avalonia.Android/AndroidInputMethod.cs

@ -1,19 +1,18 @@
using System;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Input;
using Avalonia.Input.TextInput;
using Java.Lang;
namespace Avalonia.Android
{
internal interface IAndroidInputMethod
{
public View View { get; }
public ITextInputMethodClient Client { get; }
public bool IsActive { get; }
@ -38,7 +37,7 @@ namespace Avalonia.Android
private readonly TView _host;
private readonly InputMethodManager _imm;
private ITextInputMethodClient _client;
private InputConnectionImpl _inputConnection;
private AvaloniaInputConnection _inputConnection;
public AndroidInputMethod(TView host)
{
@ -53,6 +52,8 @@ namespace Avalonia.Android
_host.ViewTreeObserver.AddOnGlobalLayoutListener(new SoftKeyboardListener(_host));
}
public View View => _host;
public bool IsActive => Client != null;
public ITextInputMethodClient Client => _client;
@ -100,6 +101,8 @@ namespace Avalonia.Android
{
var surroundingText = Client.SurroundingText;
_inputConnection.SurroundingText = surroundingText;
_imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, surroundingText.AnchorOffset, surroundingText.CursorOffset);
}
}
@ -111,11 +114,9 @@ namespace Avalonia.Android
public void SetOptions(TextInputOptions options)
{
_inputConnection = new InputConnectionImpl(_host, this);
_host.InitEditorInfo((_host, outAttrs) =>
{
//_inputConnection?.FinishComposingText();
_host.InitEditorInfo((topLevel, outAttrs) =>
{
_inputConnection = new AvaloniaInputConnection(topLevel, this);
outAttrs.InputType = options.ContentType switch
{

7
src/Android/Avalonia.Android/IInitEditorInfo.cs

@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
using Android.Views;
using Android.Views.InputMethods;
using Avalonia.Android.Platform.SkiaPlatform;
namespace Avalonia.Android
{
interface IInitEditorInfo
internal interface IInitEditorInfo
{
void InitEditorInfo(Func<View, EditorInfo, InputConnectionImpl> init);
void InitEditorInfo(Func<TopLevelImpl, EditorInfo, IInputConnection> init);
}
}

154
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -6,9 +6,12 @@ using Android.Graphics;
using Android.Media.TV;
using Android.OS;
using Android.Runtime;
using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using Avalonia.Android.OpenGL;
using Avalonia.Android.Platform.Input;
using Avalonia.Android.Platform.Specific;
using Avalonia.Android.Platform.Specific.Helpers;
using Avalonia.Android.Platform.Storage;
@ -162,6 +165,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
SetZOrderOnTop(true);
}
public TopLevelImpl TopLevelImpl => _tl;
protected override void Draw()
{
_tl.Draw();
@ -212,9 +217,9 @@ namespace Avalonia.Android.Platform.SkiaPlatform
return true;
}
private Func<View, EditorInfo, InputConnectionImpl> _initEditorInfo;
private Func<TopLevelImpl, EditorInfo, IInputConnection> _initEditorInfo;
public void InitEditorInfo(Func<View, EditorInfo, InputConnectionImpl> init)
public void InitEditorInfo(Func<TopLevelImpl, EditorInfo, IInputConnection> init)
{
_initEditorInfo = init;
}
@ -223,7 +228,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
if (_initEditorInfo != null)
{
return _initEditorInfo(this, outAttrs);
return _initEditorInfo(_tl, outAttrs);
}
return null;
@ -256,143 +261,128 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
throw new NotImplementedException();
}
}
internal class InputConnectionImpl: BaseInputConnection, IInputConnection
internal class AvaloniaInputConnection : BaseInputConnection
{
private readonly TopLevelImpl _topLevel;
private readonly IAndroidInputMethod _inputMethod;
public InputConnectionImpl(View targetView, IAndroidInputMethod inputMethod) :
base(targetView, false)
public AvaloniaInputConnection(TopLevelImpl topLevel, IAndroidInputMethod inputMethod) : base(inputMethod.View, true)
{
View = targetView;
_topLevel = topLevel;
_inputMethod = inputMethod;
}
public InputConnectionImpl(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public TextInputMethodSurroundingText SurroundingText { get; set; }
public View View { get; }
public string ComposingText { get; private set; }
public ComposingRegion ComposingRegion { get; internal set; }
public ComposingRegion ComposingRegion { get; private set; }
public string CompositionText { get; private set; }
public bool IsComposing { get; private set; }
public override bool SetComposingRegion(int start, int end)
{
if (_inputMethod.IsActive)
{
var surroundingText = _inputMethod.Client.SurroundingText;
//System.Diagnostics.Debug.WriteLine($"Composing Region: [{start}|{end}] {SurroundingText.Text?.Substring(start, end - start)}");
System.Diagnostics.Debug.WriteLine($"Composing Region: [{start}|{end}] {surroundingText.Text?.Substring(start, end - start)}");
ComposingRegion = new ComposingRegion(start, end);
}
ComposingRegion = new ComposingRegion(start, end);
return base.SetComposingRegion(start, end);
}
public override ICharSequence GetTextBeforeCursorFormatted(int length, [GeneratedEnum] GetTextFlags flags)
public override bool SetComposingText(ICharSequence text, int newCursorPosition)
{
if (_inputMethod.IsActive)
{
var surroundingText = _inputMethod.Client.SurroundingText;
var composingText = text.ToString();
if (_inputMethod.IsActive && !string.IsNullOrEmpty(surroundingText.Text))
{
var start = System.Math.Max(surroundingText.CursorOffset - length, 0);
ComposingText = composingText;
IsComposing = true;
var end = System.Math.Min(start + length, surroundingText.CursorOffset);
_inputMethod.Client.SetPreeditText(ComposingText);
var text = surroundingText.Text.Substring(start, end - start);
return base.SetComposingText(text, newCursorPosition);
}
System.Diagnostics.Debug.WriteLine($"Text Before: {text}");
public override bool FinishComposingText()
{
IsComposing = false;
return new Java.Lang.String(text);
}
}
ComposingRegion = new ComposingRegion(SurroundingText.CursorOffset, SurroundingText.CursorOffset);
return base.GetTextBeforeCursorFormatted(length, flags);
return base.FinishComposingText();
}
public override ICharSequence GetTextAfterCursorFormatted(int length, [GeneratedEnum] GetTextFlags flags)
public override ICharSequence GetTextBeforeCursorFormatted(int length, [GeneratedEnum] GetTextFlags flags)
{
if (_inputMethod.IsActive)
if (!string.IsNullOrEmpty(SurroundingText.Text))
{
var surroundingText = _inputMethod.Client.SurroundingText;
if (_inputMethod.IsActive && !string.IsNullOrEmpty(surroundingText.Text))
{
var start = surroundingText.CursorOffset;
var start = System.Math.Max(SurroundingText.CursorOffset - length, 0);
var end = System.Math.Min(start + length, surroundingText.Text.Length);
var end = System.Math.Min(start + length, SurroundingText.CursorOffset);
var text = surroundingText.Text.Substring(start, end - start);
var text = SurroundingText.Text.Substring(start, end - start);
System.Diagnostics.Debug.WriteLine($"Text After: {text}");
//System.Diagnostics.Debug.WriteLine($"Text Before: {text}");
return new Java.Lang.String(text);
}
return new Java.Lang.String(text);
}
return base.GetTextAfterCursorFormatted(length, flags);
return null;
}
public override bool SetComposingText(ICharSequence text, int newCursorPosition)
public override ICharSequence GetTextAfterCursorFormatted(int length, [GeneratedEnum] GetTextFlags flags)
{
CompositionText = text.ToString();
if (_inputMethod.IsActive)
if (!string.IsNullOrEmpty(SurroundingText.Text))
{
_inputMethod.Client.SetPreeditText(CompositionText);
var start = SurroundingText.CursorOffset;
var end = System.Math.Min(start + length, SurroundingText.Text.Length);
var text = SurroundingText.Text.Substring(start, end - start);
//System.Diagnostics.Debug.WriteLine($"Text After: {text}");
return new Java.Lang.String(text);
}
return base.SetComposingText(text, newCursorPosition);
return null;
}
public override bool SendKeyEvent(KeyEvent e)
public override bool CommitText(ICharSequence text, int newCursorPosition)
{
return base.SendKeyEvent(e);
}
var committedText = text.ToString();
public override bool CommitText(ICharSequence text, int newCursorPosition)
{
CompositionText = null;
_inputMethod.Client.SetPreeditText(null);
if (_inputMethod.IsActive)
{
_inputMethod.Client.SetPreeditText(null);
_inputMethod.Client.SelectInSurroundingText(ComposingRegion.Start, ComposingRegion.End);
if (string.IsNullOrEmpty(CompositionText))
{
var surroundingText = _inputMethod.Client.SurroundingText;
var time = DateTime.Now.TimeOfDay;
var composingRegionLength = ComposingRegion.End - ComposingRegion.Start;
var rawTextEvent = new RawTextInputEventArgs(KeyboardDevice.Instance, (ulong)time.Ticks, _topLevel.InputRoot, committedText);
var composingRegionText = surroundingText.Text?.Substring(ComposingRegion.Start, composingRegionLength);
_inputMethod.Client.SelectInSurroundingText(ComposingRegion.Start, ComposingRegion.End);
}
ComposingRegion = new ComposingRegion(ComposingRegion.End, ComposingRegion.End);
}
_topLevel.Input(rawTextEvent);
return base.CommitText(text, newCursorPosition);
}
public override bool FinishComposingText()
public override bool DeleteSurroundingText(int beforeLength, int afterLength)
{
CompositionText = null;
_inputMethod.Client.SelectInSurroundingText(beforeLength, afterLength);
if (_inputMethod.IsActive)
{
_inputMethod.Client.SetPreeditText(CompositionText);
}
_inputMethod.View.DispatchKeyEvent(new KeyEvent(KeyEventActions.Down, Keycode.ForwardDel));
return base.FinishComposingText();
}
return base.DeleteSurroundingText(beforeLength, afterLength);
}
public override bool SetSelection(int start, int end)
{
_inputMethod.Client.SelectInSurroundingText(start, end);
return base.SetSelection(start, end);
}
}
public readonly struct ComposingRegion

Loading…
Cancel
Save