From 169480e74de7a9c4c3236a9eba425e904c500f55 Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Thu, 22 Sep 2022 15:35:11 +0200 Subject: [PATCH] Fix GetTextLineText --- .../Avalonia.Android/AndroidInputMethod.cs | 5 ++- .../Platform/SkiaPlatform/TopLevelImpl.cs | 16 +++++--- .../Input/TextInput/ITextInputMethodClient.cs | 7 ---- .../Presenters/TextPresenter.cs | 34 +++++++++++----- src/Avalonia.Controls/TextBox.cs | 5 +++ .../TextBoxTextInputMethodClient.cs | 40 ++++++++++++------- .../Avalonia.Win32/Input/Imm32InputMethod.cs | 4 -- 7 files changed, 69 insertions(+), 42 deletions(-) diff --git a/src/Android/Avalonia.Android/AndroidInputMethod.cs b/src/Android/Avalonia.Android/AndroidInputMethod.cs index 590dc70cb4..b2ce2a38b1 100644 --- a/src/Android/Avalonia.Android/AndroidInputMethod.cs +++ b/src/Android/Avalonia.Android/AndroidInputMethod.cs @@ -100,12 +100,13 @@ namespace Avalonia.Android { var surroundingText = Client.SurroundingText; - _imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, _inputConnection.ComposingRegion.Start, _inputConnection.ComposingRegion.End); + _imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, surroundingText.AnchorOffset, surroundingText.CursorOffset); } } public void SetCursorRect(Rect rect) { + } public void SetOptions(TextInputOptions options) @@ -114,7 +115,7 @@ namespace Avalonia.Android _host.InitEditorInfo((_host, outAttrs) => { - _inputConnection?.FinishComposingText(); + //_inputConnection?.FinishComposingText(); outAttrs.InputType = options.ContentType switch { diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index fce7106674..491d590762 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -276,7 +276,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform public View View { get; } - public ComposingRegion ComposingRegion { get; private set; } + public ComposingRegion ComposingRegion { get; internal set; } public string CompositionText { get; private set; } @@ -365,14 +365,18 @@ namespace Avalonia.Android.Platform.SkiaPlatform { _inputMethod.Client.SetPreeditText(null); - var textLength = text.Length(); - - if (string.IsNullOrEmpty(CompositionText) && ComposingRegion.End > 0) + if (string.IsNullOrEmpty(CompositionText)) { - _inputMethod.Client.SelectInSurroundingText(ComposingRegion.Start, ComposingRegion.Start + textLength); + var surroundingText = _inputMethod.Client.SurroundingText; + + var composingRegionLength = ComposingRegion.End - ComposingRegion.Start; + + var composingRegionText = surroundingText.Text?.Substring(ComposingRegion.Start, composingRegionLength); + + _inputMethod.Client.SelectInSurroundingText(ComposingRegion.Start, ComposingRegion.End); } - ComposingRegion = new ComposingRegion(ComposingRegion.Start, ComposingRegion.Start + textLength); + ComposingRegion = new ComposingRegion(ComposingRegion.End, ComposingRegion.End); } return base.CommitText(text, newCursorPosition); diff --git a/src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs b/src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs index 14d57334d1..325b6dd0ef 100644 --- a/src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs +++ b/src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs @@ -42,13 +42,6 @@ namespace Avalonia.Input.TextInput /// event EventHandler? SurroundingTextChanged; - /// - /// Deletes specified length before and after current selection. - /// - /// The length before current selection. - /// The length after current selection. - void DeleteSurroundingText(int beforeLength, int afterLength); - void SelectInSurroundingText(int start, int end); } diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index b0b12d1ff9..a9bb16c7df 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -847,12 +847,21 @@ namespace Avalonia.Controls.Presenters _caretTimer.Tick -= CaretTimerTick; } - protected void OnPreeditTextChanged(string? preeditText) + protected void OnPreeditTextChanged(string? oldValue, string? newValue) { InvalidateTextLayout(); - if (preeditText is null) + if (string.IsNullOrEmpty(newValue)) { + if (!string.IsNullOrEmpty(oldValue)) + { + var textPosition = _compositionStartHit.FirstCharacterIndex + _compositionStartHit.TrailingLength + newValue?.Length ?? 0; + + var characterHit = GetCharacterHitFromTextPosition(textPosition); + + UpdateCaret(characterHit, true); + } + _compositionStartHit = new CharacterHit(-1); } else @@ -865,18 +874,25 @@ namespace Avalonia.Controls.Presenters if (_compositionStartHit.FirstCharacterIndex != -1) { - var textPosition = _compositionStartHit.FirstCharacterIndex + _compositionStartHit.TrailingLength + preeditText?.Length ?? 0; - - var lineIndex = TextLayout.GetLineIndexFromCharacterIndex(textPosition, true); - - var textLine = TextLayout.TextLines[lineIndex]; + var textPosition = _compositionStartHit.FirstCharacterIndex + _compositionStartHit.TrailingLength + newValue?.Length ?? 0; - var characterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(textPosition - 1)); + var characterHit = GetCharacterHitFromTextPosition(textPosition); UpdateCaret(characterHit, false); } } + private CharacterHit GetCharacterHitFromTextPosition(int textPosition) + { + var lineIndex = TextLayout.GetLineIndexFromCharacterIndex(textPosition, true); + + var textLine = TextLayout.TextLines[lineIndex]; + + var characterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(textPosition - 1)); + + return characterHit; + } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); @@ -885,7 +901,7 @@ namespace Avalonia.Controls.Presenters { case nameof(PreeditText): { - OnPreeditTextChanged(change.NewValue as string); + OnPreeditTextChanged(change.OldValue as string, change.NewValue as string); break; } diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index d14074a2ff..964a153c8b 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -831,6 +831,11 @@ namespace Avalonia.Controls return; } + if (!string.IsNullOrEmpty(_presenter.PreeditText)) + { + return; + } + var text = Text ?? string.Empty; var caretIndex = CaretIndex; var movement = false; diff --git a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs index d1277f5855..d39d964277 100644 --- a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs +++ b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs @@ -1,7 +1,9 @@ using System; using Avalonia.Controls.Presenters; using Avalonia.Input.TextInput; +using Avalonia.Media.TextFormatting; using Avalonia.Threading; +using Avalonia.Utilities; using Avalonia.VisualTree; namespace Avalonia.Controls @@ -54,7 +56,7 @@ namespace Avalonia.Controls var lineStart = textLine.FirstTextSourceIndex; - var lineText = _presenter.Text?.Substring(lineStart, textLine.Length); + var lineText = GetTextLineText(textLine); var anchorOffset = Math.Max(0, _parent.SelectionStart - lineStart); @@ -69,6 +71,29 @@ namespace Avalonia.Controls } } + private static string GetTextLineText(TextLine textLine) + { + var builder = StringBuilderCache.Acquire(textLine.Length); + + foreach (var run in textLine.TextRuns) + { + if(run.Text.Length > 0) + { +#if NET6_0 + builder.Append(run.Text.Span); +#else + builder.Append(run.Text.Span.ToArray()); +#endif + } + } + + var lineText = builder.ToString(); + + StringBuilderCache.Release(builder); + + return lineText; + } + public event EventHandler? TextViewVisualChanged; public event EventHandler? CursorRectangleChanged; @@ -149,19 +174,6 @@ namespace Avalonia.Controls } } - public void DeleteSurroundingText(int beforeLength, int afterLength) - { - if (_parent != null && _presenter != null && string.IsNullOrEmpty(_presenter.PreeditText)) - { - var start = _presenter.SelectionStart; - - _parent.SelectionStart = start - beforeLength; - _parent.SelectionEnd = start + afterLength; - - _parent.DeleteSelection(true); - } - } - private void OnCaretBoundsChanged(object? sender, EventArgs e) { Dispatcher.UIThread.Post(() => diff --git a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs index b504b306c7..7ef1cb1d1c 100644 --- a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs +++ b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.InteropServices; using System.Text; using Avalonia.Input.TextInput; using Avalonia.Threading; @@ -79,9 +78,7 @@ namespace Avalonia.Win32.Input { HWND = hwnd; _parent = parent; - _active = false; _langId = PRIMARYLANGID(LGID(HKL)); - _showCompositionWindow = true; _parent = parent; @@ -105,7 +102,6 @@ namespace Avalonia.Win32.Input _parent = null; _client = null; _langId = 0; - _showCompositionWindow = false; IsComposing = false; }