diff --git a/src/Android/Avalonia.Android/AndroidInputMethod.cs b/src/Android/Avalonia.Android/AndroidInputMethod.cs index 880b210a6c..87d97afa1a 100644 --- a/src/Android/Avalonia.Android/AndroidInputMethod.cs +++ b/src/Android/Avalonia.Android/AndroidInputMethod.cs @@ -1,10 +1,14 @@ 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 { @@ -13,6 +17,8 @@ namespace Avalonia.Android { private readonly TView _host; private readonly InputMethodManager _imm; + private ITextInputMethodClient _client; + private InputConnectionImpl _inputConnection; public AndroidInputMethod(TView host) { @@ -27,6 +33,10 @@ namespace Avalonia.Android _host.ViewTreeObserver.AddOnGlobalLayoutListener(new SoftKeyboardListener(_host)); } + public bool IsActive => Client != null; + + public ITextInputMethodClient Client => _client; + public void Reset() { _imm.RestartInput(_host); @@ -34,16 +44,16 @@ namespace Avalonia.Android public void SetClient(ITextInputMethodClient client) { - var active = client is { }; + _client = client; - if (active) + if (IsActive) { _host.RequestFocus(); Reset(); _imm.ShowSoftInput(_host, ShowFlags.Implicit); } else - _imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.None); + _imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.None); } public void SetCursorRect(Rect rect) @@ -52,7 +62,9 @@ namespace Avalonia.Android public void SetOptions(TextInputOptions options) { - _host.InitEditorInfo((outAttrs) => + _inputConnection = new InputConnectionImpl(_host, this); + + _host.InitEditorInfo((_host, outAttrs) => { outAttrs.InputType = options.ContentType switch { @@ -74,6 +86,8 @@ namespace Avalonia.Android outAttrs.InputType |= global::Android.Text.InputTypes.TextFlagMultiLine; outAttrs.ImeOptions |= ImeFlags.NoFullscreen | ImeFlags.NoExtractUi; + + return _inputConnection; }); } diff --git a/src/Android/Avalonia.Android/IInitEditorInfo.cs b/src/Android/Avalonia.Android/IInitEditorInfo.cs index 98fc4eafc1..72f9e72d1f 100644 --- a/src/Android/Avalonia.Android/IInitEditorInfo.cs +++ b/src/Android/Avalonia.Android/IInitEditorInfo.cs @@ -1,12 +1,14 @@ 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 { - void InitEditorInfo(Action init); + void InitEditorInfo(Func init); } } diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 17a0d6b63a..aa4afae0fd 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -3,6 +3,9 @@ using System.Collections.Generic; using Android.Content; using Android.Graphics; +using Android.Media.TV; +using Android.OS; +using Android.Runtime; using Android.Views; using Android.Views.InputMethods; using Avalonia.Android.OpenGL; @@ -21,6 +24,7 @@ using Avalonia.Platform; using Avalonia.Platform.Storage; using Avalonia.Rendering; using Avalonia.Rendering.Composition; +using Java.Lang; namespace Avalonia.Android.Platform.SkiaPlatform { @@ -148,7 +152,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform { private readonly TopLevelImpl _tl; 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; if (placeOnTop) @@ -187,7 +192,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform return res != null ? res.Value : baseResult; } - void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height) { var newSize = new PixelSize(width, height).ToSize(_tl.RenderScaling); @@ -206,9 +210,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform return true; } - private Action _initEditorInfo; + private Func _initEditorInfo; + protected InputConnectionImpl _inputConnection; - public void InitEditorInfo(Action init) + public void InitEditorInfo(Func init) { _initEditorInfo = init; } @@ -216,9 +221,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform public sealed override IInputConnection OnCreateInputConnection(EditorInfo outAttrs) { if (_initEditorInfo != null) - _initEditorInfo(outAttrs); - - return base.OnCreateInputConnection(outAttrs); + { + return _initEditorInfo(this, outAttrs); + } + + return null; } } @@ -249,4 +256,39 @@ namespace Avalonia.Android.Platform.SkiaPlatform 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); + } + } } diff --git a/src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs b/src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs index be7ad81f81..34129b245c 100644 --- a/src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs +++ b/src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs @@ -5,6 +5,10 @@ namespace Avalonia.Input.TextInput [Unstable] public interface ITextInputMethodImpl { + ITextInputMethodClient Client { get; } + + bool IsActive { get; } + void SetClient(ITextInputMethodClient? client); void SetCursorRect(Rect rect); void SetOptions(TextInputOptions options); diff --git a/src/Avalonia.Base/Media/FontFamily.cs b/src/Avalonia.Base/Media/FontFamily.cs index c4ebc1e0d4..da84861668 100644 --- a/src/Avalonia.Base/Media/FontFamily.cs +++ b/src/Avalonia.Base/Media/FontFamily.cs @@ -128,7 +128,7 @@ namespace Avalonia.Media default: { - throw new ArgumentException("Specified family is not supported."); + return new FontFamilyIdentifier(name, null); } } }