Browse Source

suspend selection updates in TextBoxTextInputMethodClient until all changes are completed (#15659)

pull/15666/head
Emmanuel Hansen 2 years ago
committed by GitHub
parent
commit
7da4f3b05f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 12
      src/Android/Avalonia.Android/AndroidInputMethod.cs
  2. 19
      src/Avalonia.Controls/TextBox.cs
  3. 27
      src/Avalonia.Controls/TextBoxTextInputMethodClient.cs

12
src/Android/Avalonia.Android/AndroidInputMethod.cs

@ -117,16 +117,20 @@ namespace Avalonia.Android
private void OnSelectionChanged() private void OnSelectionChanged()
{ {
if (Client is null) if (Client is null || _inputConnection is null)
{ {
return; return;
} }
OnSurroundingTextChanged();
var selection = Client.Selection; 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) private void _client_SurroundingTextChanged(object? sender, EventArgs e)
@ -140,8 +144,6 @@ namespace Avalonia.Android
{ {
if (_inputConnection is null || _inputConnection.IsInBatchEdit) if (_inputConnection is null || _inputConnection.IsInBatchEdit)
return; return;
OnSurroundingTextChanged();
OnSelectionChanged(); OnSelectionChanged();
} }

19
src/Avalonia.Controls/TextBox.cs

@ -406,6 +406,8 @@ namespace Avalonia.Controls
if (IsUndoEnabled && _undoRedoHelper.TryGetLastState(out state) && state.Text == Text) if (IsUndoEnabled && _undoRedoHelper.TryGetLastState(out state) && state.Text == Text)
_undoRedoHelper.UpdateLastState(); _undoRedoHelper.UpdateLastState();
using var _ = _imClient.BeginChange();
var newValue = e.GetNewValue<int>(); var newValue = e.GetNewValue<int>();
SetCurrentValue(SelectionStartProperty, newValue); SetCurrentValue(SelectionStartProperty, newValue);
SetCurrentValue(SelectionEndProperty, newValue); SetCurrentValue(SelectionEndProperty, newValue);
@ -1216,6 +1218,8 @@ namespace Avalonia.Controls
var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration; var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
using var _ = _imClient.BeginChange();
bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e)); bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e));
bool DetectSelection() => e.KeyModifiers.HasAllFlags(keymap.SelectionModifiers); bool DetectSelection() => e.KeyModifiers.HasAllFlags(keymap.SelectionModifiers);
@ -1547,6 +1551,8 @@ namespace Avalonia.Controls
var text = Text; var text = Text;
var clickInfo = e.GetCurrentPoint(this); var clickInfo = e.GetCurrentPoint(this);
using var _ = _imClient.BeginChange();
if (text != null && (e.Pointer.Type == PointerType.Mouse || e.ClickCount >= 2) && clickInfo.Properties.IsLeftButtonPressed && if (text != null && (e.Pointer.Type == PointerType.Mouse || e.ClickCount >= 2) && clickInfo.Properties.IsLeftButtonPressed &&
!(clickInfo.Pointer?.Captured is Border)) !(clickInfo.Pointer?.Captured is Border))
{ {
@ -1631,6 +1637,7 @@ namespace Avalonia.Controls
{ {
return; return;
} }
using var _ = _imClient.BeginChange();
// selection should not change during pointer move if the user right clicks // selection should not change during pointer move if the user right clicks
if (e.Pointer.Captured == _presenter && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) if (e.Pointer.Captured == _presenter && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
@ -1713,6 +1720,8 @@ namespace Avalonia.Controls
return; return;
} }
using var _ = _imClient.BeginChange();
if (e.Pointer.Type != PointerType.Mouse && !_isDoubleTapped) if (e.Pointer.Type != PointerType.Mouse && !_isDoubleTapped)
{ {
var text = Text; var text = Text;
@ -1857,6 +1866,8 @@ namespace Avalonia.Controls
return; return;
} }
using var _ = _imClient.BeginChange();
var text = Text ?? string.Empty; var text = Text ?? string.Empty;
var selectionStart = SelectionStart; var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd; var selectionEnd = SelectionEnd;
@ -2017,6 +2028,8 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public void SelectAll() public void SelectAll()
{ {
using var _ = _imClient.BeginChange();
SetCurrentValue(SelectionStartProperty, 0); SetCurrentValue(SelectionStartProperty, 0);
SetCurrentValue(SelectionEndProperty, Text?.Length ?? 0); SetCurrentValue(SelectionEndProperty, Text?.Length ?? 0);
} }
@ -2034,6 +2047,8 @@ namespace Avalonia.Controls
if (IsReadOnly) if (IsReadOnly)
return true; return true;
using var _ = _imClient.BeginChange();
var (start, end) = GetSelectionRange(); var (start, end) = GetSelectionRange();
if (start != end) if (start != end)
@ -2141,6 +2156,8 @@ namespace Avalonia.Controls
var text = Text ?? string.Empty; var text = Text ?? string.Empty;
var selectionStart = CaretIndex; var selectionStart = CaretIndex;
using var _ = _imClient.BeginChange();
MoveHorizontal(-1, true, false, false); MoveHorizontal(-1, true, false, false);
if (SelectionEnd > 0 && if (SelectionEnd > 0 &&
@ -2160,6 +2177,8 @@ namespace Avalonia.Controls
return; return;
} }
using var _ = _imClient.BeginChange();
SetCurrentValue(SelectionStartProperty, CaretIndex); SetCurrentValue(SelectionStartProperty, CaretIndex);
MoveHorizontal(1, true, true, false); MoveHorizontal(1, true, true, false);

27
src/Avalonia.Controls/TextBoxTextInputMethodClient.cs

@ -2,6 +2,7 @@ using System;
using Avalonia.Controls.Presenters; using Avalonia.Controls.Presenters;
using Avalonia.Input.TextInput; using Avalonia.Input.TextInput;
using Avalonia.Media.TextFormatting; using Avalonia.Media.TextFormatting;
using Avalonia.Reactive;
using Avalonia.Utilities; using Avalonia.Utilities;
namespace Avalonia.Controls namespace Avalonia.Controls
@ -10,6 +11,8 @@ namespace Avalonia.Controls
{ {
private TextBox? _parent; private TextBox? _parent;
private TextPresenter? _presenter; private TextPresenter? _presenter;
private bool _selectionChanged;
private bool _isInChange;
public override Visual TextViewVisual => _presenter!; public override Visual TextViewVisual => _presenter!;
@ -190,8 +193,30 @@ namespace Avalonia.Controls
if (e.Property == TextBox.SelectionStartProperty || e.Property == TextBox.SelectionEndProperty) 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;
}
} }
} }

Loading…
Cancel
Save