Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

vor 8 Monaten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. // This code is distributed under MIT license.
  2. // Copyright (c) 2015 George Mamaladze
  3. // See license.txt or https://mit-license.org/
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Windows.Forms;
  7. using Gma.System.MouseKeyHook.Implementation;
  8. namespace Gma.System.MouseKeyHook.HotKeys
  9. {
  10. /// <summary>
  11. /// An immutable set of Hot Keys that provides an event for when the set is activated.
  12. /// </summary>
  13. public class HotKeySet
  14. {
  15. /// <summary>
  16. /// A delegate representing the signature for the OnHotKeysDownHold event
  17. /// </summary>
  18. /// <param name="sender"></param>
  19. /// <param name="e"></param>
  20. public delegate void HotKeyHandler(object sender, HotKeyArgs e);
  21. private readonly Dictionary<Keys, bool> m_hotkeystate; //Keeps track of the status of the set of Keys
  22. /*
  23. * Example of m_remapping:
  24. * a single key from the set of Keys requested is chosen to be the reference key (aka primary key)
  25. *
  26. * m_remapping[ Keys.LShiftKey ] = Keys.LShiftKey
  27. * m_remapping[ Keys.RShiftKey ] = Keys.LShiftKey
  28. *
  29. * This allows the m_hotkeystate to use a single key (primary key) from the set that will act on behalf of all the keys in the set,
  30. * which in turn reduces to this:
  31. *
  32. * Keys k = Keys.RShiftKey
  33. * Keys primaryKey = PrimaryKeyOf( k ) = Keys.LShiftKey
  34. * m_hotkeystate[ primaryKey ] = true/false
  35. */
  36. private readonly Dictionary<Keys, Keys> m_remapping; //Used for mapping multiple keys to a single key
  37. private bool m_enabled = true; //enabled by default
  38. //These provide the actual status of whether a set is truly activated or not.
  39. private int m_hotkeydowncount; //number of hot keys down
  40. private int m_remappingCount;
  41. //the number of remappings, i.e., a set of mappings, not the individual count in m_remapping
  42. /// <summary>
  43. /// Creates an instance of the HotKeySet class. Once created, the keys cannot be changed.
  44. /// </summary>
  45. /// <param name="hotkeys">Set of Hot Keys</param>
  46. public HotKeySet(IEnumerable<Keys> hotkeys)
  47. {
  48. m_hotkeystate = new Dictionary<Keys, bool>();
  49. m_remapping = new Dictionary<Keys, Keys>();
  50. HotKeys = hotkeys;
  51. InitializeKeys();
  52. }
  53. /// <summary>
  54. /// Enables the ability to name the set
  55. /// </summary>
  56. public string Name { get; set; }
  57. /// <summary>
  58. /// Enables the ability to describe what the set is used for or supposed to do
  59. /// </summary>
  60. public string Description { get; set; }
  61. /// <summary>
  62. /// Gets the set of hotkeys that this class handles.
  63. /// </summary>
  64. public IEnumerable<Keys> HotKeys { get; }
  65. /// <summary>
  66. /// Returns whether the set of Keys is activated
  67. /// </summary>
  68. public bool HotKeysActivated
  69. {
  70. get { return m_hotkeydowncount == m_hotkeystate.Count - m_remappingCount; }
  71. }
  72. /// <summary>
  73. /// Gets or sets the enabled state of the HotKey set.
  74. /// </summary>
  75. public bool Enabled
  76. {
  77. get { return m_enabled; }
  78. set
  79. {
  80. if (value)
  81. InitializeKeys(); //must get the actual current state of each key to update
  82. m_enabled = value;
  83. }
  84. }
  85. /// <summary>
  86. /// Called as the user holds down the keys in the set. It is NOT triggered the first time the keys are set.
  87. /// <see cref="OnHotKeysDownOnce" />
  88. /// </summary>
  89. public event HotKeyHandler OnHotKeysDownHold;
  90. /// <summary>
  91. /// Called whenever the hot key set is no longer active. This is essentially a KeyPress event, indicating that a full
  92. /// key cycle has occurred, only for HotKeys because a single key removed from the set constitutes an incomplete set.
  93. /// </summary>
  94. public event HotKeyHandler OnHotKeysUp;
  95. /// <summary>
  96. /// Called the first time the down keys are set. It does not get called throughout the duration the user holds it but
  97. /// only the
  98. /// first time it's activated.
  99. /// </summary>
  100. public event HotKeyHandler OnHotKeysDownOnce;
  101. /// <summary>
  102. /// General invocation handler
  103. /// </summary>
  104. /// <param name="hotKeyDelegate"></param>
  105. private void InvokeHotKeyHandler(HotKeyHandler hotKeyDelegate)
  106. {
  107. if (hotKeyDelegate != null)
  108. hotKeyDelegate(this, new HotKeyArgs(DateTime.Now));
  109. }
  110. /// <summary>
  111. /// Adds the keys into the dictionary tracking the keys and gets the real-time status of the Keys
  112. /// from the OS
  113. /// </summary>
  114. private void InitializeKeys()
  115. {
  116. foreach (var k in HotKeys)
  117. {
  118. if (m_hotkeystate.ContainsKey(k))
  119. m_hotkeystate.Add(k, false);
  120. //assign using the current state of the keyboard
  121. m_hotkeystate[k] = KeyboardState.GetCurrent().IsDown(k);
  122. }
  123. }
  124. /// <summary>
  125. /// Unregisters a previously set exclusive or based on the primary key.
  126. /// </summary>
  127. /// <param name="anyKeyInTheExclusiveOrSet">Any key used in the Registration method used to create an exclusive or set</param>
  128. /// <returns>
  129. /// True if successful. False doesn't indicate a failure to unregister, it indicates that the Key is not
  130. /// registered as an Exclusive Or key or it's not the Primary Key.
  131. /// </returns>
  132. public bool UnregisterExclusiveOrKey(Keys anyKeyInTheExclusiveOrSet)
  133. {
  134. var primaryKey = GetExclusiveOrPrimaryKey(anyKeyInTheExclusiveOrSet);
  135. if (primaryKey == Keys.None || !m_remapping.ContainsValue(primaryKey))
  136. return false;
  137. var keystoremove = new List<Keys>();
  138. foreach (var pair in m_remapping)
  139. if (pair.Value == primaryKey)
  140. keystoremove.Add(pair.Key);
  141. foreach (var k in keystoremove)
  142. m_remapping.Remove(k);
  143. --m_remappingCount;
  144. return true;
  145. }
  146. /// <summary>
  147. /// Registers a group of Keys that are already part of the HotKeySet in order to provide better flexibility among keys.
  148. /// <example>
  149. /// <code>
  150. /// HotKeySet hks = new HotKeySet( new [] { Keys.T, Keys.LShiftKey, Keys.RShiftKey } );
  151. /// RegisterExclusiveOrKey( new [] { Keys.LShiftKey, Keys.RShiftKey } );
  152. /// </code>
  153. /// allows either Keys.LShiftKey or Keys.RShiftKey to be combined with Keys.T.
  154. /// </example>
  155. /// </summary>
  156. /// <param name="orKeySet"></param>
  157. /// <returns>Primary key used for mapping or Keys.None on error</returns>
  158. public Keys RegisterExclusiveOrKey(IEnumerable<Keys> orKeySet)
  159. {
  160. //Verification first, so as to not leave the m_remapping with a partial set.
  161. foreach (var k in orKeySet)
  162. if (!m_hotkeystate.ContainsKey(k))
  163. return Keys.None;
  164. var i = 0;
  165. var primaryKey = Keys.None;
  166. //Commit after verification
  167. foreach (var k in orKeySet)
  168. {
  169. if (i == 0)
  170. primaryKey = k;
  171. m_remapping[k] = primaryKey;
  172. ++i;
  173. }
  174. //Must increase to keep a true count of how many keys are necessary for the activation to be true
  175. ++m_remappingCount;
  176. return primaryKey;
  177. }
  178. /// <summary>
  179. /// Gets the primary key
  180. /// </summary>
  181. /// <param name="k"></param>
  182. /// <returns>The primary key if it exists, otherwise Keys.None</returns>
  183. private Keys GetExclusiveOrPrimaryKey(Keys k)
  184. {
  185. return m_remapping.ContainsKey(k) ? m_remapping[k] : Keys.None;
  186. }
  187. /// <summary>
  188. /// Resolves obtaining the key used for state checking.
  189. /// </summary>
  190. /// <param name="k"></param>
  191. /// <returns>The primary key if it exists, otherwise the key entered</returns>
  192. private Keys GetPrimaryKey(Keys k)
  193. {
  194. //If the key is remapped then get the primary keys
  195. return m_remapping.ContainsKey(k) ? m_remapping[k] : k;
  196. }
  197. /// <summary>
  198. /// </summary>
  199. /// <param name="kex"></param>
  200. internal void OnKey(KeyEventArgsExt kex)
  201. {
  202. if (!Enabled)
  203. return;
  204. //Gets the primary key if mapped to a single key or gets the key itself
  205. var primaryKey = GetPrimaryKey(kex.KeyCode);
  206. if (kex.IsKeyDown)
  207. OnKeyDown(primaryKey);
  208. else //reset
  209. OnKeyUp(primaryKey);
  210. }
  211. private void OnKeyDown(Keys k)
  212. {
  213. //If the keys are activated still then keep invoking the event
  214. if (HotKeysActivated)
  215. {
  216. InvokeHotKeyHandler(OnHotKeysDownHold); //Call the duration event
  217. }
  218. //indicates the key's state is current false but the key is now down
  219. else if (m_hotkeystate.ContainsKey(k) && !m_hotkeystate[k])
  220. {
  221. m_hotkeystate[k] = true; //key's state is down
  222. ++m_hotkeydowncount; //increase the number of keys down in this set
  223. if (HotKeysActivated) //because of the increase, check whether the set is activated
  224. InvokeHotKeyHandler(OnHotKeysDownOnce); //Call the initial event
  225. }
  226. }
  227. private void OnKeyUp(Keys k)
  228. {
  229. if (m_hotkeystate.ContainsKey(k) && m_hotkeystate[k]) //indicates the key's state was down but now it's up
  230. {
  231. var wasActive = HotKeysActivated;
  232. m_hotkeystate[k] = false; //key's state is up
  233. --m_hotkeydowncount; //this set is no longer ready
  234. if (wasActive)
  235. InvokeHotKeyHandler(OnHotKeysUp); //call the KeyUp event because the set is no longer active
  236. }
  237. }
  238. }
  239. }