| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 | //-----------------------------------------------------------------------------// InputState.cs//// Microsoft XNA Community Game Platform// Copyright (C) Microsoft Corporation. All rights reserved.//-----------------------------------------------------------------------------using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Input;using Microsoft.Xna.Framework.Input.Touch;using System;using System.Collections.Generic;namespace CardsFramework{    /// <summary>    /// 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".    /// </summary>    public class InputState    {        public const int MaxInputs = 4; // Maximum number of supported input devices (e.g., players)        // Current Inputstates - Tracks the latest state of all input devices        public readonly GamePadState[] CurrentGamePadStates;        public readonly KeyboardState[] CurrentKeyboardStates;        public MouseState CurrentMouseState;        private int touchCount; // Number of active touch inputs        public TouchCollection CurrentTouchState;        // Last Inputstates - Stores the previous frame's input states for detecting changes        public readonly GamePadState[] LastGamePadStates;        public readonly KeyboardState[] LastKeyboardStates;        public MouseState LastMouseState;        public TouchCollection LastTouchState;        public readonly List<GestureSample> Gestures = new List<GestureSample>(); // Stores touch gestures        public readonly bool[] GamePadWasConnected;        /// <summary>        /// Cursor move speed in pixels per second        /// </summary>        private const float cursorMoveSpeed = 250.0f;        private Vector2 currentCursorLocation;        /// <summary>        /// Current location of our Cursor        /// </summary>        public Vector2 CurrentCursorLocation => currentCursorLocation;        private Vector2 lastCursorLocation;        /// <summary>        /// Current location of our Cursor        /// </summary>        public Vector2 LastCursorLocation => lastCursorLocation;        private bool isMouseWheelScrolledDown;        /// <summary>        /// Has the user scrolled the mouse wheel down?        /// </summary>        public bool IsMouseWheelScrolledDown => isMouseWheelScrolledDown;        private bool isMouseWheelScrolledUp;        private Matrix inputTransformation; // Used to transform input coordinates between screen and game space        private float baseBufferWidth;        private float baseBufferHeight;        /// <summary>        /// Has the user scrolled the mouse wheel up?        /// </summary>        public bool IsMouseWheelScrolledUp => isMouseWheelScrolledUp;        /// <summary>        /// Constructs a new input state.        /// </summary>        public InputState(float baseBufferWidth, float baseBufferHeight)        {            this.baseBufferWidth = baseBufferWidth;            this.baseBufferHeight = baseBufferHeight;            // Initialize arrays for multiple controller/keyboard states            CurrentKeyboardStates = new KeyboardState[MaxInputs];            CurrentGamePadStates = new GamePadState[MaxInputs];            LastKeyboardStates = new KeyboardState[MaxInputs];            LastGamePadStates = new GamePadState[MaxInputs];            GamePadWasConnected = new bool[MaxInputs];            // Configure platform-specific input options            if (UIUtility.IsMobile)            {                TouchPanel.EnabledGestures = GestureType.Tap;            }            else if (UIUtility.IsDesktop)            {                // No desktop-specific initialization needed            }            else            {                // For now, we'll throw an exception if we don't know the platform                throw new PlatformNotSupportedException();            }        }        /// <summary>        /// Reads the latest state of the keyboard and gamepad.        /// </summary>        public void Update(GameTime gameTime)        {            // Update keyboard and gamepad states for all players            for (int i = 0; i < MaxInputs; i++)            {                LastKeyboardStates[i] = CurrentKeyboardStates[i];                LastGamePadStates[i] = CurrentGamePadStates[i];                CurrentKeyboardStates[i] = Keyboard.GetState();                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;                }            }            // Update mouse state            LastMouseState = CurrentMouseState;            CurrentMouseState = Mouse.GetState();            // Update touch state            touchCount = 0;            LastTouchState = CurrentTouchState;            CurrentTouchState = TouchPanel.GetState();            // Process all available gestures            Gestures.Clear();            while (TouchPanel.IsGestureAvailable)            {                Gestures.Add(TouchPanel.ReadGesture());            }            // Process touch inputs            foreach (TouchLocation location in CurrentTouchState)            {                switch (location.State)                {                    case TouchLocationState.Pressed:                        touchCount++;                        lastCursorLocation = currentCursorLocation;                        // Transform touch position to game coordinates                        currentCursorLocation = TransformCursorLocation(location.Position);                        break;                    case TouchLocationState.Moved:                        break;                    case TouchLocationState.Released:                        break;                }            }            // Handle mouse clicks as touch equivalents            if (IsLeftMouseButtonClicked())            {                lastCursorLocation = currentCursorLocation;                // Transform mouse position to game coordinates                currentCursorLocation = TransformCursorLocation(new Vector2(CurrentMouseState.X, CurrentMouseState.Y));                touchCount = 1;            }            if (IsMiddleMouseButtonClicked())            {                touchCount = 2; // Treat middle mouse click as double touch            }            if (IsRightMoustButtonClicked())            {                touchCount = 3; // Treat right mouse click as triple touch            }            // Reset mouse wheel flags            isMouseWheelScrolledUp = false;            isMouseWheelScrolledDown = false;            // Detect mouse wheel scrolling            if (CurrentMouseState.ScrollWheelValue != LastMouseState.ScrollWheelValue)            {                int scrollWheelDelta = CurrentMouseState.ScrollWheelValue - LastMouseState.ScrollWheelValue;                // Handle the scroll wheel event based on the delta                if (scrollWheelDelta > 0)                {                    // Mouse wheel scrolled up                    isMouseWheelScrolledUp = true;                }                else if (scrollWheelDelta < 0)                {                    // Mouse wheel scrolled down                    isMouseWheelScrolledDown = true;                }            }            // Update the cursor location using gamepad and keyboard            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;            // Move cursor with 1st gamepad thumbstick            if (CurrentGamePadStates[0].IsConnected)            {                lastCursorLocation = currentCursorLocation;                currentCursorLocation.X += CurrentGamePadStates[0].ThumbSticks.Left.X * elapsedTime * cursorMoveSpeed;                currentCursorLocation.Y -= CurrentGamePadStates[0].ThumbSticks.Left.Y * elapsedTime * cursorMoveSpeed;            }            // Keep cursor within bounds            currentCursorLocation.X = MathHelper.Clamp(currentCursorLocation.X, 0f, baseBufferWidth);            currentCursorLocation.Y = MathHelper.Clamp(currentCursorLocation.Y, 0f, baseBufferHeight);        }        /// <summary>        /// Checks if left mouse button was clicked (pressed and then released)        /// </summary>        /// <returns>True if left mouse button was clicked, false otherwise.</returns>        internal bool IsLeftMouseButtonClicked()        {            return CurrentMouseState.LeftButton == ButtonState.Released && LastMouseState.LeftButton == ButtonState.Pressed;        }        /// <summary>        /// Checks if middle mouse button was clicked (pressed and then released)        /// </summary>        /// <returns>True if middle mouse button was clicked, false otherwise.</returns>        internal bool IsMiddleMouseButtonClicked()        {            return CurrentMouseState.MiddleButton == ButtonState.Released && LastMouseState.MiddleButton == ButtonState.Pressed;        }        /// <summary>        /// Checks if right mouse button was clicked (pressed and then released)        /// </summary>        /// <returns>True if right mouse button was clicked, false otherwise.</returns>        internal bool IsRightMoustButtonClicked()        {            return CurrentMouseState.RightButton == ButtonState.Released && LastMouseState.RightButton == ButtonState.Pressed;        }        /// <summary>        /// 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.        /// </summary>        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));            }        }        /// <summary>        /// 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.        /// </summary>        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));            }        }        /// <summary>        /// 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.        /// </summary>        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);        }        /// <summary>        /// 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.        /// </summary>        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);        }        /// <summary>        /// 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.        /// </summary>        public bool IsMenuUp(PlayerIndex? controllingPlayer)        {            PlayerIndex playerIndex;            return IsNewKeyPress(Keys.Up, controllingPlayer, out playerIndex) ||                   IsNewKeyPress(Keys.Left, controllingPlayer, out playerIndex) ||                   IsNewButtonPress(Buttons.DPadLeft, controllingPlayer, out playerIndex) ||                   IsNewButtonPress(Buttons.LeftThumbstickLeft, controllingPlayer, out playerIndex);        }        /// <summary>        /// 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.        /// </summary>        public bool IsMenuDown(PlayerIndex? controllingPlayer)        {            PlayerIndex playerIndex;            return IsNewKeyPress(Keys.Down, controllingPlayer, out playerIndex) ||                   IsNewKeyPress(Keys.Right, controllingPlayer, out playerIndex) ||                   IsNewButtonPress(Buttons.DPadRight, controllingPlayer, out playerIndex) ||                   IsNewButtonPress(Buttons.LeftThumbstickRight, controllingPlayer, out playerIndex);        }        /// <summary>        /// 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.        /// </summary>        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);        }        /// <summary>        /// Updates the matrix used to transform input coordinates.        /// </summary>        /// <param name="inputTransformation">The transformation matrix to apply.</param>        public void UpdateInputTransformation(Matrix inputTransformation)        {            this.inputTransformation = inputTransformation;        }        /// <summary>        /// Transforms touch/mouse positions from screen space to game space.        /// </summary>        /// <param name="mousePosition">The screen-space position to transform.</param>        /// <returns>The transformed position in game space.</returns>        public Vector2 TransformCursorLocation(Vector2 mousePosition)        {            // Transform back to cursor location            return Vector2.Transform(mousePosition, inputTransformation);        }    }}
 |