Skip to content

Commit

Permalink
suspend selection updates in TextBoxTextInputMethodClient until all c…
Browse files Browse the repository at this point in the history
…hanges are completed (#15659)
  • Loading branch information
emmauss authored May 9, 2024
1 parent e787bb4 commit 7da4f3b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 6 deletions.
12 changes: 7 additions & 5 deletions src/Android/Avalonia.Android/AndroidInputMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,20 @@ private void _client_SelectionChanged(object? sender, EventArgs e)

private void OnSelectionChanged()
{
if (Client is null)
if (Client is null || _inputConnection is null)
{
return;
}

OnSurroundingTextChanged();

var selection = Client.Selection;

_imm.UpdateSelection(_host, selection.Start, selection.End, selection.Start, selection.End);
_inputConnection.SetSelection(selection.Start, selection.End);

var composition = _inputConnection.EditableWrapper.CurrentComposition;

_inputConnection?.SetSelection(selection.Start, selection.End);
_imm.UpdateSelection(_host, selection.Start, selection.End, composition.Start, composition.End);
}

private void _client_SurroundingTextChanged(object? sender, EventArgs e)
Expand All @@ -140,8 +144,6 @@ public void OnBatchEditedEnded()
{
if (_inputConnection is null || _inputConnection.IsInBatchEdit)
return;

OnSurroundingTextChanged();
OnSelectionChanged();
}

Expand Down
19 changes: 19 additions & 0 deletions src/Avalonia.Controls/TextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,8 @@ private void OnCaretIndexChanged(AvaloniaPropertyChangedEventArgs e)
if (IsUndoEnabled && _undoRedoHelper.TryGetLastState(out state) && state.Text == Text)
_undoRedoHelper.UpdateLastState();

using var _ = _imClient.BeginChange();

var newValue = e.GetNewValue<int>();
SetCurrentValue(SelectionStartProperty, newValue);
SetCurrentValue(SelectionEndProperty, newValue);
Expand Down Expand Up @@ -1216,6 +1218,8 @@ protected override void OnKeyDown(KeyEventArgs e)

var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;

using var _ = _imClient.BeginChange();

bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e));
bool DetectSelection() => e.KeyModifiers.HasAllFlags(keymap.SelectionModifiers);

Expand Down Expand Up @@ -1547,6 +1551,8 @@ protected override void OnPointerPressed(PointerPressedEventArgs e)
var text = Text;
var clickInfo = e.GetCurrentPoint(this);

using var _ = _imClient.BeginChange();

if (text != null && (e.Pointer.Type == PointerType.Mouse || e.ClickCount >= 2) && clickInfo.Properties.IsLeftButtonPressed &&
!(clickInfo.Pointer?.Captured is Border))
{
Expand Down Expand Up @@ -1631,6 +1637,7 @@ protected override void OnPointerMoved(PointerEventArgs e)
{
return;
}
using var _ = _imClient.BeginChange();

// selection should not change during pointer move if the user right clicks
if (e.Pointer.Captured == _presenter && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
Expand Down Expand Up @@ -1713,6 +1720,8 @@ protected override void OnPointerReleased(PointerReleasedEventArgs e)
return;
}

using var _ = _imClient.BeginChange();

if (e.Pointer.Type != PointerType.Mouse && !_isDoubleTapped)
{
var text = Text;
Expand Down Expand Up @@ -1857,6 +1866,8 @@ private void MoveHorizontal(int direction, bool wholeWord, bool isSelecting, boo
return;
}

using var _ = _imClient.BeginChange();

var text = Text ?? string.Empty;
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
Expand Down Expand Up @@ -2017,6 +2028,8 @@ public void ScrollToLine(int lineIndex)
/// </summary>
public void SelectAll()
{
using var _ = _imClient.BeginChange();

SetCurrentValue(SelectionStartProperty, 0);
SetCurrentValue(SelectionEndProperty, Text?.Length ?? 0);
}
Expand All @@ -2034,6 +2047,8 @@ internal bool DeleteSelection()
if (IsReadOnly)
return true;

using var _ = _imClient.BeginChange();

var (start, end) = GetSelectionRange();

if (start != end)
Expand Down Expand Up @@ -2141,6 +2156,8 @@ private void SetSelectionForControlBackspace()
var text = Text ?? string.Empty;
var selectionStart = CaretIndex;

using var _ = _imClient.BeginChange();

MoveHorizontal(-1, true, false, false);

if (SelectionEnd > 0 &&
Expand All @@ -2160,6 +2177,8 @@ private void SetSelectionForControlDelete()
return;
}

using var _ = _imClient.BeginChange();

SetCurrentValue(SelectionStartProperty, CaretIndex);

MoveHorizontal(1, true, true, false);
Expand Down
27 changes: 26 additions & 1 deletion src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Avalonia.Controls.Presenters;
using Avalonia.Input.TextInput;
using Avalonia.Media.TextFormatting;
using Avalonia.Reactive;
using Avalonia.Utilities;

namespace Avalonia.Controls
Expand All @@ -10,6 +11,8 @@ internal class TextBoxTextInputMethodClient : TextInputMethodClient
{
private TextBox? _parent;
private TextPresenter? _presenter;
private bool _selectionChanged;
private bool _isInChange;

public override Visual TextViewVisual => _presenter!;

Expand Down Expand Up @@ -190,8 +193,30 @@ private void OnParentPropertyChanged(object? sender, AvaloniaPropertyChangedEven

if (e.Property == TextBox.SelectionStartProperty || e.Property == TextBox.SelectionEndProperty)
{
RaiseSelectionChanged();
if (_isInChange)
_selectionChanged = true;
else
RaiseSelectionChanged();
}
}

internal IDisposable BeginChange()
{
if (_isInChange)
return Disposable.Empty;

_isInChange = true;
return Disposable.Create(RaiseEvents);
}

private void RaiseEvents()
{
_isInChange = false;

if (_selectionChanged)
RaiseSelectionChanged();

_selectionChanged = false;
}
}
}

0 comments on commit 7da4f3b

Please sign in to comment.