#region License /* FNA - XNA4 Reimplementation for Desktop Platforms * Copyright 2009-2016 Ethan Lee and the MonoGame Team * * Released under the Microsoft Public License. * See LICENSE for details. */ #endregion #region Using Statements using System.Collections.Generic; #endregion namespace Microsoft.Xna.Framework.Input { /// /// Holds the state of keystrokes by a keyboard. /// public struct KeyboardState { #region Public Properties /// /// Returns the state of a specified key. /// /// The key to query. /// The state of the key. public KeyState this[Keys key] { get { return InternalGetKey(key) ? KeyState.Down : KeyState.Up; } } #endregion #region Private Variables // Array of 256 bits: uint keys0, keys1, keys2, keys3, keys4, keys5, keys6, keys7; #endregion #region Private Static Variables // Used for the common situation where GetPressedKeys will return an empty array static Keys[] empty = new Keys[0]; #endregion #region Public Constructor /// /// Initializes a new instance of the class. /// /// List of keys to be flagged as pressed on initialization. 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); } } } #endregion #region Internal Constructor /// /// Initializes a new instance of the class. /// /// List of keys to be flagged as pressed on initialization. internal KeyboardState(List 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); } } } #endregion #region Public Methods /// /// Gets whether given key is currently being pressed. /// /// The key to query. /// true if the key is pressed; false otherwise. public bool IsKeyDown(Keys key) { return InternalGetKey(key); } /// /// Gets whether given key is currently being not pressed. /// /// The key to query. /// true if the key is not pressed; false otherwise. public bool IsKeyUp(Keys key) { return !InternalGetKey(key); } /// /// Returns an array of values holding keys that are currently being pressed. /// /// The keys that are currently being pressed. 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 Private Methods 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 Public Static Operators and Override Methods /// /// Gets the hash code for instance. /// /// Hash code of the object. public override int GetHashCode() { return (int) (keys0 ^ keys1 ^ keys2 ^ keys3 ^ keys4 ^ keys5 ^ keys6 ^ keys7); } /// /// Compares whether two instances are equal. /// /// instance to the left of the equality operator. /// instance to the right of the equality operator. /// true if the instances are equal; false otherwise. 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 ); } /// /// Compares whether two instances are not equal. /// /// instance to the left of the inequality operator. /// instance to the right of the inequality operator. /// true if the instances are different; false otherwise. public static bool operator !=(KeyboardState a, KeyboardState b) { return !(a == b); } /// /// Compares whether current instance is equal to specified object. /// /// The to compare. /// true if the provided instance is same with current; false otherwise. public override bool Equals(object obj) { return obj is KeyboardState && this == (KeyboardState) obj; } #endregion #region Private Static Methods 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 += 1) { if ((keys & (1 << i)) != 0) { pressedKeys[index++] = (Keys) (offset + i); } } return index; } #endregion } }