mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Merge branch 'v2_develop' into v2_3029-MouseEvents
This commit is contained in:
@@ -5,17 +5,17 @@ public static partial class Application // Keyboard handling
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when the user presses a key (by the <see cref="ConsoleDriver"/>). Raises the cancelable
|
||||
/// <see cref="KeyDown"/> event
|
||||
/// then calls <see cref="View.NewKeyDownEvent"/> on all top level views. Called before <see cref="RaiseKeyUpEvent"/>.
|
||||
/// <see cref="KeyDown"/> event, then calls <see cref="View.NewKeyDownEvent"/> on all top level views, and finally
|
||||
/// if the key was not handled, invokes any Application-scoped <see cref="KeyBindings"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Can be used to simulate key press events.</remarks>
|
||||
/// <param name="keyEvent"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns><see langword="true"/> if the key was handled.</returns>
|
||||
public static bool RaiseKeyDownEvent (Key keyEvent)
|
||||
public static bool RaiseKeyDownEvent (Key key)
|
||||
{
|
||||
KeyDown?.Invoke (null, keyEvent);
|
||||
KeyDown?.Invoke (null, key);
|
||||
|
||||
if (keyEvent.Handled)
|
||||
if (key.Handled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public static partial class Application // Keyboard handling
|
||||
{
|
||||
foreach (Toplevel topLevel in TopLevels.ToList ())
|
||||
{
|
||||
if (topLevel.NewKeyDownEvent (keyEvent))
|
||||
if (topLevel.NewKeyDownEvent (key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public static partial class Application // Keyboard handling
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Top.NewKeyDownEvent (keyEvent))
|
||||
if (Top.NewKeyDownEvent (key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -45,7 +45,7 @@ public static partial class Application // Keyboard handling
|
||||
|
||||
// Invoke any Application-scoped KeyBindings.
|
||||
// The first view that handles the key will stop the loop.
|
||||
foreach (KeyValuePair<Key, KeyBinding> binding in KeyBindings.Bindings.Where (b => b.Key == keyEvent.KeyCode))
|
||||
foreach (KeyValuePair<Key, KeyBinding> binding in KeyBindings.Bindings.Where (b => b.Key == key.KeyCode))
|
||||
{
|
||||
if (binding.Value.BoundView is { })
|
||||
{
|
||||
@@ -58,7 +58,7 @@ public static partial class Application // Keyboard handling
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!KeyBindings.TryGet (keyEvent, KeyBindingScope.Application, out KeyBinding appBinding))
|
||||
if (!KeyBindings.TryGet (key, KeyBindingScope.Application, out KeyBinding appBinding))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public static partial class Application // Keyboard handling
|
||||
|
||||
foreach (Command command in appBinding.Commands)
|
||||
{
|
||||
toReturn = InvokeCommand (command, keyEvent, appBinding);
|
||||
toReturn = InvokeCommand (command, key, appBinding);
|
||||
}
|
||||
|
||||
return toReturn ?? true;
|
||||
@@ -76,18 +76,18 @@ public static partial class Application // Keyboard handling
|
||||
|
||||
return false;
|
||||
|
||||
static bool? InvokeCommand (Command command, Key keyEvent, KeyBinding appBinding)
|
||||
static bool? InvokeCommand (Command command, Key key, KeyBinding appBinding)
|
||||
{
|
||||
if (!CommandImplementations!.ContainsKey (command))
|
||||
{
|
||||
throw new NotSupportedException (
|
||||
@$"A KeyBinding was set up for the command {command} ({keyEvent}) but that command is not supported by Application."
|
||||
@$"A KeyBinding was set up for the command {command} ({key}) but that command is not supported by Application."
|
||||
);
|
||||
}
|
||||
|
||||
if (CommandImplementations.TryGetValue (command, out View.CommandImplementation? implementation))
|
||||
{
|
||||
var context = new CommandContext (command, keyEvent, appBinding); // Create the context here
|
||||
var context = new CommandContext (command, key, appBinding); // Create the context here
|
||||
|
||||
return implementation (context);
|
||||
}
|
||||
@@ -116,25 +116,25 @@ public static partial class Application // Keyboard handling
|
||||
/// then calls <see cref="View.NewKeyUpEvent"/> on all top level views. Called after <see cref="RaiseKeyDownEvent"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Can be used to simulate key release events.</remarks>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns><see langword="true"/> if the key was handled.</returns>
|
||||
public static bool RaiseKeyUpEvent (Key a)
|
||||
public static bool RaiseKeyUpEvent (Key key)
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
KeyUp?.Invoke (null, a);
|
||||
KeyUp?.Invoke (null, key);
|
||||
|
||||
if (a.Handled)
|
||||
if (key.Handled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (Toplevel topLevel in TopLevels.ToList ())
|
||||
{
|
||||
if (topLevel.NewKeyUpEvent (a))
|
||||
if (topLevel.NewKeyUpEvent (key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
// TODO: Nuke when #2975 is completed
|
||||
/// <summary>Represents a helper to manipulate shortcut keys used on views.</summary>
|
||||
public class ShortcutHelper
|
||||
{
|
||||
// TODO: Update this to use Key, not KeyCode
|
||||
private KeyCode shortcut;
|
||||
|
||||
/// <summary>This is the global setting that can be used as a global shortcut to invoke the action on the view.</summary>
|
||||
public virtual KeyCode Shortcut
|
||||
{
|
||||
get => shortcut;
|
||||
set
|
||||
{
|
||||
if (shortcut != value && (PostShortcutValidation (value) || value is KeyCode.Null))
|
||||
{
|
||||
shortcut = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The keystroke combination used in the <see cref="Shortcut"/> as string.</summary>
|
||||
public virtual string ShortcutTag => Key.ToString (shortcut, Key.Separator);
|
||||
|
||||
/// <summary>Lookup for a <see cref="KeyCode"/> on range of keys.</summary>
|
||||
/// <param name="key">The source key.</param>
|
||||
/// <param name="first">First key in range.</param>
|
||||
/// <param name="last">Last key in range.</param>
|
||||
public static bool CheckKeysFlagRange (KeyCode key, KeyCode first, KeyCode last)
|
||||
{
|
||||
for (var i = (uint)first; i < (uint)last; i++)
|
||||
{
|
||||
if ((key | (KeyCode)i) == key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>Allows to retrieve a <see cref="KeyCode"/> from a <see cref="ShortcutTag"/></summary>
|
||||
/// <param name="tag">The key as string.</param>
|
||||
/// <param name="delimiter">The delimiter string.</param>
|
||||
public static KeyCode GetShortcutFromTag (string tag, Rune delimiter = default)
|
||||
{
|
||||
string sCut = tag;
|
||||
|
||||
if (string.IsNullOrEmpty (sCut))
|
||||
{
|
||||
return default (KeyCode);
|
||||
}
|
||||
|
||||
var key = KeyCode.Null;
|
||||
|
||||
//var hasCtrl = false;
|
||||
if (delimiter == default (Rune))
|
||||
{
|
||||
delimiter = Key.Separator;
|
||||
}
|
||||
|
||||
string [] keys = sCut.Split (delimiter.ToString ());
|
||||
|
||||
for (var i = 0; i < keys.Length; i++)
|
||||
{
|
||||
string k = keys [i];
|
||||
|
||||
if (k == "Ctrl")
|
||||
{
|
||||
//hasCtrl = true;
|
||||
key |= KeyCode.CtrlMask;
|
||||
}
|
||||
else if (k == "Shift")
|
||||
{
|
||||
key |= KeyCode.ShiftMask;
|
||||
}
|
||||
else if (k == "Alt")
|
||||
{
|
||||
key |= KeyCode.AltMask;
|
||||
}
|
||||
else if (k.StartsWith ("F") && k.Length > 1)
|
||||
{
|
||||
int.TryParse (k.Substring (1), out int n);
|
||||
|
||||
for (var j = (uint)KeyCode.F1; j <= (uint)KeyCode.F12; j++)
|
||||
{
|
||||
int.TryParse (((KeyCode)j).ToString ().Substring (1), out int f);
|
||||
|
||||
if (f == n)
|
||||
{
|
||||
key |= (KeyCode)j;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
key |= (KeyCode)Enum.Parse (typeof (KeyCode), k);
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/// <summary>Used at key up validation.</summary>
|
||||
/// <param name="key">The key to validate.</param>
|
||||
/// <returns><c>true</c> if is valid.<c>false</c>otherwise.</returns>
|
||||
public static bool PostShortcutValidation (KeyCode key)
|
||||
{
|
||||
GetKeyToString (key, out KeyCode knm);
|
||||
|
||||
if (CheckKeysFlagRange (key, KeyCode.F1, KeyCode.F12) || ((key & (KeyCode.CtrlMask | KeyCode.ShiftMask | KeyCode.AltMask)) != 0 && knm != KeyCode.Null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>Used at key down or key press validation.</summary>
|
||||
/// <param name="key">The key to validate.</param>
|
||||
/// <returns><c>true</c> if is valid.<c>false</c>otherwise.</returns>
|
||||
public static bool PreShortcutValidation (KeyCode key)
|
||||
{
|
||||
if ((key & (KeyCode.CtrlMask | KeyCode.ShiftMask | KeyCode.AltMask)) == 0
|
||||
&& !CheckKeysFlagRange (key, KeyCode.F1, KeyCode.F12))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Return key as string.</summary>
|
||||
/// <param name="key">The key to extract.</param>
|
||||
/// <param name="knm">Correspond to the non modifier key.</param>
|
||||
private static string GetKeyToString (KeyCode key, out KeyCode knm)
|
||||
{
|
||||
if (key == KeyCode.Null)
|
||||
{
|
||||
knm = KeyCode.Null;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
knm = key;
|
||||
KeyCode mK = key & (KeyCode.AltMask | KeyCode.CtrlMask | KeyCode.ShiftMask);
|
||||
knm &= ~mK;
|
||||
|
||||
for (var i = (uint)KeyCode.F1; i < (uint)KeyCode.F12; i++)
|
||||
{
|
||||
if (knm == (KeyCode)i)
|
||||
{
|
||||
mK |= (KeyCode)i;
|
||||
}
|
||||
}
|
||||
|
||||
knm &= ~mK;
|
||||
uint.TryParse (knm.ToString (), out uint c);
|
||||
string s = mK == KeyCode.Null ? "" : mK.ToString ();
|
||||
|
||||
if (s != "" && (knm != KeyCode.Null || c > 0))
|
||||
{
|
||||
s += ",";
|
||||
}
|
||||
|
||||
s += c == 0 ? knm == KeyCode.Null ? "" : knm.ToString () : ((char)c).ToString ();
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -297,7 +297,6 @@ public partial class View // Keyboard APIs
|
||||
}
|
||||
|
||||
// After
|
||||
// TODO: Is ProcessKeyDown really the right name?
|
||||
if (RaiseKeyDownNotHandled (key) || key.Handled)
|
||||
{
|
||||
return true;
|
||||
@@ -426,7 +425,7 @@ public partial class View // Keyboard APIs
|
||||
/// <para>
|
||||
/// If the focused sub view does not handle the key press, this method raises <see cref="OnKeyUp"/>/
|
||||
/// <see cref="KeyUp"/> to allow the
|
||||
/// view to pre-process the key press. If <see cref="OnKeyUp"/>/<see cref="KeyUp"/>.
|
||||
/// view to pre-process the key press.
|
||||
/// </para>
|
||||
/// <para>See <see href="../docs/keyboard.md">for an overview of Terminal.Gui keyboard APIs.</see></para>
|
||||
/// </remarks>
|
||||
|
||||
@@ -670,11 +670,11 @@ public class FileDialog : Dialog
|
||||
FinishAccept ();
|
||||
}
|
||||
|
||||
private void AcceptIf (Key keyEvent, KeyCode isKey)
|
||||
private void AcceptIf (Key key, KeyCode isKey)
|
||||
{
|
||||
if (!keyEvent.Handled && keyEvent.KeyCode == isKey)
|
||||
if (!key.Handled && key.KeyCode == isKey)
|
||||
{
|
||||
keyEvent.Handled = true;
|
||||
key.Handled = true;
|
||||
|
||||
// User hit Enter in text box so probably wants the
|
||||
// contents of the text box as their selection not
|
||||
|
||||
@@ -817,7 +817,6 @@ public class ListView : View, IDesignable
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should be cancelable
|
||||
/// <summary>Invokes the <see cref="OpenSelectedItem"/> event if it is defined.</summary>
|
||||
/// <returns><see langword="true"/> if the <see cref="OpenSelectedItem"/> event was fired.</returns>
|
||||
public bool OnOpenSelectedItem ()
|
||||
|
||||
@@ -1563,7 +1563,7 @@ public class TableView : View
|
||||
/// <returns></returns>
|
||||
private TableSelection CreateTableSelection (int x, int y) { return CreateTableSelection (x, y, x, y); }
|
||||
|
||||
private bool CycleToNextTableEntryBeginningWith (Key keyEvent)
|
||||
private bool CycleToNextTableEntryBeginningWith (Key key)
|
||||
{
|
||||
int row = SelectedRow;
|
||||
|
||||
@@ -1573,7 +1573,7 @@ public class TableView : View
|
||||
return false;
|
||||
}
|
||||
|
||||
int match = CollectionNavigator.GetNextMatchingItem (row, (char)keyEvent);
|
||||
int match = CollectionNavigator.GetNextMatchingItem (row, (char)key);
|
||||
|
||||
if (match != -1)
|
||||
{
|
||||
|
||||
@@ -286,11 +286,11 @@ public class TileView : View
|
||||
|
||||
//// BUGBUG: Why is this not handled by a key binding???
|
||||
/// <inheritdoc/>
|
||||
protected override bool OnKeyDownNotHandled (Key keyEvent)
|
||||
protected override bool OnKeyDownNotHandled (Key key)
|
||||
{
|
||||
var focusMoved = false;
|
||||
|
||||
if (keyEvent.KeyCode == ToggleResizable)
|
||||
if (key.KeyCode == ToggleResizable)
|
||||
{
|
||||
foreach (TileViewLineView l in _splitterLines)
|
||||
{
|
||||
|
||||
@@ -1182,7 +1182,7 @@ public class TreeView<T> : View, ITreeView where T : class
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool OnKeyDown (Key keyEvent)
|
||||
protected override bool OnKeyDown (Key key)
|
||||
{
|
||||
if (!Enabled)
|
||||
{
|
||||
@@ -1190,7 +1190,7 @@ public class TreeView<T> : View, ITreeView where T : class
|
||||
}
|
||||
|
||||
// If not a keybinding, is the key a searchable key press?
|
||||
if (CollectionNavigatorBase.IsCompatibleKey (keyEvent) && AllowLetterBasedNavigation)
|
||||
if (CollectionNavigatorBase.IsCompatibleKey (key) && AllowLetterBasedNavigation)
|
||||
{
|
||||
// If there has been a call to InvalidateMap since the last time
|
||||
// we need a new one to reflect the new exposed tree state
|
||||
@@ -1198,7 +1198,7 @@ public class TreeView<T> : View, ITreeView where T : class
|
||||
|
||||
// Find the current selected object within the tree
|
||||
int current = map.IndexOf (b => b.Model == SelectedObject);
|
||||
int? newIndex = KeystrokeNavigator?.GetNextMatchingItem (current, (char)keyEvent);
|
||||
int? newIndex = KeystrokeNavigator?.GetNextMatchingItem (current, (char)key);
|
||||
|
||||
if (newIndex is int && newIndex != -1)
|
||||
{
|
||||
|
||||
@@ -76,18 +76,18 @@ public class Keys : Scenario
|
||||
win.Add (label);
|
||||
int maxKeyString = Key.CursorRight.WithAlt.WithCtrl.WithShift.ToString ().Length;
|
||||
|
||||
ObservableCollection<string> keyEventList = new ();
|
||||
ObservableCollection<string> keyList = new ();
|
||||
|
||||
var appKeyEventListView = new ListView
|
||||
var appKeyListView = new ListView
|
||||
{
|
||||
X = 0,
|
||||
Y = Pos.Bottom (label),
|
||||
Width = "KeyDown:".Length + maxKeyString,
|
||||
Height = Dim.Fill (),
|
||||
Source = new ListWrapper<string> (keyEventList)
|
||||
Source = new ListWrapper<string> (keyList)
|
||||
};
|
||||
appKeyEventListView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
|
||||
win.Add (appKeyEventListView);
|
||||
appKeyListView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
|
||||
win.Add (appKeyListView);
|
||||
|
||||
// View key events...
|
||||
edit.KeyDown += (s, a) => { keyDownList.Add (a.ToString ()); };
|
||||
@@ -100,7 +100,7 @@ public class Keys : Scenario
|
||||
// KeyDown
|
||||
label = new Label
|
||||
{
|
||||
X = Pos.Right (appKeyEventListView) + 1,
|
||||
X = Pos.Right (appKeyListView) + 1,
|
||||
Y = Pos.Top (label),
|
||||
Text = "TextView Key Down:"
|
||||
};
|
||||
@@ -142,10 +142,9 @@ public class Keys : Scenario
|
||||
|
||||
void KeyDownPressUp (Key args, string updown)
|
||||
{
|
||||
// BUGBUG: KeyEvent.ToString is badly broken
|
||||
var msg = $"Key{updown,-7}: {args}";
|
||||
keyEventList.Add (msg);
|
||||
appKeyEventListView.MoveDown ();
|
||||
keyList.Add (msg);
|
||||
appKeyListView.MoveDown ();
|
||||
onKeyDownNotHandledListView.MoveDown ();
|
||||
}
|
||||
|
||||
|
||||
@@ -357,30 +357,30 @@ public class Snake : Scenario
|
||||
}
|
||||
|
||||
// BUGBUG: Should (can) this use key bindings instead.
|
||||
protected override bool OnKeyDown (Key keyEvent)
|
||||
protected override bool OnKeyDown (Key key)
|
||||
{
|
||||
if (keyEvent.KeyCode == KeyCode.CursorUp)
|
||||
if (key.KeyCode == KeyCode.CursorUp)
|
||||
{
|
||||
State.PlannedDirection = Direction.Up;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyEvent.KeyCode == KeyCode.CursorDown)
|
||||
if (key.KeyCode == KeyCode.CursorDown)
|
||||
{
|
||||
State.PlannedDirection = Direction.Down;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyEvent.KeyCode == KeyCode.CursorLeft)
|
||||
if (key.KeyCode == KeyCode.CursorLeft)
|
||||
{
|
||||
State.PlannedDirection = Direction.Left;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyEvent.KeyCode == KeyCode.CursorRight)
|
||||
if (key.KeyCode == KeyCode.CursorRight)
|
||||
{
|
||||
State.PlannedDirection = Direction.Right;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user