InputState.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. //-----------------------------------------------------------------------------
  2. // InputState.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using Microsoft.Xna.Framework;
  10. using Microsoft.Xna.Framework.Input;
  11. using Microsoft.Xna.Framework.Input.Touch;
  12. namespace CatapultGame
  13. {
  14. /// <summary>
  15. /// Helper for reading input from keyboard, gamepad, and touch input. This class
  16. /// tracks both the current and previous state of the input devices, and implements
  17. /// query methods for high level input actions such as "move up through the menu"
  18. /// or "pause the game".
  19. /// </summary>
  20. public class InputState
  21. {
  22. public const int MaxInputs = 4;
  23. public readonly KeyboardState[] CurrentKeyboardStates;
  24. public readonly GamePadState[] CurrentGamePadStates;
  25. public readonly KeyboardState[] LastKeyboardStates;
  26. public readonly GamePadState[] LastGamePadStates;
  27. public readonly bool[] GamePadWasConnected;
  28. public TouchCollection TouchState;
  29. public MouseState CurrentMouseState;
  30. public MouseState LastMouseState;
  31. public readonly List<GestureSample> Gestures = new List<GestureSample>();
  32. Matrix inputTransformation;
  33. readonly float baseBufferWidth;
  34. readonly float baseBufferHeight;
  35. /// <summary>
  36. /// Constructs a new input state.
  37. /// </summary>
  38. public InputState(float baseBufferWidth, float baseBufferHeight)
  39. {
  40. this.baseBufferWidth = baseBufferWidth;
  41. this.baseBufferHeight = baseBufferHeight;
  42. CurrentKeyboardStates = new KeyboardState[MaxInputs];
  43. CurrentGamePadStates = new GamePadState[MaxInputs];
  44. LastKeyboardStates = new KeyboardState[MaxInputs];
  45. LastGamePadStates = new GamePadState[MaxInputs];
  46. GamePadWasConnected = new bool[MaxInputs];
  47. }
  48. /// <summary>
  49. /// Reads the latest state of the keyboard and gamepad.
  50. /// </summary>
  51. public void Update()
  52. {
  53. for (int i = 0; i < MaxInputs; i++)
  54. {
  55. LastKeyboardStates[i] = CurrentKeyboardStates[i];
  56. LastGamePadStates[i] = CurrentGamePadStates[i];
  57. CurrentKeyboardStates[i] = Keyboard.GetState();
  58. CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);
  59. // Keep track of whether a gamepad has ever been
  60. // connected, so we can detect if it is unplugged.
  61. if (CurrentGamePadStates[i].IsConnected)
  62. {
  63. GamePadWasConnected[i] = true;
  64. }
  65. }
  66. TouchState = TouchPanel.GetState();
  67. LastMouseState = CurrentMouseState;
  68. CurrentMouseState = Mouse.GetState();
  69. UpdateMouseStates();
  70. Gestures.Clear();
  71. while (TouchPanel.IsGestureAvailable)
  72. {
  73. Gestures.Add(TouchPanel.ReadGesture());
  74. }
  75. }
  76. bool dragging = false;
  77. bool dragComplete = false;
  78. bool leftMouseDown = false;
  79. int dragThreshold = 3;
  80. MouseGestureType mouseGestureType;
  81. Vector2 currentMousePosition = Vector2.Zero;
  82. Vector2 prevMousePosition = Vector2.Zero;
  83. Vector2 dragMouseStart = Vector2.Zero;
  84. Vector2 dragMouseEnd = Vector2.Zero;
  85. public MouseGestureType MouseGesture
  86. {
  87. get
  88. {
  89. return mouseGestureType;
  90. }
  91. }
  92. public Vector2 CurrentMousePosition
  93. {
  94. get
  95. {
  96. return currentMousePosition;
  97. }
  98. }
  99. public Vector2 PrevMousePosition
  100. {
  101. get
  102. {
  103. return prevMousePosition;
  104. }
  105. }
  106. public Vector2 MouseDelta
  107. {
  108. get
  109. {
  110. return prevMousePosition - currentMousePosition;
  111. }
  112. }
  113. public Vector2 MouseDragDelta
  114. {
  115. get
  116. {
  117. return dragMouseStart - dragMouseEnd;
  118. }
  119. }
  120. public Vector2 MouseDragStartPosition
  121. {
  122. get
  123. {
  124. return dragMouseStart;
  125. }
  126. }
  127. public Vector2 MouseDragEndPosition
  128. {
  129. get
  130. {
  131. return dragMouseEnd;
  132. }
  133. }
  134. void UpdateMouseStates()
  135. {
  136. currentMousePosition.X = CurrentMouseState.X;
  137. currentMousePosition.Y = CurrentMouseState.Y;
  138. prevMousePosition.X = LastMouseState.X;
  139. prevMousePosition.Y = LastMouseState.Y;
  140. if (mouseGestureType.HasFlag(MouseGestureType.LeftClick))
  141. mouseGestureType = mouseGestureType ^ MouseGestureType.LeftClick;
  142. if (mouseGestureType.HasFlag(MouseGestureType.Move))
  143. mouseGestureType = mouseGestureType ^ MouseGestureType.Move;
  144. if (MouseDelta.Length() != 0)
  145. mouseGestureType = mouseGestureType | MouseGestureType.Move;
  146. // If we were dragging and the left mouse button was released
  147. // then we are no longer dragging and need to throw the banana.
  148. if (CurrentMouseState.LeftButton == ButtonState.Released &&
  149. dragging)
  150. {
  151. leftMouseDown = false;
  152. dragging = false;
  153. dragComplete = true;
  154. dragMouseEnd = currentMousePosition;
  155. mouseGestureType |= MouseGestureType.DragComplete;
  156. mouseGestureType = mouseGestureType ^ MouseGestureType.FreeDrag;
  157. //Console.WriteLine ("Dragging: " + mouseGestureType);
  158. }
  159. // Let's set the left mouse down and the mouse origin
  160. if (!leftMouseDown && CurrentMouseState.LeftButton == ButtonState.Pressed &&
  161. !CurrentMouseState.Equals(LastMouseState))
  162. {
  163. //Console.WriteLine ("left down");
  164. leftMouseDown = true;
  165. dragComplete = false;
  166. dragMouseStart = currentMousePosition;
  167. }
  168. if (leftMouseDown && CurrentMouseState.LeftButton == ButtonState.Released &&
  169. !CurrentMouseState.Equals(LastMouseState))
  170. {
  171. leftMouseDown = false;
  172. mouseGestureType |= MouseGestureType.LeftClick;
  173. }
  174. // Here we test the distance and if over the threshold then we set the dragging to true
  175. // Current threshold is 5 pixels.
  176. if (leftMouseDown && !dragging)
  177. {
  178. Vector2 delta = dragMouseStart - currentMousePosition;
  179. if (delta.Length() > dragThreshold)
  180. {
  181. dragging = true;
  182. dragMouseStart = currentMousePosition;
  183. mouseGestureType = mouseGestureType | MouseGestureType.FreeDrag;
  184. //Console.WriteLine ("Dragging: " + mouseGestureType);
  185. }
  186. }
  187. //Console.WriteLine(mouseGestureType);
  188. }
  189. /// <summary>
  190. /// Helper for checking if a key was newly pressed during this update. The
  191. /// controllingPlayer parameter specifies which player to read input for.
  192. /// If this is null, it will accept input from any player. When a keypress
  193. /// is detected, the output playerIndex reports which player pressed it.
  194. /// </summary>
  195. public bool IsNewKeyPress(Keys key, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
  196. {
  197. if (controllingPlayer.HasValue)
  198. {
  199. // Read input from the specified player.
  200. playerIndex = controllingPlayer.Value;
  201. int i = (int)playerIndex;
  202. return (CurrentKeyboardStates[i].IsKeyDown(key) && LastKeyboardStates[i].IsKeyUp(key));
  203. }
  204. else
  205. {
  206. // Accept input from any player.
  207. return (IsNewKeyPress(key, PlayerIndex.One, out playerIndex) ||
  208. IsNewKeyPress(key, PlayerIndex.Two, out playerIndex) ||
  209. IsNewKeyPress(key, PlayerIndex.Three, out playerIndex) ||
  210. IsNewKeyPress(key, PlayerIndex.Four, out playerIndex));
  211. }
  212. }
  213. /// <summary>
  214. /// Helper for checking if a button was newly pressed during this update.
  215. /// The controllingPlayer parameter specifies which player to read input for.
  216. /// If this is null, it will accept input from any player. When a button press
  217. /// is detected, the output playerIndex reports which player pressed it.
  218. /// </summary>
  219. public bool IsNewButtonPress(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
  220. {
  221. if (controllingPlayer.HasValue)
  222. {
  223. // Read input from the specified player.
  224. playerIndex = controllingPlayer.Value;
  225. int i = (int)playerIndex;
  226. return (CurrentGamePadStates[i].IsButtonDown(button) && LastGamePadStates[i].IsButtonUp(button));
  227. }
  228. else
  229. {
  230. // Accept input from any player.
  231. return (IsNewButtonPress(button, PlayerIndex.One, out playerIndex) ||
  232. IsNewButtonPress(button, PlayerIndex.Two, out playerIndex) ||
  233. IsNewButtonPress(button, PlayerIndex.Three, out playerIndex) ||
  234. IsNewButtonPress(button, PlayerIndex.Four, out playerIndex));
  235. }
  236. }
  237. /// <summary>
  238. /// Checks for a "menu select" input action.
  239. /// The controllingPlayer parameter specifies which player to read input for.
  240. /// If this is null, it will accept input from any player. When the action
  241. /// is detected, the output playerIndex reports which player pressed it.
  242. /// </summary>
  243. public bool IsMenuSelect(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
  244. {
  245. return IsNewKeyPress(Keys.Space, controllingPlayer, out playerIndex) ||
  246. IsNewKeyPress(Keys.Enter, controllingPlayer, out playerIndex) ||
  247. IsNewButtonPress(Buttons.A, controllingPlayer, out playerIndex) ||
  248. IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
  249. }
  250. /// <summary>
  251. /// Checks for a "menu cancel" input action.
  252. /// The controllingPlayer parameter specifies which player to read input for.
  253. /// If this is null, it will accept input from any player. When the action
  254. /// is detected, the output playerIndex reports which player pressed it.
  255. /// </summary>
  256. public bool IsMenuCancel(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
  257. {
  258. return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
  259. IsNewButtonPress(Buttons.B, controllingPlayer, out playerIndex) ||
  260. IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex);
  261. }
  262. /// <summary>
  263. /// Checks for a "menu up" input action.
  264. /// The controllingPlayer parameter specifies which player to read
  265. /// input for. If this is null, it will accept input from any player.
  266. /// </summary>
  267. public bool IsMenuUp(PlayerIndex? controllingPlayer)
  268. {
  269. PlayerIndex playerIndex;
  270. return IsNewKeyPress(Keys.Up, controllingPlayer, out playerIndex) ||
  271. IsNewButtonPress(Buttons.DPadUp, controllingPlayer, out playerIndex) ||
  272. IsNewButtonPress(Buttons.LeftThumbstickUp, controllingPlayer, out playerIndex);
  273. }
  274. /// <summary>
  275. /// Checks for a "menu down" input action.
  276. /// The controllingPlayer parameter specifies which player to read
  277. /// input for. If this is null, it will accept input from any player.
  278. /// </summary>
  279. public bool IsMenuDown(PlayerIndex? controllingPlayer)
  280. {
  281. PlayerIndex playerIndex;
  282. return IsNewKeyPress(Keys.Down, controllingPlayer, out playerIndex) ||
  283. IsNewButtonPress(Buttons.DPadDown, controllingPlayer, out playerIndex) ||
  284. IsNewButtonPress(Buttons.LeftThumbstickDown, controllingPlayer, out playerIndex);
  285. }
  286. /// <summary>
  287. /// Checks for a "pause the game" input action.
  288. /// The controllingPlayer parameter specifies which player to read
  289. /// input for. If this is null, it will accept input from any player.
  290. /// </summary>
  291. public bool IsPauseGame(PlayerIndex? controllingPlayer)
  292. {
  293. PlayerIndex playerIndex;
  294. return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
  295. IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex) ||
  296. IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
  297. }
  298. /// <summary>
  299. /// Updates the matrix used to transform input coordinates.
  300. /// </summary>
  301. /// <param name="inputTransformation">The transformation matrix to apply.</param>
  302. public void UpdateInputTransformation(Matrix inputTransformation)
  303. {
  304. this.inputTransformation = inputTransformation;
  305. }
  306. }
  307. }