diff --git a/Terminal.Gui/Core/ShortCutHelper.cs b/Terminal.Gui/Core/ShortCutHelper.cs
index 3c3abd8eb..3bb8c9931 100644
--- a/Terminal.Gui/Core/ShortCutHelper.cs
+++ b/Terminal.Gui/Core/ShortCutHelper.cs
@@ -29,6 +29,32 @@ namespace Terminal.Gui {
///
public virtual ustring ShortCutTag => GetShortCutTag (shortCut);
+ ///
+ /// The action to run if the is defined.
+ ///
+ public virtual Action ShortCutAction { get; set; }
+
+ ///
+ /// Gets the key with all the keys modifiers, especially the shift key that sometimes have to be injected later.
+ ///
+ /// The to check.
+ /// The with all the keys modifiers.
+ public static Key GetModifiersKey (KeyEvent kb)
+ {
+ var key = kb.Key;
+ if (kb.IsAlt && (key & Key.AltMask) == 0) {
+ key |= Key.AltMask;
+ }
+ if (kb.IsCtrl && (key & Key.CtrlMask) == 0) {
+ key |= Key.CtrlMask;
+ }
+ if (kb.IsShift && (key & Key.ShiftMask) == 0) {
+ key |= Key.ShiftMask;
+ }
+
+ return key;
+ }
+
///
/// Get the key as string.
///
@@ -202,5 +228,38 @@ namespace Terminal.Gui {
}
return false;
}
+
+ ///
+ /// Allows a view to run a if defined.
+ ///
+ /// The
+ /// The
+ /// true if defined falseotherwise.
+ public static bool FindAndOpenByShortCut (KeyEvent kb, View view = null)
+ {
+ if (view == null) {
+ return false; }
+
+ var key = kb.KeyValue;
+ var keys = GetModifiersKey (kb);
+ key |= (int)keys;
+ foreach (var v in view.Subviews) {
+ if (v.ShortCut != Key.Null && v.ShortCut == (Key)key) {
+ var action = v.ShortCutAction;
+ if (action != null) {
+ Application.MainLoop.AddIdle (() => {
+ action ();
+ return false;
+ });
+ }
+ return true;
+ }
+ if (FindAndOpenByShortCut (kb, v)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
}
diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs
index 1d5dc207f..f6594e7fa 100644
--- a/Terminal.Gui/Core/Toplevel.cs
+++ b/Terminal.Gui/Core/Toplevel.cs
@@ -213,6 +213,19 @@ namespace Terminal.Gui {
return false;
}
+ ///
+ public override bool ProcessColdKey (KeyEvent keyEvent)
+ {
+ if (base.ProcessColdKey (keyEvent)) {
+ return true;
+ }
+
+ if (ShortCutHelper.FindAndOpenByShortCut(keyEvent, this)) {
+ return true;
+ }
+ return false;
+ }
+
View GetDeepestFocusedSubview (View view)
{
if (view == null) {
diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs
index 97d8d4df8..0417b2c04 100644
--- a/Terminal.Gui/Core/View.cs
+++ b/Terminal.Gui/Core/View.cs
@@ -125,6 +125,8 @@ namespace Terminal.Gui {
TextFormatter textFormatter;
+ ShortCutHelper shortCutHelper;
+
///
/// Event fired when a subview is being added to this view.
///
@@ -170,6 +172,28 @@ namespace Terminal.Gui {
///
public Rune HotKeySpecifier { get => textFormatter.HotKeySpecifier; set => textFormatter.HotKeySpecifier = value; }
+ ///
+ /// This is the global setting that can be used as a global shortcut to invoke an action if provided.
+ ///
+ public Key ShortCut {
+ get => shortCutHelper.ShortCut;
+ set {
+ if (shortCutHelper.ShortCut != value && (ShortCutHelper.PostShortCutValidation (value) || value == Key.Null)) {
+ shortCutHelper.ShortCut = value;
+ }
+ }
+ }
+
+ ///
+ /// The keystroke combination used in the as string.
+ ///
+ public ustring ShortCutTag => ShortCutHelper.GetShortCutTag (shortCutHelper.ShortCut);
+
+ ///
+ /// The action to run if the is defined.
+ ///
+ public virtual Action ShortCutAction { get; set; }
+
///
/// Gets or sets arbitrary data for the view.
///
@@ -550,6 +574,8 @@ namespace Terminal.Gui {
textFormatter = new TextFormatter ();
this.Text = ustring.Empty;
+ shortCutHelper = new ShortCutHelper ();
+
this.Frame = frame;
LayoutStyle = LayoutStyle.Absolute;
}
@@ -612,6 +638,8 @@ namespace Terminal.Gui {
{
textFormatter = new TextFormatter ();
this.Text = text;
+
+ shortCutHelper = new ShortCutHelper ();
}
///
@@ -633,6 +661,8 @@ namespace Terminal.Gui {
textFormatter = new TextFormatter ();
this.Text = text;
+ shortCutHelper = new ShortCutHelper ();
+
CanFocus = false;
TabIndex = -1;
TabStop = false;
@@ -2055,26 +2085,5 @@ namespace Terminal.Gui {
return true;
}
-
- ///
- /// Gets the key with all the keys modifiers, especially the shift key that sometimes have to be injected later.
- ///
- /// The to check.
- /// The with all the keys modifiers.
- public Key GetModifiersKey (KeyEvent kb)
- {
- var key = kb.Key;
- if (kb.IsAlt && (key & Key.AltMask) == 0) {
- key |= Key.AltMask;
- }
- if (kb.IsCtrl && (key & Key.CtrlMask) == 0) {
- key |= Key.CtrlMask;
- }
- if (kb.IsShift && (key & Key.ShiftMask) == 0) {
- key |= Key.ShiftMask;
- }
-
- return key;
- }
}
}
diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs
index b6bfcb353..7bcde1e55 100644
--- a/Terminal.Gui/Views/Menu.cs
+++ b/Terminal.Gui/Views/Menu.cs
@@ -1328,14 +1328,8 @@ namespace Terminal.Gui {
}
var key = kb.KeyValue;
- var keys = GetModifiersKey (kb);
+ var keys = ShortCutHelper.GetModifiersKey (kb);
key |= (int)keys;
- //if (kb.IsShift) {
- // key |= (int)Key.ShiftMask;
- //}
- //if (kb.IsAlt) {
- // key |= unchecked((int)Key.AltMask);
- //}
for (int i = 0; i < children.Length; i++) {
var mi = children [i];
if (mi == null) {
diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs
index 9f084a919..f0d6645ef 100644
--- a/Terminal.Gui/Views/TextField.cs
+++ b/Terminal.Gui/Views/TextField.cs
@@ -345,7 +345,7 @@ namespace Terminal.Gui {
// Needed for the Elmish Wrapper issue https://github.com/DieselMeister/Terminal.Gui.Elmish/issues/2
var oldCursorPos = point;
- switch (GetModifiersKey (kb)) {
+ switch (ShortCutHelper.GetModifiersKey (kb)) {
case Key.DeleteChar:
case Key.D | Key.CtrlMask:
if (ReadOnly)
diff --git a/UICatalog/Scenarios/DynamicMenuBar.cs b/UICatalog/Scenarios/DynamicMenuBar.cs
index 3c8d433da..96c45225f 100644
--- a/UICatalog/Scenarios/DynamicMenuBar.cs
+++ b/UICatalog/Scenarios/DynamicMenuBar.cs
@@ -725,7 +725,7 @@ namespace UICatalog {
return;
}
- var k = GetModifiersKey (e.KeyEvent);
+ var k = ShortCutHelper.GetModifiersKey (e.KeyEvent);
if (CheckShortCut (k, true)) {
e.Handled = true;
}
@@ -764,7 +764,7 @@ namespace UICatalog {
}
_txtShortCut.KeyUp += (e) => {
- var k = GetModifiersKey (e.KeyEvent);
+ var k = ShortCutHelper.GetModifiersKey (e.KeyEvent);
if (CheckShortCut (k, false)) {
e.Handled = true;
}
diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs
index 288d1331c..e5c4a8f98 100644
--- a/UICatalog/UICatalog.cs
+++ b/UICatalog/UICatalog.cs
@@ -105,7 +105,7 @@ namespace UICatalog {
_rightPane.SetFocus ();
_top.Ready -= ReadyHandler;
}
-
+
_top.Ready += ReadyHandler;
#if DEBUG_IDISPOSABLE
@@ -114,7 +114,7 @@ namespace UICatalog {
foreach (var inst in Responder.Instances) {
Debug.Assert (inst.WasDisposed);
}
- Responder.Instances.Clear();
+ Responder.Instances.Clear ();
#endif
}
@@ -174,8 +174,10 @@ namespace UICatalog {
Width = 25,
Height = Dim.Fill (1),
CanFocus = false,
+ ShortCut = Key.CtrlMask | Key.C
};
-
+ _leftPane.Title = $"{_leftPane.Title} ({_leftPane.ShortCutTag})";
+ _leftPane.ShortCutAction = () => _leftPane.SetFocus ();
_categories = Scenario.GetAllCategories ().OrderBy (c => c).ToList ();
_categoryListView = new ListView (_categories) {
@@ -198,8 +200,10 @@ namespace UICatalog {
Width = Dim.Fill (),
Height = Dim.Fill (1),
CanFocus = true,
-
+ ShortCut = Key.CtrlMask | Key.S
};
+ _rightPane.Title = $"{_rightPane.Title} ({_rightPane.ShortCutTag})";
+ _rightPane.ShortCutAction = () => _rightPane.SetFocus ();
_nameColumnWidth = Scenario.ScenarioMetadata.GetName (_scenarios.OrderByDescending (t => Scenario.ScenarioMetadata.GetName (t).Length).FirstOrDefault ()).Length;
@@ -222,7 +226,7 @@ namespace UICatalog {
_numlock = new StatusItem (Key.CharMask, "Num", null);
_scrolllock = new StatusItem (Key.CharMask, "Scroll", null);
- _statusBar = new StatusBar () {
+ _statusBar = new StatusBar () {
Visible = true,
};
_statusBar.Items = new StatusItem [] {