Skip to content

Commit 6b5a9a7

Browse files
exGensImplmaxkatz6
authored andcommitted
Improving TextBox behaviour on Ctrl+Backspace down event (#14138)
* Test: TextBox Ctrl+Back caret position * Fixed: TextBox Ctrl+Back caret position * Test: TextBox Ctrl+Back remove double whitespace * Fixed: TextBox Ctrl+Back remove double whitespace * Test: TextBox Ctrl+Back undo return caret position * Fixed: TextBox Ctrl+Back undo return caret position
1 parent dd0da02 commit 6b5a9a7

File tree

2 files changed

+92
-9
lines changed

2 files changed

+92
-9
lines changed

src/Avalonia.Controls/TextBox.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,13 +1275,13 @@ protected override void OnKeyDown(KeyEventArgs e)
12751275
{
12761276
case Key.Left:
12771277
selection = DetectSelection();
1278-
MoveHorizontal(-1, hasWholeWordModifiers, selection);
1278+
MoveHorizontal(-1, hasWholeWordModifiers, selection, true);
12791279
movement = true;
12801280
break;
12811281

12821282
case Key.Right:
12831283
selection = DetectSelection();
1284-
MoveHorizontal(1, hasWholeWordModifiers, selection);
1284+
MoveHorizontal(1, hasWholeWordModifiers, selection, true);
12851285
movement = true;
12861286
break;
12871287

@@ -1672,7 +1672,7 @@ internal static int CoerceCaretIndex(AvaloniaObject sender, int value)
16721672
/// </summary>
16731673
public void Clear() => SetCurrentValue(TextProperty, string.Empty);
16741674

1675-
private void MoveHorizontal(int direction, bool wholeWord, bool isSelecting)
1675+
private void MoveHorizontal(int direction, bool wholeWord, bool isSelecting, bool moveCaretPosition)
16761676
{
16771677
if (_presenter == null)
16781678
{
@@ -1727,10 +1727,13 @@ private void MoveHorizontal(int direction, bool wholeWord, bool isSelecting)
17271727
}
17281728

17291729
SetCurrentValue(SelectionEndProperty, SelectionEnd + offset);
1730+
1731+
if (moveCaretPosition)
1732+
{
1733+
_presenter.MoveCaretToTextPosition(SelectionEnd);
1734+
}
17301735

1731-
_presenter.MoveCaretToTextPosition(SelectionEnd);
1732-
1733-
if (!isSelecting)
1736+
if (!isSelecting && moveCaretPosition)
17341737
{
17351738
SetCurrentValue(CaretIndexProperty, SelectionEnd);
17361739
}
@@ -1867,7 +1870,7 @@ internal bool DeleteSelection()
18671870

18681871
_presenter?.MoveCaretToTextPosition(start);
18691872

1870-
SetCurrentValue(CaretIndexProperty, start);
1873+
SetCurrentValue(SelectionStartProperty, start);
18711874

18721875
ClearSelection();
18731876

@@ -1957,9 +1960,16 @@ private void RaiseTextChangeEvents()
19571960

19581961
private void SetSelectionForControlBackspace()
19591962
{
1963+
var text = Text ?? string.Empty;
19601964
var selectionStart = CaretIndex;
19611965

1962-
MoveHorizontal(-1, true, false);
1966+
MoveHorizontal(-1, true, false, false);
1967+
1968+
if (SelectionEnd > 0 &&
1969+
selectionStart < text.Length && text[selectionStart] == ' ')
1970+
{
1971+
SetCurrentValue(SelectionEndProperty, SelectionEnd - 1);
1972+
}
19631973

19641974
SetCurrentValue(SelectionStartProperty, selectionStart);
19651975
}
@@ -1974,7 +1984,7 @@ private void SetSelectionForControlDelete()
19741984

19751985
SetCurrentValue(SelectionStartProperty, CaretIndex);
19761986

1977-
MoveHorizontal(1, true, true);
1987+
MoveHorizontal(1, true, true, false);
19781988

19791989
if (SelectionEnd < textLength && Text![SelectionEnd] == ' ')
19801990
{

tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,79 @@ public void CaretIndex_Can_Moved_To_Position_After_The_End_Of_Text_With_Arrow_Ke
151151
Assert.Equal(4, target.CaretIndex);
152152
}
153153
}
154+
155+
[Fact]
156+
public void Control_Backspace_Should_Set_Caret_Position_To_The_Start_Of_The_Deletion()
157+
{
158+
using (UnitTestApplication.Start(Services))
159+
{
160+
var target = new TextBox
161+
{
162+
Template = CreateTemplate(),
163+
Text = "First Second Third",
164+
SelectionStart = 13,
165+
SelectionEnd = 13
166+
};
167+
168+
target.CaretIndex = 10;
169+
target.ApplyTemplate();
170+
171+
// (First Second |Third)
172+
RaiseKeyEvent(target, Key.Back, KeyModifiers.Control);
173+
// (First |Third)
174+
175+
Assert.Equal(6, target.CaretIndex);
176+
}
177+
}
178+
179+
[Fact]
180+
public void Control_Backspace_Should_Remove_The_Double_Whitespace_If_Caret_Index_Was_At_The_End_Of_A_Word()
181+
{
182+
using (UnitTestApplication.Start(Services))
183+
{
184+
var target = new TextBox
185+
{
186+
Template = CreateTemplate(),
187+
Text = "First Second Third",
188+
SelectionStart = 12,
189+
SelectionEnd = 12
190+
};
191+
192+
target.ApplyTemplate();
193+
194+
// (First Second| Third)
195+
RaiseKeyEvent(target, Key.Back, KeyModifiers.Control);
196+
// (First| Third)
197+
198+
Assert.Equal("First Third", target.Text);
199+
}
200+
}
201+
202+
[Fact]
203+
public void Control_Backspace_Undo_Should_Return_Caret_Position()
204+
{
205+
using (UnitTestApplication.Start(Services))
206+
{
207+
var target = new TextBox
208+
{
209+
Template = CreateTemplate(),
210+
Text = "First Second Third",
211+
SelectionStart = 9,
212+
SelectionEnd = 9
213+
};
214+
215+
target.ApplyTemplate();
216+
217+
// (First Second| Third)
218+
RaiseKeyEvent(target, Key.Back, KeyModifiers.Control);
219+
// (First| Third)
220+
221+
target.Undo();
222+
// (First Second| Third)
223+
224+
Assert.Equal(9, target.CaretIndex);
225+
}
226+
}
154227

155228
[Fact]
156229
public void Press_Ctrl_A_Select_All_Text()

0 commit comments

Comments
 (0)