protected override void OnKeyDown()

in src/Avalonia.Controls/TextBox.cs [1279:1609]


        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (_presenter == null)
            {
                return;
            }

            if (!string.IsNullOrEmpty(_presenter.PreeditText))
            {
                return;
            }

            var text = Text ?? string.Empty;
            var caretIndex = CaretIndex;
            var movement = false;
            var selection = false;
            var handled = false;
            var modifiers = e.KeyModifiers;

            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);

            if (Match(keymap.SelectAll))
            {
                SelectAll();
                handled = true;
            }
            else if (Match(keymap.Copy))
            {
                if (!IsPasswordBox)
                {
                    Copy();
                }

                handled = true;
            }
            else if (Match(keymap.Cut))
            {
                if (!IsPasswordBox)
                {
                    Cut();
                }

                handled = true;
            }
            else if (Match(keymap.Paste))
            {
                Paste();
                handled = true;
            }
            else if (Match(keymap.Undo) && IsUndoEnabled)
            {
                Undo();

                handled = true;
            }
            else if (Match(keymap.Redo) && IsUndoEnabled)
            {
                Redo();

                handled = true;
            }
            else if (Match(keymap.MoveCursorToTheStartOfDocument))
            {
                MoveHome(true);
                movement = true;
                selection = false;
                handled = true;
                SetCurrentValue(CaretIndexProperty, _presenter.CaretIndex);
            }
            else if (Match(keymap.MoveCursorToTheEndOfDocument))
            {
                MoveEnd(true);
                movement = true;
                selection = false;
                handled = true;
                SetCurrentValue(CaretIndexProperty, _presenter.CaretIndex);
            }
            else if (Match(keymap.MoveCursorToTheStartOfLine))
            {
                MoveHome(false);
                movement = true;
                selection = false;
                handled = true;
                SetCurrentValue(CaretIndexProperty, _presenter.CaretIndex);
            }
            else if (Match(keymap.MoveCursorToTheEndOfLine))
            {
                MoveEnd(false);
                movement = true;
                selection = false;
                handled = true;
                SetCurrentValue(CaretIndexProperty, _presenter.CaretIndex);
            }
            else if (Match(keymap.MoveCursorToTheStartOfDocumentWithSelection))
            {
                SetCurrentValue(SelectionStartProperty, caretIndex);
                MoveHome(true);
                SetCurrentValue(SelectionEndProperty, _presenter.CaretIndex);
                movement = true;
                selection = true;
                handled = true;
            }
            else if (Match(keymap.MoveCursorToTheEndOfDocumentWithSelection))
            {
                SetCurrentValue(SelectionStartProperty, caretIndex);
                MoveEnd(true);
                SetCurrentValue(SelectionEndProperty, _presenter.CaretIndex);
                movement = true;
                selection = true;
                handled = true;
            }
            else if (Match(keymap.MoveCursorToTheStartOfLineWithSelection))
            {
                SetCurrentValue(SelectionStartProperty, caretIndex);
                MoveHome(false);
                SetCurrentValue(SelectionEndProperty, _presenter.CaretIndex);
                movement = true;
                selection = true;
                handled = true;

            }
            else if (Match(keymap.MoveCursorToTheEndOfLineWithSelection))
            {
                SetCurrentValue(SelectionStartProperty, caretIndex);
                MoveEnd(false);
                SetCurrentValue(SelectionEndProperty, _presenter.CaretIndex);
                movement = true;
                selection = true;
                handled = true;
            }
            else if (Match(keymap.PageLeft))
            {
                MovePageLeft();
                movement = true;
                selection = false;
                handled = true;
            }
            else if (Match(keymap.PageRight))
            {
                MovePageRight();
                movement = true;
                selection = false;
                handled = true;
            }
            else if (Match(keymap.PageUp))
            {
                MovePageUp();
                movement = true;
                selection = false;
                handled = true;
            }
            else if (Match(keymap.PageDown))
            {
                MovePageDown();
                movement = true;
                selection = false;
                handled = true;
            }
            else
            {
                // It's not secure to rely on password field content when moving.
                bool hasWholeWordModifiers = modifiers.HasAllFlags(keymap.WholeWordTextActionModifiers) && !IsPasswordBox;
                switch (e.Key)
                {
                    case Key.Left:
                        selection = DetectSelection();
                        MoveHorizontal(-1, hasWholeWordModifiers, selection, true);
                        if (caretIndex != _presenter.CaretIndex)
                        {
                            movement = true;
                        }
                        break;

                    case Key.Right:
                        selection = DetectSelection();
                        MoveHorizontal(1, hasWholeWordModifiers, selection, true);
                        if (caretIndex != _presenter.CaretIndex)
                        {
                            movement = true;
                        }
                        break;

                    case Key.Up:
                        selection = DetectSelection();
                        MoveVertical(LogicalDirection.Backward, selection);
                        if (caretIndex != _presenter.CaretIndex)
                        {
                            movement = true;
                        }
                        break;

                    case Key.Down:
                        selection = DetectSelection();
                        MoveVertical(LogicalDirection.Forward, selection);
                        if (caretIndex != _presenter.CaretIndex)
                        {
                            movement = true;
                        }
                        break;

                    case Key.Back:
                        {
                            SnapshotUndoRedo();

                            if (hasWholeWordModifiers && SelectionStart == SelectionEnd)
                            {
                                SetSelectionForControlBackspace();
                            }

                            if (!DeleteSelection())
                            {
                                var characterHit = _presenter.GetNextCharacterHit(LogicalDirection.Backward);

                                var backspacePosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength;

                                var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(caretIndex, true);

                                var backspaceCharacterHit = _presenter.TextLayout.TextLines[lineIndex]
                                    .GetBackspaceCaretCharacterHit(new CharacterHit(caretIndex));

                                if (backspaceCharacterHit.FirstCharacterIndex > backspacePosition &&
                                    backspaceCharacterHit.FirstCharacterIndex < caretIndex)
                                {
                                    backspacePosition = backspaceCharacterHit.FirstCharacterIndex;
                                }

                                if (caretIndex != backspacePosition)
                                {
                                    var start = Math.Min(backspacePosition, caretIndex);
                                    var end = Math.Max(backspacePosition, caretIndex);

                                    var length = end - start;

                                    var sb = StringBuilderCache.Acquire(text.Length);
                                    sb.Append(text);
                                    sb.Remove(start, end - start);

                                    SetCurrentValue(TextProperty, StringBuilderCache.GetStringAndRelease(sb));

                                    SetCurrentValue(CaretIndexProperty, start);

                                    _presenter.MoveCaretToTextPosition(start);
                                }
                            }

                            SnapshotUndoRedo();

                            handled = true;
                            break;
                        }
                    case Key.Delete:
                        SnapshotUndoRedo();

                        if (hasWholeWordModifiers && SelectionStart == SelectionEnd)
                        {
                            SetSelectionForControlDelete();
                        }

                        if (!DeleteSelection())
                        {
                            var characterHit = _presenter.GetNextCharacterHit();

                            var nextPosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength;

                            if (nextPosition != caretIndex)
                            {
                                var start = Math.Min(nextPosition, caretIndex);
                                var end = Math.Max(nextPosition, caretIndex);

                                var sb = StringBuilderCache.Acquire(text.Length);
                                sb.Append(text);
                                sb.Remove(start, end - start);

                                SetCurrentValue(TextProperty, StringBuilderCache.GetStringAndRelease(sb));
                            }
                        }

                        SnapshotUndoRedo();

                        handled = true;
                        break;

                    case Key.Enter:
                        if (AcceptsReturn)
                        {
                            SnapshotUndoRedo();
                            HandleTextInput(NewLine);
                            handled = true;
                        }

                        break;

                    case Key.Tab:
                        if (AcceptsTab)
                        {
                            SnapshotUndoRedo();
                            HandleTextInput("\t");
                            handled = true;
                        }
                        else
                        {
                            base.OnKeyDown(e);
                        }

                        break;

                    case Key.Space:
                        SnapshotUndoRedo(); // always snapshot in between words
                        break;

                    default:
                        handled = false;
                        break;
                }
            }

            if (movement && !selection)
            {
                ClearSelection();
            }

            if (handled || movement)
            {
                e.Handled = true;
            }
        }