Skip to content

Commit 5b85b16

Browse files
authored
Fixes #4096. Ctrl+Delete/Backspace (#4099)
* Fixes #4096. Ctrl+Delete/Backspace * Fixes Ctrl+Backspace exception * Fixes #4039. Keyboard-selected text not hightlighted in TextView * Fixes #4048. Selecting text with mouse isn't working in v2win driver * Fixes #4061. Last character of line not mouse-selectable in TextView * Fix unit test not updating cursor position by not invoke UnwrappedCursorPosition * Reinforcing unit test * Fix v2win input processor * Fixes #4100. PopupAutoComplete isn't clearing after pressing ESC * Cleanup code * Add ControlKeyState into unit tests * Fix merge conflicts
1 parent cbfd545 commit 5b85b16

File tree

12 files changed

+299
-77
lines changed

12 files changed

+299
-77
lines changed

Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,10 @@ internal void ProcessInput ()
777777
wch -= 60;
778778
k = KeyCode.ShiftMask | KeyCode.AltMask | MapCursesKey (wch);
779779
}
780+
else if (wch == 520) // Ctrl+Delete
781+
{
782+
k = KeyCode.CtrlMask | KeyCode.Delete;
783+
}
780784

781785
OnKeyDown (new Key (k));
782786
OnKeyUp (new Key (k));
@@ -878,6 +882,12 @@ internal void ProcessInput ()
878882
OnKeyDown (key);
879883
OnKeyUp (key);
880884
}
885+
else if (wch == 8) // Ctrl+Backspace
886+
{
887+
k = KeyCode.Backspace | KeyCode.CtrlMask;
888+
OnKeyDown (new Key (k));
889+
OnKeyUp (new Key (k));
890+
}
881891
else if (wch == Curses.KeyTab)
882892
{
883893
k = MapCursesKey (wch);

Terminal.Gui/ConsoleDrivers/EscSeqUtils/EscSeqUtils.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,17 @@ public static ConsoleKeyInfo MapConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
11231123
(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
11241124
true);
11251125
}
1126+
else if (consoleKeyInfo is { Key: 0, KeyChar: '\b' })
1127+
{
1128+
key = ConsoleKey.Backspace;
1129+
1130+
newConsoleKeyInfo = new (
1131+
consoleKeyInfo.KeyChar,
1132+
key,
1133+
(consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
1134+
(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
1135+
true);
1136+
}
11261137
else if (consoleKeyInfo.Key == 0)
11271138
{
11281139
key = (ConsoleKey)(char)(consoleKeyInfo.KeyChar + (uint)ConsoleKey.A - 1);

Terminal.Gui/ConsoleDrivers/V2/WindowsInputProcessor.cs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ protected override void ProcessAfterParsing (InputRecord input)
8181

8282
public MouseEventArgs ToDriverMouse (MouseEventRecord e)
8383
{
84-
var mouseFlags = MouseFlags.ReportMousePosition;
84+
var mouseFlags = MouseFlags.None;
8585

8686
mouseFlags = UpdateMouseFlags (mouseFlags, e.ButtonState, ButtonState.Button1Pressed, MouseFlags.Button1Pressed, MouseFlags.Button1Released, 0);
8787
mouseFlags = UpdateMouseFlags (mouseFlags, e.ButtonState, ButtonState.Button2Pressed, MouseFlags.Button2Pressed, MouseFlags.Button2Released, 1);
@@ -100,9 +100,6 @@ public MouseEventArgs ToDriverMouse (MouseEventRecord e)
100100
{
101101
mouseFlags |= MouseFlags.Button3Released;
102102

103-
// Removes the moved flag when raising released flags (see https://github.com/gui-cs/Terminal.Gui/issues/4088)
104-
mouseFlags &= ~MouseFlags.ReportMousePosition;
105-
106103
_lastWasPressed [2] = false;
107104
}
108105
}
@@ -123,14 +120,44 @@ public MouseEventArgs ToDriverMouse (MouseEventRecord e)
123120
}
124121
}
125122

123+
if (e.EventFlags != EventFlags.NoEvent)
124+
{
125+
switch (e.EventFlags)
126+
{
127+
case EventFlags.MouseMoved:
128+
mouseFlags |= MouseFlags.ReportMousePosition;
129+
130+
break;
131+
}
132+
}
133+
134+
if (e.ControlKeyState != ControlKeyState.NoControlKeyPressed)
135+
{
136+
switch (e.ControlKeyState)
137+
{
138+
case ControlKeyState.RightAltPressed:
139+
case ControlKeyState.LeftAltPressed:
140+
mouseFlags |= MouseFlags.ButtonAlt;
141+
142+
break;
143+
case ControlKeyState.RightControlPressed:
144+
case ControlKeyState.LeftControlPressed:
145+
mouseFlags |= MouseFlags.ButtonCtrl;
146+
147+
break;
148+
case ControlKeyState.ShiftPressed:
149+
mouseFlags |= MouseFlags.ButtonShift;
150+
151+
break;
152+
}
153+
}
154+
126155
var result = new MouseEventArgs
127156
{
128157
Position = new (e.MousePosition.X, e.MousePosition.Y),
129158
Flags = mouseFlags
130159
};
131160

132-
// TODO: Return keys too
133-
134161
return result;
135162
}
136163

@@ -154,8 +181,6 @@ int buttonIndex
154181
{
155182
current |= releasedFlag;
156183

157-
// Removes the moved flag when raising released flags (see https://github.com/gui-cs/Terminal.Gui/issues/4088)
158-
current &= ~MouseFlags.ReportMousePosition;
159184
_lastWasPressed [buttonIndex] = false;
160185
}
161186
}

Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,11 +789,11 @@ public static KeyCode MapKey (WindowsConsole.ConsoleKeyInfoEx keyInfoEx)
789789
if (keyInfo.KeyChar <= 'Z')
790790
{
791791
return (KeyCode)keyInfo.Key | KeyCode.ShiftMask;
792-
}
792+
}
793793

794794
// Always return the KeyChar because it may be an Á, À with Oem1, etc
795795
return (KeyCode)keyInfo.KeyChar;
796-
}
796+
}
797797
}
798798

799799
if (keyInfo.KeyChar <= 'z')
@@ -806,6 +806,7 @@ public static KeyCode MapKey (WindowsConsole.ConsoleKeyInfoEx keyInfoEx)
806806
}
807807

808808
// Handle control keys whose VK codes match the related ASCII value (those below ASCII 33) like ESC
809+
// Also handle the key ASCII value 127 (BACK)
809810
if (Enum.IsDefined (typeof (KeyCode), (uint)keyInfo.Key))
810811
{
811812
// If the key is JUST a modifier, return it as just that key
@@ -829,6 +830,12 @@ public static KeyCode MapKey (WindowsConsole.ConsoleKeyInfoEx keyInfoEx)
829830
return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.KeyChar);
830831
}
831832

833+
// Backspace (ASCII 127)
834+
if (keyInfo.KeyChar == '\u007f')
835+
{
836+
return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.Key);
837+
}
838+
832839
if (keyInfo.Key != ConsoleKey.None)
833840
{
834841
return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.KeyChar);

Terminal.Gui/Text/Autocomplete/AutocompleteBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public abstract class AutocompleteBase : IAutocomplete
4343
public virtual Key CloseKey { get; set; } = Key.Esc;
4444

4545
/// <inheritdoc/>
46-
public virtual Key Reopen { get; set; } = Key.Space.WithCtrl.WithAlt;
46+
public virtual Key Reopen { get; set; } = Key.Space.WithShift;
4747

4848
/// <inheritdoc/>
4949
public virtual AutocompleteContext Context { get; set; }

Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ public override void RenderOverlay (Point renderAt)
285285
if (PopupInsideContainer)
286286
{
287287
// don't overspill vertically
288-
height = Math.Min (HostControl.Viewport.Height - renderAt.Y, MaxHeight);
288+
height = Math.Min (Math.Min (HostControl!.Viewport.Height - renderAt.Y, MaxHeight), Suggestions.Count);
289289

290290
// There is no space below, lets see if can popup on top
291291
if (height < Suggestions.Count && HostControl.Viewport.Height - renderAt.Y >= height)
@@ -419,8 +419,9 @@ protected void Close ()
419419
ClearSuggestions ();
420420
Visible = false;
421421
_closed = true;
422-
HostControl?.SetNeedsDraw ();
423422
//RemovePopupFromTop ();
423+
_popup.Visible = false;
424+
HostControl?.SetNeedsDraw ();
424425
}
425426

426427
/// <summary>Deletes the text backwards before insert the selected text in the <see cref="HostControl"/>.</summary>
@@ -507,6 +508,7 @@ protected bool ReopenSuggestions ()
507508
{
508509
Visible = true;
509510
_closed = false;
511+
_popup.Visible = true;
510512
HostControl?.SetNeedsDraw ();
511513

512514
return true;

Terminal.Gui/Views/TextInput/TextField.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,6 @@ protected override bool OnDrawingContent ()
10151015

10161016
RenderCaption ();
10171017

1018-
DrawAutocomplete ();
10191018
_isDrawing = false;
10201019

10211020
return true;
@@ -1686,6 +1685,8 @@ private void ProcessAutocomplete ()
16861685
}
16871686

16881687
GenerateSuggestions ();
1688+
1689+
DrawAutocomplete ();
16891690
}
16901691

16911692
private void DrawAutocomplete ()

Terminal.Gui/Views/TextInput/TextModel.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,11 @@ void ProcMovePrev (ref int nCol, ref int nRow, Rune nRune)
269269

270270
if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune)))
271271
{
272+
List<Cell> line = GetLine (nRow);
273+
272274
if (lastValidCol > -1)
273275
{
274-
nCol = lastValidCol;
276+
nCol = lastValidCol + Math.Max (lastValidCol, line.Count);
275277
}
276278

277279
return;

Terminal.Gui/Views/TextInput/TextView.cs

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,6 +1715,7 @@ protected override bool OnMouseEvent (MouseEventArgs ev)
17151715
PositionCursor ();
17161716
_lastWasKill = false;
17171717
_columnTrack = CurrentColumn;
1718+
SetNeedsDraw ();
17181719
}
17191720
else if (ev.Flags.HasFlag (MouseFlags.Button1TripleClicked))
17201721
{
@@ -1735,6 +1736,7 @@ protected override bool OnMouseEvent (MouseEventArgs ev)
17351736
PositionCursor ();
17361737
_lastWasKill = false;
17371738
_columnTrack = CurrentColumn;
1739+
SetNeedsDraw ();
17381740
}
17391741
else if (ev.Flags == ContextMenu!.MouseFlags)
17401742
{
@@ -1747,6 +1749,8 @@ protected override bool OnMouseEvent (MouseEventArgs ev)
17471749
//ShowContextMenu ();
17481750
}
17491751

1752+
OnUnwrappedCursorPosition ();
1753+
17501754
return true;
17511755
}
17521756

@@ -1757,7 +1761,7 @@ public void MoveEnd ()
17571761
List<Cell> line = GetCurrentLine ();
17581762
CurrentColumn = line.Count;
17591763
TrackColumn ();
1760-
PositionCursor ();
1764+
DoNeededAction ();
17611765
}
17621766

17631767
/// <summary>Will scroll the <see cref="TextView"/> to the first line and position the cursor there.</summary>
@@ -1768,8 +1772,7 @@ public void MoveHome ()
17681772
CurrentColumn = 0;
17691773
_leftColumn = 0;
17701774
TrackColumn ();
1771-
PositionCursor ();
1772-
SetNeedsDraw ();
1775+
DoNeededAction ();
17731776
}
17741777

17751778
/// <summary>
@@ -2661,13 +2664,19 @@ private bool DeleteTextForwards ()
26612664

26622665
private void DoNeededAction ()
26632666
{
2667+
if (!NeedsDraw && (IsSelecting || _wrapNeeded || !Used))
2668+
{
2669+
SetNeedsDraw ();
2670+
}
2671+
26642672
if (NeedsDraw)
26652673
{
26662674
Adjust ();
26672675
}
26682676
else
26692677
{
26702678
PositionCursor ();
2679+
OnUnwrappedCursorPosition ();
26712680
}
26722681
}
26732682

@@ -3385,8 +3394,24 @@ [ [.. GetCurrentLine ()]],
33853394
}
33863395
else if (newPos.HasValue)
33873396
{
3388-
int restCount = currentLine.Count - CurrentColumn;
3389-
currentLine.RemoveRange (CurrentColumn, restCount);
3397+
int restCount;
3398+
3399+
if (newPos.Value.row == CurrentRow)
3400+
{
3401+
restCount = currentLine.Count - CurrentColumn;
3402+
currentLine.RemoveRange (CurrentColumn, restCount);
3403+
}
3404+
else
3405+
{
3406+
while (CurrentRow != newPos.Value.row)
3407+
{
3408+
restCount = currentLine.Count;
3409+
currentLine.RemoveRange (0, restCount);
3410+
3411+
CurrentRow--;
3412+
currentLine = GetCurrentLine ();
3413+
}
3414+
}
33903415

33913416
if (_wordWrap)
33923417
{
@@ -3540,8 +3565,7 @@ private bool MoveDown ()
35403565
private void MoveEndOfLine ()
35413566
{
35423567
List<Cell> currentLine = GetCurrentLine ();
3543-
CurrentColumn = Math.Max (currentLine.Count - (ReadOnly ? 1 : 0), 0);
3544-
Adjust ();
3568+
CurrentColumn = currentLine.Count;
35453569
DoNeededAction ();
35463570
}
35473571

@@ -3572,7 +3596,6 @@ private bool MoveLeft ()
35723596
}
35733597
}
35743598

3575-
Adjust ();
35763599
DoNeededAction ();
35773600

35783601
return true;
@@ -3654,18 +3677,13 @@ private bool MoveRight ()
36543677
_topRow++;
36553678
SetNeedsDraw ();
36563679
}
3657-
else
3658-
{
3659-
return false;
3660-
}
36613680
}
36623681
else
36633682
{
36643683
return false;
36653684
}
36663685
}
36673686

3668-
Adjust ();
36693687
DoNeededAction ();
36703688

36713689
return true;
@@ -3680,7 +3698,6 @@ private void MoveLeftStart ()
36803698

36813699
CurrentColumn = 0;
36823700
_leftColumn = 0;
3683-
Adjust ();
36843701
DoNeededAction ();
36853702
}
36863703

@@ -3743,7 +3760,6 @@ private void MoveWordBackward ()
37433760
CurrentRow = newPos.Value.row;
37443761
}
37453762

3746-
Adjust ();
37473763
DoNeededAction ();
37483764
}
37493765

@@ -3757,7 +3773,6 @@ private void MoveWordForward ()
37573773
CurrentRow = newPos.Value.row;
37583774
}
37593775

3760-
Adjust ();
37613776
DoNeededAction ();
37623777
}
37633778

@@ -4031,6 +4046,7 @@ private void ProcessKillWordBackward ()
40314046
private void ProcessKillWordForward ()
40324047
{
40334048
ResetColumnTrack ();
4049+
StopSelecting ();
40344050
KillWordForward ();
40354051
}
40364052

@@ -4578,6 +4594,11 @@ private void StartSelecting ()
45784594

45794595
private void StopSelecting ()
45804596
{
4597+
if (IsSelecting)
4598+
{
4599+
SetNeedsDraw ();
4600+
}
4601+
45814602
_shiftSelecting = false;
45824603
IsSelecting = false;
45834604
_isButtonShift = false;

0 commit comments

Comments
 (0)