/MonoGame.Framework/Input/KeyboardState.cs
C# | 303 lines | 172 code | 37 blank | 94 comment | 47 complexity | 212760d602b48c27706975f673798d45 MD5 | raw file
- // #region License
- // /*
- // Microsoft Public License (Ms-PL)
- // MonoGame - Copyright © 2009 The MonoGame Team
- //
- // All rights reserved.
- //
- // This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
- // accept the license, do not use the software.
- //
- // 1. Definitions
- // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
- // U.S. copyright law.
- //
- // A "contribution" is the original software, or any additions or changes to the software.
- // A "contributor" is any person that distributes its contribution under this license.
- // "Licensed patents" are a contributor's patent claims that read directly on its contribution.
- //
- // 2. Grant of Rights
- // (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
- // 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.
- // (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
- // 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.
- //
- // 3. Conditions and Limitations
- // (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
- // (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
- // your patent license from such contributor to the software ends automatically.
- // (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
- // notices that are present in the software.
- // (D) If you distribute any portion of the software in source code form, you may do so only under this license by including
- // a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
- // code form, you may only do so under a license that complies with this license.
- // (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
- // or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
- // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
- // purpose and non-infringement.
- // */
- // #endregion License
- //
- using System.Collections.Generic;
- namespace Microsoft.Xna.Framework.Input
- {
- /// <summary>
- /// Holds the state of keystrokes by a keyboard.
- /// </summary>
- public struct KeyboardState
- {
- // Used for the common situation where GetPressedKeys will return an empty array
- static Keys[] empty = new Keys[0];
- #region Key Data
- // Array of 256 bits:
- uint keys0, keys1, keys2, keys3, keys4, keys5, keys6, keys7;
- bool InternalGetKey(Keys key)
- {
- uint mask = (uint)1 << (((int)key) & 0x1f);
- uint element;
- switch (((int)key) >> 5)
- {
- case 0: element = keys0; break;
- case 1: element = keys1; break;
- case 2: element = keys2; break;
- case 3: element = keys3; break;
- case 4: element = keys4; break;
- case 5: element = keys5; break;
- case 6: element = keys6; break;
- case 7: element = keys7; break;
- default: element = 0; break;
- }
- return (element & mask) != 0;
- }
- void InternalSetKey(Keys key)
- {
- uint mask = (uint)1 << (((int)key) & 0x1f);
- switch (((int)key) >> 5)
- {
- case 0: keys0 |= mask; break;
- case 1: keys1 |= mask; break;
- case 2: keys2 |= mask; break;
- case 3: keys3 |= mask; break;
- case 4: keys4 |= mask; break;
- case 5: keys5 |= mask; break;
- case 6: keys6 |= mask; break;
- case 7: keys7 |= mask; break;
- }
- }
- void InternalClearKey(Keys key)
- {
- uint mask = (uint)1 << (((int)key) & 0x1f);
- switch (((int)key) >> 5)
- {
- case 0: keys0 &= ~mask; break;
- case 1: keys1 &= ~mask; break;
- case 2: keys2 &= ~mask; break;
- case 3: keys3 &= ~mask; break;
- case 4: keys4 &= ~mask; break;
- case 5: keys5 &= ~mask; break;
- case 6: keys6 &= ~mask; break;
- case 7: keys7 &= ~mask; break;
- }
- }
- void InternalClearAllKeys()
- {
- keys0 = 0;
- keys1 = 0;
- keys2 = 0;
- keys3 = 0;
- keys4 = 0;
- keys5 = 0;
- keys6 = 0;
- keys7 = 0;
- }
- #endregion
- #region XNA Interface
- /// <summary>
- /// Initializes a new instance of the <see cref="KeyboardState"/> class.
- /// </summary>
- /// <param name="keys">List of keys to be flagged as pressed on initialization.</param>
- internal KeyboardState(List<Keys> keys)
- {
- keys0 = 0;
- keys1 = 0;
- keys2 = 0;
- keys3 = 0;
- keys4 = 0;
- keys5 = 0;
- keys6 = 0;
- keys7 = 0;
- if (keys != null)
- foreach (Keys k in keys)
- InternalSetKey(k);
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="KeyboardState"/> class.
- /// </summary>
- /// <param name="keys">List of keys to be flagged as pressed on initialization.</param>
- public KeyboardState(params Keys[] keys)
- {
- keys0 = 0;
- keys1 = 0;
- keys2 = 0;
- keys3 = 0;
- keys4 = 0;
- keys5 = 0;
- keys6 = 0;
- keys7 = 0;
- if (keys != null)
- foreach (Keys k in keys)
- InternalSetKey(k);
- }
- /// <summary>
- /// Returns the state of a specified key.
- /// </summary>
- /// <param name="key">The key to query.</param>
- /// <returns>The state of the key.</returns>
- public KeyState this[Keys key]
- {
- get { return InternalGetKey(key) ? KeyState.Down : KeyState.Up; }
- }
- /// <summary>
- /// Gets whether given key is currently being pressed.
- /// </summary>
- /// <param name="key">The key to query.</param>
- /// <returns>true if the key is pressed; false otherwise.</returns>
- public bool IsKeyDown(Keys key)
- {
- return InternalGetKey(key);
- }
- /// <summary>
- /// Gets whether given key is currently being not pressed.
- /// </summary>
- /// <param name="key">The key to query.</param>
- /// <returns>true if the key is not pressed; false otherwise.</returns>
- public bool IsKeyUp(Keys key)
- {
- return !InternalGetKey(key);
- }
- #endregion
- #region GetPressedKeys()
- private static uint CountBits(uint v)
- {
- // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
- v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
- v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
- return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
- }
- private static int AddKeysToArray(uint keys, int offset, Keys[] pressedKeys, int index)
- {
- for (int i = 0; i < 32; i++)
- {
- if ((keys & (1 << i)) != 0)
- pressedKeys[index++] = (Keys)(offset + i);
- }
- return index;
- }
- /// <summary>
- /// Returns an array of values holding keys that are currently being pressed.
- /// </summary>
- /// <returns>The keys that are currently being pressed.</returns>
- public Keys[] GetPressedKeys()
- {
- uint count = CountBits(keys0) + CountBits(keys1) + CountBits(keys2) + CountBits(keys3)
- + CountBits(keys4) + CountBits(keys5) + CountBits(keys6) + CountBits(keys7);
- if (count == 0)
- return empty;
- Keys[] keys = new Keys[count];
- int index = 0;
- if (keys0 != 0) index = AddKeysToArray(keys0, 0 * 32, keys, index);
- if (keys1 != 0) index = AddKeysToArray(keys1, 1 * 32, keys, index);
- if (keys2 != 0) index = AddKeysToArray(keys2, 2 * 32, keys, index);
- if (keys3 != 0) index = AddKeysToArray(keys3, 3 * 32, keys, index);
- if (keys4 != 0) index = AddKeysToArray(keys4, 4 * 32, keys, index);
- if (keys5 != 0) index = AddKeysToArray(keys5, 5 * 32, keys, index);
- if (keys6 != 0) index = AddKeysToArray(keys6, 6 * 32, keys, index);
- if (keys7 != 0) index = AddKeysToArray(keys7, 7 * 32, keys, index);
- return keys;
- }
- #endregion
- #region Objet and Equality
- /// <summary>
- /// Gets the hash code for <see cref="KeyboardState"/> instance.
- /// </summary>
- /// <returns>Hash code of the object.</returns>
- public override int GetHashCode()
- {
- return (int)(keys0 ^ keys1 ^ keys2 ^ keys3 ^ keys4 ^ keys5 ^ keys6 ^ keys7);
- }
- /// <summary>
- /// Compares whether two <see cref="KeyboardState"/> instances are equal.
- /// </summary>
- /// <param name="a"><see cref="KeyboardState"/> instance to the left of the equality operator.</param>
- /// <param name="b"><see cref="KeyboardState"/> instance to the right of the equality operator.</param>
- /// <returns>true if the instances are equal; false otherwise.</returns>
- public static bool operator ==(KeyboardState a, KeyboardState b)
- {
- return a.keys0 == b.keys0
- && a.keys1 == b.keys1
- && a.keys2 == b.keys2
- && a.keys3 == b.keys3
- && a.keys4 == b.keys4
- && a.keys5 == b.keys5
- && a.keys6 == b.keys6
- && a.keys7 == b.keys7;
- }
- /// <summary>
- /// Compares whether two <see cref="KeyboardState"/> instances are not equal.
- /// </summary>
- /// <param name="a"><see cref="KeyboardState"/> instance to the left of the inequality operator.</param>
- /// <param name="b"><see cref="KeyboardState"/> instance to the right of the inequality operator.</param>
- /// <returns>true if the instances are different; false otherwise.</returns>
- public static bool operator !=(KeyboardState a, KeyboardState b)
- {
- return !(a == b);
- }
- /// <summary>
- /// Compares whether current instance is equal to specified object.
- /// </summary>
- /// <param name="obj">The <see cref="KeyboardState"/> to compare.</param>
- /// <returns>true if the provided <see cref="KeyboardState"/> instance is same with current; false otherwise.</returns>
- public override bool Equals(object obj)
- {
- return obj is KeyboardState && this == (KeyboardState)obj;
- }
- #endregion
- }
- }