PageRenderTime 66ms CodeModel.GetById 38ms RepoModel.GetById 1ms app.codeStats 0ms

/MonoGame.Framework/Input/KeyboardState.cs

https://bitbucket.org/refuzion/monogame
C# | 303 lines | 172 code | 37 blank | 94 comment | 47 complexity | 212760d602b48c27706975f673798d45 MD5 | raw file
  1. // #region License
  2. // /*
  3. // Microsoft Public License (Ms-PL)
  4. // MonoGame - Copyright © 2009 The MonoGame Team
  5. //
  6. // All rights reserved.
  7. //
  8. // This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
  9. // accept the license, do not use the software.
  10. //
  11. // 1. Definitions
  12. // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
  13. // U.S. copyright law.
  14. //
  15. // A "contribution" is the original software, or any additions or changes to the software.
  16. // A "contributor" is any person that distributes its contribution under this license.
  17. // "Licensed patents" are a contributor's patent claims that read directly on its contribution.
  18. //
  19. // 2. Grant of Rights
  20. // (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
  21. // each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
  22. // (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
  23. // each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
  24. //
  25. // 3. Conditions and Limitations
  26. // (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
  27. // (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
  28. // your patent license from such contributor to the software ends automatically.
  29. // (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
  30. // notices that are present in the software.
  31. // (D) If you distribute any portion of the software in source code form, you may do so only under this license by including
  32. // a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
  33. // code form, you may only do so under a license that complies with this license.
  34. // (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
  35. // or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
  36. // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
  37. // purpose and non-infringement.
  38. // */
  39. // #endregion License
  40. //
  41. using System.Collections.Generic;
  42. namespace Microsoft.Xna.Framework.Input
  43. {
  44. /// <summary>
  45. /// Holds the state of keystrokes by a keyboard.
  46. /// </summary>
  47. public struct KeyboardState
  48. {
  49. // Used for the common situation where GetPressedKeys will return an empty array
  50. static Keys[] empty = new Keys[0];
  51. #region Key Data
  52. // Array of 256 bits:
  53. uint keys0, keys1, keys2, keys3, keys4, keys5, keys6, keys7;
  54. bool InternalGetKey(Keys key)
  55. {
  56. uint mask = (uint)1 << (((int)key) & 0x1f);
  57. uint element;
  58. switch (((int)key) >> 5)
  59. {
  60. case 0: element = keys0; break;
  61. case 1: element = keys1; break;
  62. case 2: element = keys2; break;
  63. case 3: element = keys3; break;
  64. case 4: element = keys4; break;
  65. case 5: element = keys5; break;
  66. case 6: element = keys6; break;
  67. case 7: element = keys7; break;
  68. default: element = 0; break;
  69. }
  70. return (element & mask) != 0;
  71. }
  72. void InternalSetKey(Keys key)
  73. {
  74. uint mask = (uint)1 << (((int)key) & 0x1f);
  75. switch (((int)key) >> 5)
  76. {
  77. case 0: keys0 |= mask; break;
  78. case 1: keys1 |= mask; break;
  79. case 2: keys2 |= mask; break;
  80. case 3: keys3 |= mask; break;
  81. case 4: keys4 |= mask; break;
  82. case 5: keys5 |= mask; break;
  83. case 6: keys6 |= mask; break;
  84. case 7: keys7 |= mask; break;
  85. }
  86. }
  87. void InternalClearKey(Keys key)
  88. {
  89. uint mask = (uint)1 << (((int)key) & 0x1f);
  90. switch (((int)key) >> 5)
  91. {
  92. case 0: keys0 &= ~mask; break;
  93. case 1: keys1 &= ~mask; break;
  94. case 2: keys2 &= ~mask; break;
  95. case 3: keys3 &= ~mask; break;
  96. case 4: keys4 &= ~mask; break;
  97. case 5: keys5 &= ~mask; break;
  98. case 6: keys6 &= ~mask; break;
  99. case 7: keys7 &= ~mask; break;
  100. }
  101. }
  102. void InternalClearAllKeys()
  103. {
  104. keys0 = 0;
  105. keys1 = 0;
  106. keys2 = 0;
  107. keys3 = 0;
  108. keys4 = 0;
  109. keys5 = 0;
  110. keys6 = 0;
  111. keys7 = 0;
  112. }
  113. #endregion
  114. #region XNA Interface
  115. /// <summary>
  116. /// Initializes a new instance of the <see cref="KeyboardState"/> class.
  117. /// </summary>
  118. /// <param name="keys">List of keys to be flagged as pressed on initialization.</param>
  119. internal KeyboardState(List<Keys> keys)
  120. {
  121. keys0 = 0;
  122. keys1 = 0;
  123. keys2 = 0;
  124. keys3 = 0;
  125. keys4 = 0;
  126. keys5 = 0;
  127. keys6 = 0;
  128. keys7 = 0;
  129. if (keys != null)
  130. foreach (Keys k in keys)
  131. InternalSetKey(k);
  132. }
  133. /// <summary>
  134. /// Initializes a new instance of the <see cref="KeyboardState"/> class.
  135. /// </summary>
  136. /// <param name="keys">List of keys to be flagged as pressed on initialization.</param>
  137. public KeyboardState(params Keys[] keys)
  138. {
  139. keys0 = 0;
  140. keys1 = 0;
  141. keys2 = 0;
  142. keys3 = 0;
  143. keys4 = 0;
  144. keys5 = 0;
  145. keys6 = 0;
  146. keys7 = 0;
  147. if (keys != null)
  148. foreach (Keys k in keys)
  149. InternalSetKey(k);
  150. }
  151. /// <summary>
  152. /// Returns the state of a specified key.
  153. /// </summary>
  154. /// <param name="key">The key to query.</param>
  155. /// <returns>The state of the key.</returns>
  156. public KeyState this[Keys key]
  157. {
  158. get { return InternalGetKey(key) ? KeyState.Down : KeyState.Up; }
  159. }
  160. /// <summary>
  161. /// Gets whether given key is currently being pressed.
  162. /// </summary>
  163. /// <param name="key">The key to query.</param>
  164. /// <returns>true if the key is pressed; false otherwise.</returns>
  165. public bool IsKeyDown(Keys key)
  166. {
  167. return InternalGetKey(key);
  168. }
  169. /// <summary>
  170. /// Gets whether given key is currently being not pressed.
  171. /// </summary>
  172. /// <param name="key">The key to query.</param>
  173. /// <returns>true if the key is not pressed; false otherwise.</returns>
  174. public bool IsKeyUp(Keys key)
  175. {
  176. return !InternalGetKey(key);
  177. }
  178. #endregion
  179. #region GetPressedKeys()
  180. private static uint CountBits(uint v)
  181. {
  182. // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
  183. v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
  184. v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
  185. return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
  186. }
  187. private static int AddKeysToArray(uint keys, int offset, Keys[] pressedKeys, int index)
  188. {
  189. for (int i = 0; i < 32; i++)
  190. {
  191. if ((keys & (1 << i)) != 0)
  192. pressedKeys[index++] = (Keys)(offset + i);
  193. }
  194. return index;
  195. }
  196. /// <summary>
  197. /// Returns an array of values holding keys that are currently being pressed.
  198. /// </summary>
  199. /// <returns>The keys that are currently being pressed.</returns>
  200. public Keys[] GetPressedKeys()
  201. {
  202. uint count = CountBits(keys0) + CountBits(keys1) + CountBits(keys2) + CountBits(keys3)
  203. + CountBits(keys4) + CountBits(keys5) + CountBits(keys6) + CountBits(keys7);
  204. if (count == 0)
  205. return empty;
  206. Keys[] keys = new Keys[count];
  207. int index = 0;
  208. if (keys0 != 0) index = AddKeysToArray(keys0, 0 * 32, keys, index);
  209. if (keys1 != 0) index = AddKeysToArray(keys1, 1 * 32, keys, index);
  210. if (keys2 != 0) index = AddKeysToArray(keys2, 2 * 32, keys, index);
  211. if (keys3 != 0) index = AddKeysToArray(keys3, 3 * 32, keys, index);
  212. if (keys4 != 0) index = AddKeysToArray(keys4, 4 * 32, keys, index);
  213. if (keys5 != 0) index = AddKeysToArray(keys5, 5 * 32, keys, index);
  214. if (keys6 != 0) index = AddKeysToArray(keys6, 6 * 32, keys, index);
  215. if (keys7 != 0) index = AddKeysToArray(keys7, 7 * 32, keys, index);
  216. return keys;
  217. }
  218. #endregion
  219. #region Objet and Equality
  220. /// <summary>
  221. /// Gets the hash code for <see cref="KeyboardState"/> instance.
  222. /// </summary>
  223. /// <returns>Hash code of the object.</returns>
  224. public override int GetHashCode()
  225. {
  226. return (int)(keys0 ^ keys1 ^ keys2 ^ keys3 ^ keys4 ^ keys5 ^ keys6 ^ keys7);
  227. }
  228. /// <summary>
  229. /// Compares whether two <see cref="KeyboardState"/> instances are equal.
  230. /// </summary>
  231. /// <param name="a"><see cref="KeyboardState"/> instance to the left of the equality operator.</param>
  232. /// <param name="b"><see cref="KeyboardState"/> instance to the right of the equality operator.</param>
  233. /// <returns>true if the instances are equal; false otherwise.</returns>
  234. public static bool operator ==(KeyboardState a, KeyboardState b)
  235. {
  236. return a.keys0 == b.keys0
  237. && a.keys1 == b.keys1
  238. && a.keys2 == b.keys2
  239. && a.keys3 == b.keys3
  240. && a.keys4 == b.keys4
  241. && a.keys5 == b.keys5
  242. && a.keys6 == b.keys6
  243. && a.keys7 == b.keys7;
  244. }
  245. /// <summary>
  246. /// Compares whether two <see cref="KeyboardState"/> instances are not equal.
  247. /// </summary>
  248. /// <param name="a"><see cref="KeyboardState"/> instance to the left of the inequality operator.</param>
  249. /// <param name="b"><see cref="KeyboardState"/> instance to the right of the inequality operator.</param>
  250. /// <returns>true if the instances are different; false otherwise.</returns>
  251. public static bool operator !=(KeyboardState a, KeyboardState b)
  252. {
  253. return !(a == b);
  254. }
  255. /// <summary>
  256. /// Compares whether current instance is equal to specified object.
  257. /// </summary>
  258. /// <param name="obj">The <see cref="KeyboardState"/> to compare.</param>
  259. /// <returns>true if the provided <see cref="KeyboardState"/> instance is same with current; false otherwise.</returns>
  260. public override bool Equals(object obj)
  261. {
  262. return obj is KeyboardState && this == (KeyboardState)obj;
  263. }
  264. #endregion
  265. }
  266. }