Browse Source

Android preedit

feature/ImePreeditText
Benedikt Stebner 4 years ago
parent
commit
ab6df8c9ed
  1. 22
      src/Android/Avalonia.Android/AndroidInputMethod.cs
  2. 4
      src/Android/Avalonia.Android/IInitEditorInfo.cs
  3. 56
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  4. 4
      src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs
  5. 2
      src/Avalonia.Base/Media/FontFamily.cs

22
src/Android/Avalonia.Android/AndroidInputMethod.cs

@ -1,10 +1,14 @@
using System; using System;
using Android.Content; using Android.Content;
using Android.OS;
using Android.Runtime; using Android.Runtime;
using Android.Text;
using Android.Views; using Android.Views;
using Android.Views.InputMethods; using Android.Views.InputMethods;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.TextInput; using Avalonia.Input.TextInput;
using Java.Lang;
namespace Avalonia.Android namespace Avalonia.Android
{ {
@ -13,6 +17,8 @@ namespace Avalonia.Android
{ {
private readonly TView _host; private readonly TView _host;
private readonly InputMethodManager _imm; private readonly InputMethodManager _imm;
private ITextInputMethodClient _client;
private InputConnectionImpl _inputConnection;
public AndroidInputMethod(TView host) public AndroidInputMethod(TView host)
{ {
@ -27,6 +33,10 @@ namespace Avalonia.Android
_host.ViewTreeObserver.AddOnGlobalLayoutListener(new SoftKeyboardListener(_host)); _host.ViewTreeObserver.AddOnGlobalLayoutListener(new SoftKeyboardListener(_host));
} }
public bool IsActive => Client != null;
public ITextInputMethodClient Client => _client;
public void Reset() public void Reset()
{ {
_imm.RestartInput(_host); _imm.RestartInput(_host);
@ -34,16 +44,16 @@ namespace Avalonia.Android
public void SetClient(ITextInputMethodClient client) public void SetClient(ITextInputMethodClient client)
{ {
var active = client is { }; _client = client;
if (active) if (IsActive)
{ {
_host.RequestFocus(); _host.RequestFocus();
Reset(); Reset();
_imm.ShowSoftInput(_host, ShowFlags.Implicit); _imm.ShowSoftInput(_host, ShowFlags.Implicit);
} }
else else
_imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.None); _imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.None);
} }
public void SetCursorRect(Rect rect) public void SetCursorRect(Rect rect)
@ -52,7 +62,9 @@ namespace Avalonia.Android
public void SetOptions(TextInputOptions options) public void SetOptions(TextInputOptions options)
{ {
_host.InitEditorInfo((outAttrs) => _inputConnection = new InputConnectionImpl(_host, this);
_host.InitEditorInfo((_host, outAttrs) =>
{ {
outAttrs.InputType = options.ContentType switch outAttrs.InputType = options.ContentType switch
{ {
@ -74,6 +86,8 @@ namespace Avalonia.Android
outAttrs.InputType |= global::Android.Text.InputTypes.TextFlagMultiLine; outAttrs.InputType |= global::Android.Text.InputTypes.TextFlagMultiLine;
outAttrs.ImeOptions |= ImeFlags.NoFullscreen | ImeFlags.NoExtractUi; outAttrs.ImeOptions |= ImeFlags.NoFullscreen | ImeFlags.NoExtractUi;
return _inputConnection;
}); });
} }

4
src/Android/Avalonia.Android/IInitEditorInfo.cs

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

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

@ -3,6 +3,9 @@ using System.Collections.Generic;
using Android.Content; using Android.Content;
using Android.Graphics; using Android.Graphics;
using Android.Media.TV;
using Android.OS;
using Android.Runtime;
using Android.Views; using Android.Views;
using Android.Views.InputMethods; using Android.Views.InputMethods;
using Avalonia.Android.OpenGL; using Avalonia.Android.OpenGL;
@ -21,6 +24,7 @@ using Avalonia.Platform;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Rendering.Composition; using Avalonia.Rendering.Composition;
using Java.Lang;
namespace Avalonia.Android.Platform.SkiaPlatform namespace Avalonia.Android.Platform.SkiaPlatform
{ {
@ -148,7 +152,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{ {
private readonly TopLevelImpl _tl; private readonly TopLevelImpl _tl;
private Size _oldSize; private Size _oldSize;
public ViewImpl(Context context, TopLevelImpl tl, bool placeOnTop) : base(context)
public ViewImpl(Context context, TopLevelImpl tl, bool placeOnTop) : base(context)
{ {
_tl = tl; _tl = tl;
if (placeOnTop) if (placeOnTop)
@ -187,7 +192,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
return res != null ? res.Value : baseResult; return res != null ? res.Value : baseResult;
} }
void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height) void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{ {
var newSize = new PixelSize(width, height).ToSize(_tl.RenderScaling); var newSize = new PixelSize(width, height).ToSize(_tl.RenderScaling);
@ -206,9 +210,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform
return true; return true;
} }
private Action<EditorInfo> _initEditorInfo; private Func<View, EditorInfo, InputConnectionImpl> _initEditorInfo;
protected InputConnectionImpl _inputConnection;
public void InitEditorInfo(Action<EditorInfo> init) public void InitEditorInfo(Func<View, EditorInfo, InputConnectionImpl> init)
{ {
_initEditorInfo = init; _initEditorInfo = init;
} }
@ -216,9 +221,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public sealed override IInputConnection OnCreateInputConnection(EditorInfo outAttrs) public sealed override IInputConnection OnCreateInputConnection(EditorInfo outAttrs)
{ {
if (_initEditorInfo != null) if (_initEditorInfo != null)
_initEditorInfo(outAttrs); {
return _initEditorInfo(this, outAttrs);
return base.OnCreateInputConnection(outAttrs); }
return null;
} }
} }
@ -249,4 +256,39 @@ namespace Avalonia.Android.Platform.SkiaPlatform
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }
internal class InputConnectionImpl: BaseInputConnection
{
private readonly ITextInputMethodImpl _inputMethod;
public InputConnectionImpl(View? targetView, ITextInputMethodImpl inputMethod) :
base(targetView, false)
{
_inputMethod = inputMethod;
}
public InputConnectionImpl(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public override bool SetComposingText(ICharSequence text, int newCursorPosition)
{
if (_inputMethod.IsActive)
{
_inputMethod.Client.SetPreeditText(text.ToString());
}
return base.SetComposingText(text, newCursorPosition);
}
public override bool CommitText(ICharSequence text, int newCursorPosition)
{
if (_inputMethod.IsActive)
{
_inputMethod.Client.SetPreeditText(null);
}
return base.CommitText(text, newCursorPosition);
}
}
} }

4
src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs

@ -5,6 +5,10 @@ namespace Avalonia.Input.TextInput
[Unstable] [Unstable]
public interface ITextInputMethodImpl public interface ITextInputMethodImpl
{ {
ITextInputMethodClient Client { get; }
bool IsActive { get; }
void SetClient(ITextInputMethodClient? client); void SetClient(ITextInputMethodClient? client);
void SetCursorRect(Rect rect); void SetCursorRect(Rect rect);
void SetOptions(TextInputOptions options); void SetOptions(TextInputOptions options);

2
src/Avalonia.Base/Media/FontFamily.cs

@ -128,7 +128,7 @@ namespace Avalonia.Media
default: default:
{ {
throw new ArgumentException("Specified family is not supported."); return new FontFamilyIdentifier(name, null);
} }
} }
} }

Loading…
Cancel
Save