123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- using System;
- using Android.Content;
- using Android.Runtime;
- using Android.Text;
- using Android.Views;
- using Android.Views.InputMethods;
- using Avalonia.Android.Platform.SkiaPlatform;
- using Avalonia.Input.TextInput;
- namespace Avalonia.Android
- {
- internal interface IAndroidInputMethod
- {
- public View View { get; }
- public TextInputMethodClient Client { get; }
- public bool IsActive { get; }
- public InputMethodManager IMM { get; }
- }
- enum CustomImeFlags
- {
- ActionNone = 0x00000001,
- ActionGo = 0x00000002,
- ActionSearch = 0x00000003,
- ActionSend = 0x00000004,
- ActionNext = 0x00000005,
- ActionDone = 0x00000006,
- ActionPrevious = 0x00000007,
- }
- internal class AndroidInputMethod<TView> : ITextInputMethodImpl, IAndroidInputMethod
- where TView : View, IInitEditorInfo
- {
- private readonly TView _host;
- private readonly InputMethodManager _imm;
- private TextInputMethodClient _client;
- private AvaloniaInputConnection _inputConnection;
- 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<InputMethodManager>();
- _host.Focusable = true;
- _host.FocusableInTouchMode = true;
- _host.ViewTreeObserver.AddOnGlobalLayoutListener(new SoftKeyboardListener(_host));
- }
- public View View => _host;
- public bool IsActive => Client != null;
- public TextInputMethodClient Client => _client;
- public InputMethodManager IMM => _imm;
- public void Reset()
- {
- }
- public void SetClient(TextInputMethodClient client)
- {
- _client = client;
- if (IsActive)
- {
- _host.RequestFocus();
- _imm.RestartInput(View);
- _imm.ShowSoftInput(_host, ShowFlags.Implicit);
- var selection = Client.Selection;
- _imm.UpdateSelection(_host, selection.Start, selection.End, selection.Start, selection.End);
- var surroundingText = _client.SurroundingText ?? "";
- var extractedText = new ExtractedText
- {
- Text = new Java.Lang.String(surroundingText),
- SelectionStart = selection.Start,
- SelectionEnd = selection.End,
- PartialEndOffset = surroundingText.Length
- };
- _imm.UpdateExtractedText(_host, _inputConnection?.ExtractedTextToken ?? 0, extractedText);
- _client.SurroundingTextChanged += _client_SurroundingTextChanged;
- _client.SelectionChanged += _client_SelectionChanged;
- }
- else
- {
- _imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.ImplicitOnly);
- }
- }
- private void _client_SelectionChanged(object sender, EventArgs e)
- {
- var selection = Client.Selection;
- _imm.UpdateSelection(_host, selection.Start, selection.End, selection.Start, selection.End);
- }
- private void _client_SurroundingTextChanged(object sender, EventArgs e)
- {
- var surroundingText = _client.SurroundingText ?? "";
- _inputConnection.EditableWrapper.IgnoreChange = true;
- _inputConnection.Editable.Replace(0, _inputConnection.Editable.Length(), surroundingText);
- _inputConnection.EditableWrapper.IgnoreChange = false;
- var selection = Client.Selection;
- _imm.UpdateSelection(_host, selection.Start, selection.End, selection.Start, selection.End);
- //Debug.WriteLine($"SurroundingText: {surroundingText}, CaretIndex: {selection.Start}");
- }
- public void SetCursorRect(Rect rect)
- {
-
- }
- public void SetOptions(TextInputOptions options)
- {
- _host.InitEditorInfo((topLevel, outAttrs) =>
- {
- if (_client == null)
- return null;
- _inputConnection = new AvaloniaInputConnection(topLevel, this);
- outAttrs.InputType = options.ContentType switch
- {
- TextInputContentType.Email => global::Android.Text.InputTypes.TextVariationEmailAddress,
- TextInputContentType.Number => global::Android.Text.InputTypes.ClassNumber,
- TextInputContentType.Password => global::Android.Text.InputTypes.TextVariationPassword,
- TextInputContentType.Digits => global::Android.Text.InputTypes.ClassPhone,
- TextInputContentType.Url => global::Android.Text.InputTypes.TextVariationUri,
- _ => global::Android.Text.InputTypes.ClassText
- };
- if (options.AutoCapitalization)
- {
- outAttrs.InitialCapsMode = global::Android.Text.CapitalizationMode.Sentences;
- outAttrs.InputType |= global::Android.Text.InputTypes.TextFlagCapSentences;
- }
- if (options.Multiline)
- outAttrs.InputType |= global::Android.Text.InputTypes.TextFlagMultiLine;
- outAttrs.ImeOptions = options.ReturnKeyType switch
- {
- TextInputReturnKeyType.Return => ImeFlags.NoEnterAction,
- TextInputReturnKeyType.Go => (ImeFlags)CustomImeFlags.ActionGo,
- TextInputReturnKeyType.Send => (ImeFlags)CustomImeFlags.ActionSend,
- TextInputReturnKeyType.Search => (ImeFlags)CustomImeFlags.ActionSearch,
- TextInputReturnKeyType.Next => (ImeFlags)CustomImeFlags.ActionNext,
- TextInputReturnKeyType.Previous => (ImeFlags)CustomImeFlags.ActionPrevious,
- TextInputReturnKeyType.Done => (ImeFlags)CustomImeFlags.ActionDone,
- _ => options.Multiline ? ImeFlags.NoEnterAction : (ImeFlags)CustomImeFlags.ActionDone
- };
- outAttrs.ImeOptions |= ImeFlags.NoFullscreen | ImeFlags.NoExtractUi;
- return _inputConnection;
- });
- }
- }
- }
|