#region File Description //----------------------------------------------------------------------------- // InputState.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input.Touch; #endregion namespace GameStateManagement { /// /// Helper for reading input from keyboard, gamepad, and touch input. This class /// tracks both the current and previous state of the input devices, and implements /// query methods for high level input actions such as "move up through the menu" /// or "pause the game". /// public class InputState { #region Fields public const int MaxInputs = 4; public readonly KeyboardState[] CurrentKeyboardStates; public readonly GamePadState[] CurrentGamePadStates; public readonly KeyboardState[] LastKeyboardStates; public readonly GamePadState[] LastGamePadStates; public readonly bool[] GamePadWasConnected; public TouchCollection TouchState; public MouseState CurrentMouseState; public MouseState LastMouseState; public readonly List Gestures = new List (); #endregion #region Initialization /// /// Constructs a new input state. /// public InputState () { CurrentKeyboardStates = new KeyboardState[MaxInputs]; CurrentGamePadStates = new GamePadState[MaxInputs]; LastKeyboardStates = new KeyboardState[MaxInputs]; LastGamePadStates = new GamePadState[MaxInputs]; GamePadWasConnected = new bool[MaxInputs]; } #endregion #region Public Methods /// /// Reads the latest state of the keyboard and gamepad. /// public void Update () { for (int i = 0; i < MaxInputs; i++) { LastKeyboardStates [i] = CurrentKeyboardStates [i]; LastGamePadStates [i] = CurrentGamePadStates [i]; CurrentKeyboardStates [i] = Keyboard.GetState ((PlayerIndex)i); CurrentGamePadStates [i] = GamePad.GetState ((PlayerIndex)i); // Keep track of whether a gamepad has ever been // connected, so we can detect if it is unplugged. if (CurrentGamePadStates [i].IsConnected) { GamePadWasConnected [i] = true; } } TouchState = TouchPanel.GetState (); LastMouseState = CurrentMouseState; CurrentMouseState = Mouse.GetState (); UpdateMouseStates(); Gestures.Clear (); while (TouchPanel.IsGestureAvailable) { Gestures.Add (TouchPanel.ReadGesture ()); } } bool dragging = false; bool dragComplete = false; bool leftMouseDown = false; int dragThreshold = 3; MouseGestureType mouseGestureType; Vector2 currentMousePosition = Vector2.Zero; Vector2 prevMousePosition = Vector2.Zero; Vector2 dragMouseStart = Vector2.Zero; Vector2 dragMouseEnd = Vector2.Zero; public MouseGestureType MouseGesture { get { return mouseGestureType; } } public Vector2 CurrentMousePosition { get { return currentMousePosition; } } public Vector2 PrevMousePosition { get { return prevMousePosition; } } public Vector2 MouseDelta { get { return prevMousePosition - currentMousePosition; } } public Vector2 MouseDragDelta { get { return dragMouseStart - dragMouseEnd; } } public Vector2 MouseDragStartPosition { get { return dragMouseStart; } } public Vector2 MouseDragEndPosition { get { return dragMouseEnd; } } void UpdateMouseStates () { currentMousePosition.X = CurrentMouseState.X; currentMousePosition.Y = CurrentMouseState.Y; prevMousePosition.X = LastMouseState.X; prevMousePosition.Y = LastMouseState.Y; if (mouseGestureType.HasFlag(MouseGestureType.LeftClick)) mouseGestureType = mouseGestureType ^ MouseGestureType.LeftClick; if (mouseGestureType.HasFlag(MouseGestureType.Move)) mouseGestureType = mouseGestureType ^ MouseGestureType.Move; if (MouseDelta.Length() != 0) mouseGestureType = mouseGestureType | MouseGestureType.Move; // If we were dragging and the left mouse button was released // then we are no longer dragging and need to throw the banana. if (CurrentMouseState.LeftButton == ButtonState.Released && dragging) { leftMouseDown = false; dragging = false; dragComplete = true; dragMouseEnd = currentMousePosition; mouseGestureType |= MouseGestureType.DragComplete; mouseGestureType = mouseGestureType ^ MouseGestureType.FreeDrag; //Console.WriteLine ("Dragging: " + mouseGestureType); } // Let's set the left mouse down and the mouse origin if (!leftMouseDown && CurrentMouseState.LeftButton == ButtonState.Pressed && !CurrentMouseState.Equals (LastMouseState)) { //Console.WriteLine ("left down"); leftMouseDown = true; dragComplete = false; dragMouseStart = currentMousePosition; } if (leftMouseDown && CurrentMouseState.LeftButton == ButtonState.Released && !CurrentMouseState.Equals (LastMouseState)) { leftMouseDown = false; mouseGestureType |= MouseGestureType.LeftClick; } // Here we test the distance and if over the threshold then we set the dragging to true // Current threshold is 5 pixels. if (leftMouseDown && !dragging) { Vector2 delta = dragMouseStart - currentMousePosition; if (delta.Length() > dragThreshold) { dragging = true; dragMouseStart = currentMousePosition; mouseGestureType = mouseGestureType | MouseGestureType.FreeDrag; //Console.WriteLine ("Dragging: " + mouseGestureType); } } //Console.WriteLine(mouseGestureType); } /// /// Helper for checking if a key was newly pressed during this update. The /// controllingPlayer parameter specifies which player to read input for. /// If this is null, it will accept input from any player. When a keypress /// is detected, the output playerIndex reports which player pressed it. /// public bool IsNewKeyPress (Keys key, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex) { if (controllingPlayer.HasValue) { // Read input from the specified player. playerIndex = controllingPlayer.Value; int i = (int)playerIndex; return (CurrentKeyboardStates [i].IsKeyDown (key) && LastKeyboardStates [i].IsKeyUp (key)); } else { // Accept input from any player. return (IsNewKeyPress (key, PlayerIndex.One, out playerIndex) || IsNewKeyPress (key, PlayerIndex.Two, out playerIndex) || IsNewKeyPress (key, PlayerIndex.Three, out playerIndex) || IsNewKeyPress (key, PlayerIndex.Four, out playerIndex)); } } /// /// Helper for checking if a button was newly pressed during this update. /// The controllingPlayer parameter specifies which player to read input for. /// If this is null, it will accept input from any player. When a button press /// is detected, the output playerIndex reports which player pressed it. /// public bool IsNewButtonPress (Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex) { if (controllingPlayer.HasValue) { // Read input from the specified player. playerIndex = controllingPlayer.Value; int i = (int)playerIndex; return (CurrentGamePadStates [i].IsButtonDown (button) && LastGamePadStates [i].IsButtonUp (button)); } else { // Accept input from any player. return (IsNewButtonPress (button, PlayerIndex.One, out playerIndex) || IsNewButtonPress (button, PlayerIndex.Two, out playerIndex) || IsNewButtonPress (button, PlayerIndex.Three, out playerIndex) || IsNewButtonPress (button, PlayerIndex.Four, out playerIndex)); } } /// /// Checks for a "menu select" input action. /// The controllingPlayer parameter specifies which player to read input for. /// If this is null, it will accept input from any player. When the action /// is detected, the output playerIndex reports which player pressed it. /// public bool IsMenuSelect (PlayerIndex? controllingPlayer, out PlayerIndex playerIndex) { return IsNewKeyPress (Keys.Space, controllingPlayer, out playerIndex) || IsNewKeyPress (Keys.Enter, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.A, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.Start, controllingPlayer, out playerIndex); } /// /// Checks for a "menu cancel" input action. /// The controllingPlayer parameter specifies which player to read input for. /// If this is null, it will accept input from any player. When the action /// is detected, the output playerIndex reports which player pressed it. /// public bool IsMenuCancel (PlayerIndex? controllingPlayer, out PlayerIndex playerIndex) { return IsNewKeyPress (Keys.Escape, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.B, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.Back, controllingPlayer, out playerIndex); } /// /// Checks for a "menu up" input action. /// The controllingPlayer parameter specifies which player to read /// input for. If this is null, it will accept input from any player. /// public bool IsMenuUp (PlayerIndex? controllingPlayer) { PlayerIndex playerIndex; return IsNewKeyPress (Keys.Up, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.DPadUp, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.LeftThumbstickUp, controllingPlayer, out playerIndex); } /// /// Checks for a "menu down" input action. /// The controllingPlayer parameter specifies which player to read /// input for. If this is null, it will accept input from any player. /// public bool IsMenuDown (PlayerIndex? controllingPlayer) { PlayerIndex playerIndex; return IsNewKeyPress (Keys.Down, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.DPadDown, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.LeftThumbstickDown, controllingPlayer, out playerIndex); } /// /// Checks for a "pause the game" input action. /// The controllingPlayer parameter specifies which player to read /// input for. If this is null, it will accept input from any player. /// public bool IsPauseGame (PlayerIndex? controllingPlayer) { PlayerIndex playerIndex; return IsNewKeyPress (Keys.Escape, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.Back, controllingPlayer, out playerIndex) || IsNewButtonPress (Buttons.Start, controllingPlayer, out playerIndex); } #endregion } }