From 78859b88294897dced36ccda030722f47d09652a Mon Sep 17 00:00:00 2001 From: ili Date: Wed, 7 Apr 2021 18:54:12 +0500 Subject: [PATCH] Tech: working on Avalonia.Input support --- global.json | 2 +- .../Avalonia.Android/AndroidInputMethod.cs | 50 +++++++++++++++++++ .../InvalidationAwareSurfaceView.cs | 20 +------- .../Platform/SkiaPlatform/TopLevelImpl.cs | 35 +++++++++++-- .../Helpers/AndroidKeyboardEventsHelper.cs | 3 +- 5 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 src/Android/Avalonia.Android/AndroidInputMethod.cs diff --git a/global.json b/global.json index b2b2da7c4f..351c7c7e1e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "3.1.401" + "version": "3.1.407" }, "msbuild-sdks": { "Microsoft.Build.Traversal": "1.0.43", diff --git a/src/Android/Avalonia.Android/AndroidInputMethod.cs b/src/Android/Avalonia.Android/AndroidInputMethod.cs new file mode 100644 index 0000000000..fb6f5a0562 --- /dev/null +++ b/src/Android/Avalonia.Android/AndroidInputMethod.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Android.Content; +using Android.Runtime; +using Android.Views; +using Android.Views.InputMethods; +using Avalonia.Input.TextInput; + +namespace Avalonia.Android +{ + class AndroidInputMethod : ITextInputMethodImpl + where TView: View, IInitEditorInfo + { + private readonly TView _host; + private readonly InputMethodManager _imm; + + public AndroidInputMethod(TView host) + { + if (host.OnCheckIsTextEditor() == false) + throw new InvalidOperationException("Host should return true from OnCheckIsTextEditor()"); + + _host = host; + _imm = host.Context.GetSystemService(Context.InputMethodService).JavaCast(); + + _host.Focusable = true; + _host.FocusableInTouchMode = true; + } + + public void Reset() + { + _imm.RestartInput(_host); + } + + public void SetActive(bool active) + { + if (active) + _host.RequestFocus(); + } + + public void SetCursorRect(Rect rect) + { + } + + public void SetOptions(TextInputOptionsQueryEventArgs options) + { + //throw new NotImplementedException(); + } + } +} diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs index a43861d4e7..3444193140 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs @@ -13,7 +13,7 @@ using Avalonia.Platform; namespace Avalonia.Android { - public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle, IInitEditorInfo + public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle { bool _invalidateQueued; private ISoftInputElement _softInputElement; @@ -92,24 +92,6 @@ namespace Avalonia.Android protected abstract void Draw(); public string HandleDescriptor => "SurfaceView"; - private Action _initEditorInfo; - - public void InitEditorInfo(Action init) - { - _initEditorInfo = init; - } - - public sealed override IInputConnection OnCreateInputConnection(EditorInfo outAttrs) - { - if (_initEditorInfo == null) - throw new InvalidOperationException("Call IInitEditorInfo.InitEditorInfo first"); - - _initEditorInfo(outAttrs); - - return base.OnCreateInputConnection(outAttrs); - } - - public override bool CheckInputConnectionProxy(View view) { return base.CheckInputConnectionProxy(view); diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index bd9a5868c0..dc9932b38c 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -9,9 +9,11 @@ using Avalonia.Android.OpenGL; using Avalonia.Android.Platform.Specific; using Avalonia.Android.Platform.Specific.Helpers; using Avalonia.Controls; +using Avalonia.Controls.Platform; using Avalonia.Controls.Platform.Surfaces; using Avalonia.Input; using Avalonia.Input.Raw; +using Avalonia.Input.TextInput; using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Surfaces; using Avalonia.Platform; @@ -19,19 +21,20 @@ using Avalonia.Rendering; namespace Avalonia.Android.Platform.SkiaPlatform { - class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo, IInitEditorInfo + class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo, ITopLevelImplWithTextInputMethod { private readonly IGlPlatformSurface _gl; private readonly IFramebufferPlatformSurface _framebuffer; private readonly AndroidKeyboardEventsHelper _keyboardHelper; private readonly AndroidTouchEventsHelper _touchHelper; - + private readonly ITextInputMethodImpl _textInputMethod; private ViewImpl _view; public TopLevelImpl(Context context, bool placeOnTop = false) { _view = new ViewImpl(context, this, placeOnTop); + _textInputMethod = new AndroidInputMethod(_view); _keyboardHelper = new AndroidKeyboardEventsHelper(this); _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, GetAvaloniaPointFromEvent); @@ -47,7 +50,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform _keyboardHelper.ActivateAutoShowKeyboard(); } - public bool HandleEvents { get { return _keyboardHelper.HandleEvents; } @@ -141,7 +143,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform Resized?.Invoke(size); } - class ViewImpl : InvalidationAwareSurfaceView, ISurfaceHolderCallback + class ViewImpl : InvalidationAwareSurfaceView, ISurfaceHolderCallback, IInitEditorInfo { private readonly TopLevelImpl _tl; private Size _oldSize; @@ -188,6 +190,29 @@ namespace Avalonia.Android.Platform.SkiaPlatform base.SurfaceChanged(holder, format, width, height); } + + public sealed override bool OnCheckIsTextEditor() + { + return true; + } + + private Action _initEditorInfo; + + public void InitEditorInfo(Action init) + { + _initEditorInfo = init; + } + + public sealed override IInputConnection OnCreateInputConnection(EditorInfo outAttrs) + { + if (_initEditorInfo == null) + throw new InvalidOperationException("Call IInitEditorInfo.InitEditorInfo first"); + + _initEditorInfo(outAttrs); + + return base.OnCreateInputConnection(outAttrs); + } + } public IPopupImpl CreatePopup() => null; @@ -206,6 +231,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform public double Scaling => RenderScaling; + public ITextInputMethodImpl TextInputMethod => _textInputMethod; + public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { throw new NotImplementedException(); diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs index e98a8f183e..db864c0ee0 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs @@ -9,12 +9,13 @@ using Android.Widget; using Avalonia.Android.Platform.Input; using Avalonia.Android.Platform.SkiaPlatform; using Avalonia.Controls; +using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Input.Raw; namespace Avalonia.Android.Platform.Specific.Helpers { - internal class AndroidKeyboardEventsHelper : IDisposable where TView : TopLevelImpl, IAndroidView, IInitEditorInfo + internal class AndroidKeyboardEventsHelper : IDisposable where TView : TopLevelImpl, IAndroidView, ITopLevelImplWithTextInputMethod { private TView _view; private IInputElement _lastFocusedElement;