From 8084bdbd78a944f8a3f6e8a2ede325f937286fa0 Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Wed, 21 Sep 2022 16:34:36 +0200 Subject: [PATCH] Properly raise surroundingText changed --- .../Avalonia.Android/AndroidInputMethod.cs | 6 +- .../Platform/SkiaPlatform/TopLevelImpl.cs | 80 ++++++------------- .../TextBoxTextInputMethodClient.cs | 45 ++++++++--- 3 files changed, 61 insertions(+), 70 deletions(-) diff --git a/src/Android/Avalonia.Android/AndroidInputMethod.cs b/src/Android/Avalonia.Android/AndroidInputMethod.cs index 5293759586..590dc70cb4 100644 --- a/src/Android/Avalonia.Android/AndroidInputMethod.cs +++ b/src/Android/Avalonia.Android/AndroidInputMethod.cs @@ -17,6 +17,8 @@ namespace Avalonia.Android public ITextInputMethodClient Client { get; } public bool IsActive { get; } + + public InputMethodManager IMM { get; } } enum CustomImeFlags @@ -55,6 +57,8 @@ namespace Avalonia.Android public ITextInputMethodClient Client => _client; + public InputMethodManager IMM => _imm; + public void Reset() { _imm.RestartInput(_host); @@ -96,7 +100,7 @@ namespace Avalonia.Android { var surroundingText = Client.SurroundingText; - _imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, surroundingText.AnchorOffset, surroundingText.CursorOffset); + _imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, _inputConnection.ComposingRegion.Start, _inputConnection.ComposingRegion.End); } } diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 75143d02f5..fce7106674 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -262,9 +262,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform { private readonly IAndroidInputMethod _inputMethod; - public InputConnectionImpl(View? targetView, IAndroidInputMethod inputMethod) : + public InputConnectionImpl(View targetView, IAndroidInputMethod inputMethod) : base(targetView, false) { + View = targetView; + _inputMethod = inputMethod; } @@ -272,20 +274,12 @@ namespace Avalonia.Android.Platform.SkiaPlatform { } + public View View { get; } + public ComposingRegion ComposingRegion { get; private set; } public string CompositionText { get; private set; } - public override bool SetSelection(int start, int end) - { - if (_inputMethod.IsActive) - { - _inputMethod.Client.SelectInSurroundingText(start, end); - } - - return base.SetSelection(start, end); - } - public override bool SetComposingRegion(int start, int end) { if (_inputMethod.IsActive) @@ -300,21 +294,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform return base.SetComposingRegion(start, end); } - public override bool CommitCorrection(CorrectionInfo correctionInfo) - { - return base.CommitCorrection(correctionInfo); - } - - public override bool DeleteSurroundingText(int beforeLength, int afterLength) - { - if (_inputMethod.IsActive && _inputMethod.Client.SupportsSurroundingText) - { - _inputMethod.Client.DeleteSurroundingText(beforeLength, afterLength); - } - - return base.DeleteSurroundingText(beforeLength, afterLength); - } - public override ICharSequence GetTextBeforeCursorFormatted(int length, [GeneratedEnum] GetTextFlags flags) { if (_inputMethod.IsActive) @@ -329,7 +308,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform var text = surroundingText.Text.Substring(start, end - start); - //System.Diagnostics.Debug.WriteLine($"Text Before: {text}"); + System.Diagnostics.Debug.WriteLine($"Text Before: {text}"); return new Java.Lang.String(text); } @@ -352,7 +331,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform var text = surroundingText.Text.Substring(start, end - start); - //System.Diagnostics.Debug.WriteLine($"Text After: {text}"); + System.Diagnostics.Debug.WriteLine($"Text After: {text}"); return new Java.Lang.String(text); } @@ -368,16 +347,16 @@ namespace Avalonia.Android.Platform.SkiaPlatform if (_inputMethod.IsActive) { _inputMethod.Client.SetPreeditText(CompositionText); - - if (!string.IsNullOrEmpty(CompositionText)) - { - ComposingRegion = default; - } } return base.SetComposingText(text, newCursorPosition); } + public override bool SendKeyEvent(KeyEvent e) + { + return base.SendKeyEvent(e); + } + public override bool CommitText(ICharSequence text, int newCursorPosition) { CompositionText = null; @@ -386,32 +365,19 @@ namespace Avalonia.Android.Platform.SkiaPlatform { _inputMethod.Client.SetPreeditText(null); - if (string.IsNullOrEmpty(CompositionText) && ComposingRegion.Start != ComposingRegion.End) + var textLength = text.Length(); + + if (string.IsNullOrEmpty(CompositionText) && ComposingRegion.End > 0) { - _inputMethod.Client.SelectInSurroundingText(ComposingRegion.Start, ComposingRegion.End); + _inputMethod.Client.SelectInSurroundingText(ComposingRegion.Start, ComposingRegion.Start + textLength); } - ComposingRegion = new ComposingRegion(ComposingRegion.Start, ComposingRegion.Start + text.Length()); + ComposingRegion = new ComposingRegion(ComposingRegion.Start, ComposingRegion.Start + textLength); } return base.CommitText(text, newCursorPosition); } - public override bool PerformEditorAction([GeneratedEnum] ImeAction actionCode) - { - return base.PerformEditorAction(actionCode); - } - - public override bool PerformPrivateCommand(string action, Bundle data) - { - return base.PerformPrivateCommand(action, data); - } - - public override bool SendKeyEvent(KeyEvent e) - { - return base.SendKeyEvent(e); - } - public override bool FinishComposingText() { CompositionText = null; @@ -427,14 +393,16 @@ namespace Avalonia.Android.Platform.SkiaPlatform public readonly struct ComposingRegion { + private readonly int _start = -1; + private readonly int _end = -1; + public ComposingRegion(int start, int end) { - Start = start; - End = end; + _start = start; + _end = end; } - public int Start { get; } - - public int End { get; } + public int Start => _start; + public int End => _end; } } diff --git a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs index 2788789298..d1277f5855 100644 --- a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs +++ b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs @@ -43,7 +43,7 @@ namespace Avalonia.Controls { get { - if(_presenter is null) + if(_presenter is null || _parent is null) { return default; } @@ -56,7 +56,7 @@ namespace Avalonia.Controls var lineText = _presenter.Text?.Substring(lineStart, textLine.Length); - var anchorOffset = Math.Max(0, _presenter.SelectionStart - lineStart); + var anchorOffset = Math.Max(0, _parent.SelectionStart - lineStart); var cursorOffset = Math.Max(0, _presenter.SelectionEnd - lineStart); @@ -87,16 +87,19 @@ namespace Avalonia.Controls public void SelectInSurroundingText(int start, int end) { - if(_parent == null) + if(_parent is null ||_presenter is null) { return; } - //start and end are relative to surroundingText - var surroundingText = SurroundingText; + var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(_presenter.CaretIndex, false); - var selectionStart = surroundingText.AnchorOffset + start; - var selectionEnd = surroundingText.AnchorOffset + end; + var textLine = _presenter.TextLayout.TextLines[lineIndex]; + + var lineStart = textLine.FirstTextSourceIndex; + + var selectionStart = lineStart + start; + var selectionEnd = lineStart + end; _parent.SelectionStart = selectionStart; _parent.SelectionEnd = selectionEnd; @@ -104,13 +107,23 @@ namespace Avalonia.Controls public void SetPresenter(TextPresenter? presenter, TextBox? parent) { + if(_parent != null) + { + _parent.PropertyChanged -= OnParentPropertyChanged; + } + _parent = parent; + if(_parent != null) + { + _parent.PropertyChanged += OnParentPropertyChanged; + } + if (_presenter != null) { _presenter.PreeditText = null; - _presenter.CaretBoundsChanged -= OnCaretBoundsChanged; + _presenter.CaretBoundsChanged -= OnCaretBoundsChanged; } _presenter = presenter; @@ -125,6 +138,17 @@ namespace Avalonia.Controls OnCaretBoundsChanged(this, EventArgs.Empty); } + private void OnParentPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if(e.Property == TextBox.SelectionStartProperty || e.Property == TextBox.SelectionEndProperty) + { + if (SupportsSurroundingText) + { + SurroundingTextChanged?.Invoke(this, e); + } + } + } + public void DeleteSurroundingText(int beforeLength, int afterLength) { if (_parent != null && _presenter != null && string.IsNullOrEmpty(_presenter.PreeditText)) @@ -142,11 +166,6 @@ namespace Avalonia.Controls { Dispatcher.UIThread.Post(() => { - if (SupportsSurroundingText) - { - SurroundingTextChanged?.Invoke(this, e); - } - CursorRectangleChanged?.Invoke(this, e); }, DispatcherPriority.Input);