ShortCutHelper.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. using NStack;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace Terminal.Gui {
  8. /// <summary>
  9. /// Represents a helper to manipulate shortcut keys used on views.
  10. /// </summary>
  11. public class ShortCutHelper {
  12. private Key shortCut;
  13. /// <summary>
  14. /// This is the global setting that can be used as a global shortcut to invoke the action on the view.
  15. /// </summary>
  16. public virtual Key ShortCut {
  17. get => shortCut;
  18. set {
  19. if (shortCut != value && (PostShortCutValidation (value) || value == Key.Null)) {
  20. shortCut = value;
  21. }
  22. }
  23. }
  24. /// <summary>
  25. /// The keystroke combination used in the <see cref="ShortCut"/> as string.
  26. /// </summary>
  27. public virtual ustring ShortCutTag => GetShortCutTag (shortCut);
  28. /// <summary>
  29. /// Get the <see cref="ShortCut"/> key as string.
  30. /// </summary>
  31. /// <param name="shortCut">The shortcut key.</param>
  32. /// <returns></returns>
  33. public static ustring GetShortCutTag (Key shortCut)
  34. {
  35. if (shortCut == Key.Null) {
  36. return "";
  37. }
  38. var k = shortCut;
  39. var delimiter = MenuBar.ShortCutDelimiter;
  40. ustring tag = ustring.Empty;
  41. var sCut = GetKeyToString (k, out Key knm).ToString ();
  42. if (knm == Key.Unknown) {
  43. k &= ~Key.Unknown;
  44. sCut = GetKeyToString (k, out _).ToString ();
  45. }
  46. if ((k & Key.CtrlMask) != 0) {
  47. tag = "Ctrl";
  48. }
  49. if ((k & Key.ShiftMask) != 0) {
  50. if (!tag.IsEmpty) {
  51. tag += delimiter;
  52. }
  53. tag += "Shift";
  54. }
  55. if ((k & Key.AltMask) != 0) {
  56. if (!tag.IsEmpty) {
  57. tag += delimiter;
  58. }
  59. tag += "Alt";
  60. }
  61. ustring [] keys = ustring.Make (sCut).Split (",");
  62. for (int i = 0; i < keys.Length; i++) {
  63. var key = keys [i].TrimSpace ();
  64. if (key == Key.AltMask.ToString () || key == Key.ShiftMask.ToString () || key == Key.CtrlMask.ToString ()) {
  65. continue;
  66. }
  67. if (!tag.IsEmpty) {
  68. tag += delimiter;
  69. }
  70. if (!key.Contains ("F") && key.Length > 2 && keys.Length == 1) {
  71. k = (uint)Key.AltMask + k;
  72. tag += ((char)k).ToString ();
  73. } else if (key.Length == 2 && key.StartsWith ("D")) {
  74. tag += ((char)key.ElementAt (1)).ToString ();
  75. } else {
  76. tag += key;
  77. }
  78. }
  79. return tag;
  80. }
  81. /// <summary>
  82. /// Return key as string.
  83. /// </summary>
  84. /// <param name="key">The key to extract.</param>
  85. /// <param name="knm">Correspond to the non modifier key.</param>
  86. public static ustring GetKeyToString (Key key, out Key knm)
  87. {
  88. if (key == Key.Null) {
  89. knm = Key.Null;
  90. return "";
  91. }
  92. knm = key;
  93. var mK = key & (Key.AltMask | Key.CtrlMask | Key.ShiftMask);
  94. knm &= ~mK;
  95. for (uint i = (uint)Key.F1; i < (uint)Key.F12; i++) {
  96. if (knm == (Key)i) {
  97. mK |= (Key)i;
  98. }
  99. }
  100. knm &= ~mK;
  101. uint.TryParse (knm.ToString (), out uint c);
  102. var s = mK == Key.Null ? "" : mK.ToString ();
  103. if (s != "" && (knm != Key.Null || c > 0)) {
  104. s += ",";
  105. }
  106. s += c == 0 ? knm == Key.Null ? "" : knm.ToString () : ((char)c).ToString ();
  107. return s;
  108. }
  109. /// <summary>
  110. /// Allows to retrieve a <see cref="Key"/> from a <see cref="ShortCutTag"/>
  111. /// </summary>
  112. /// <param name="tag">The key as string.</param>
  113. public static Key GetShortCutFromTag (ustring tag)
  114. {
  115. var sCut = tag;
  116. if (sCut.IsEmpty) {
  117. return default;
  118. }
  119. Key key = Key.Null;
  120. //var hasCtrl = false;
  121. var delimiter = MenuBar.ShortCutDelimiter;
  122. ustring [] keys = sCut.Split (delimiter);
  123. for (int i = 0; i < keys.Length; i++) {
  124. var k = keys [i];
  125. if (k == "Ctrl") {
  126. //hasCtrl = true;
  127. key |= Key.CtrlMask;
  128. } else if (k == "Shift") {
  129. key |= Key.ShiftMask;
  130. } else if (k == "Alt") {
  131. key |= Key.AltMask;
  132. } else if (k.StartsWith ("F") && k.Length > 1) {
  133. int.TryParse (k.Substring (1).ToString (), out int n);
  134. for (uint j = (uint)Key.F1; j <= (uint)Key.F12; j++) {
  135. int.TryParse (((Key)j).ToString ().Substring (1), out int f);
  136. if (f == n) {
  137. key |= (Key)j;
  138. }
  139. }
  140. } else {
  141. key |= (Key)Enum.Parse (typeof (Key), k.ToString ());
  142. }
  143. }
  144. return key;
  145. }
  146. /// <summary>
  147. /// Lookup for a <see cref="Key"/> on range of keys.
  148. /// </summary>
  149. /// <param name="key">The source key.</param>
  150. /// <param name="first">First key in range.</param>
  151. /// <param name="last">Last key in range.</param>
  152. public static bool CheckKeysFlagRange (Key key, Key first, Key last)
  153. {
  154. for (uint i = (uint)first; i < (uint)last; i++) {
  155. if ((key | (Key)i) == key) {
  156. return true;
  157. }
  158. }
  159. return false;
  160. }
  161. /// <summary>
  162. /// Used at key down or key press validation.
  163. /// </summary>
  164. /// <param name="key">The key to validate.</param>
  165. /// <returns><c>true</c> if is valid.<c>false</c>otherwise.</returns>
  166. public static bool PreShortCutValidation (Key key)
  167. {
  168. if ((key & (Key.CtrlMask | Key.ShiftMask | Key.AltMask)) == 0 && !CheckKeysFlagRange (key, Key.F1, Key.F12)) {
  169. return false;
  170. }
  171. return true;
  172. }
  173. /// <summary>
  174. /// Used at key up validation.
  175. /// </summary>
  176. /// <param name="key">The key to validate.</param>
  177. /// <returns><c>true</c> if is valid.<c>false</c>otherwise.</returns>
  178. public static bool PostShortCutValidation (Key key)
  179. {
  180. GetKeyToString (key, out Key knm);
  181. if (CheckKeysFlagRange (key, Key.F1, Key.F12) ||
  182. ((key & (Key.CtrlMask | Key.ShiftMask | Key.AltMask)) != 0 && knm != Key.Null && knm != Key.Unknown)) {
  183. return true;
  184. }
  185. return false;
  186. }
  187. }
  188. }