diff options
Diffstat (limited to 'src/SMAPI/Framework/Input')
-rw-r--r-- | src/SMAPI/Framework/Input/GamePadStateBuilder.cs | 162 | ||||
-rw-r--r-- | src/SMAPI/Framework/Input/InputState.cs | 163 | ||||
-rw-r--r-- | src/SMAPI/Framework/Input/SInputState.cs | 382 |
3 files changed, 544 insertions, 163 deletions
diff --git a/src/SMAPI/Framework/Input/GamePadStateBuilder.cs b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs new file mode 100644 index 00000000..33557385 --- /dev/null +++ b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs @@ -0,0 +1,162 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Framework.Input +{ + /// <summary>An abstraction for manipulating controller state.</summary> + internal class GamePadStateBuilder + { + /********* + ** Properties + *********/ + /// <summary>The current button states.</summary> + private readonly IDictionary<SButton, ButtonState> ButtonStates; + + /// <summary>The left trigger value.</summary> + private float LeftTrigger; + + /// <summary>The right trigger value.</summary> + private float RightTrigger; + + /// <summary>The left thumbstick position.</summary> + private Vector2 LeftStickPos; + + /// <summary>The left thumbstick position.</summary> + private Vector2 RightStickPos; + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="state">The initial controller state.</param> + public GamePadStateBuilder(GamePadState state) + { + this.ButtonStates = new Dictionary<SButton, ButtonState> + { + [SButton.DPadUp] = state.DPad.Up, + [SButton.DPadDown] = state.DPad.Down, + [SButton.DPadLeft] = state.DPad.Left, + [SButton.DPadRight] = state.DPad.Right, + + [SButton.ControllerA] = state.Buttons.A, + [SButton.ControllerB] = state.Buttons.B, + [SButton.ControllerX] = state.Buttons.X, + [SButton.ControllerY] = state.Buttons.Y, + [SButton.LeftStick] = state.Buttons.LeftStick, + [SButton.RightStick] = state.Buttons.RightStick, + [SButton.LeftShoulder] = state.Buttons.LeftShoulder, + [SButton.RightShoulder] = state.Buttons.RightShoulder, + [SButton.ControllerBack] = state.Buttons.Back, + [SButton.ControllerStart] = state.Buttons.Start, + [SButton.BigButton] = state.Buttons.BigButton + }; + this.LeftTrigger = state.Triggers.Left; + this.RightTrigger = state.Triggers.Right; + this.LeftStickPos = state.ThumbSticks.Left; + this.RightStickPos = state.ThumbSticks.Right; + } + + /// <summary>Mark all matching buttons unpressed.</summary> + /// <param name="buttons">The buttons.</param> + public void SuppressButtons(IEnumerable<SButton> buttons) + { + foreach (SButton button in buttons) + this.SuppressButton(button); + } + + /// <summary>Mark a button unpressed.</summary> + /// <param name="button">The button.</param> + public void SuppressButton(SButton button) + { + switch (button) + { + // left thumbstick + case SButton.LeftThumbstickUp: + if (this.LeftStickPos.Y > 0) + this.LeftStickPos.Y = 0; + break; + case SButton.LeftThumbstickDown: + if (this.LeftStickPos.Y < 0) + this.LeftStickPos.Y = 0; + break; + case SButton.LeftThumbstickLeft: + if (this.LeftStickPos.X < 0) + this.LeftStickPos.X = 0; + break; + case SButton.LeftThumbstickRight: + if (this.LeftStickPos.X > 0) + this.LeftStickPos.X = 0; + break; + + // right thumbstick + case SButton.RightThumbstickUp: + if (this.RightStickPos.Y > 0) + this.RightStickPos.Y = 0; + break; + case SButton.RightThumbstickDown: + if (this.RightStickPos.Y < 0) + this.RightStickPos.Y = 0; + break; + case SButton.RightThumbstickLeft: + if (this.RightStickPos.X < 0) + this.RightStickPos.X = 0; + break; + case SButton.RightThumbstickRight: + if (this.RightStickPos.X > 0) + this.RightStickPos.X = 0; + break; + + // triggers + case SButton.LeftTrigger: + this.LeftTrigger = 0; + break; + case SButton.RightTrigger: + this.RightTrigger = 0; + break; + + // buttons + default: + if (this.ButtonStates.ContainsKey(button)) + this.ButtonStates[button] = ButtonState.Released; + break; + } + } + + /// <summary>Construct an equivalent gamepad state.</summary> + public GamePadState ToGamePadState() + { + return new GamePadState( + leftThumbStick: this.LeftStickPos, + rightThumbStick: this.RightStickPos, + leftTrigger: this.LeftTrigger, + rightTrigger: this.RightTrigger, + buttons: this.GetBitmask(this.GetPressedButtons()) // MonoDevelop requires one bitmask here; don't specify multiple values + ); + } + + /********* + ** Private methods + *********/ + /// <summary>Get all pressed buttons.</summary> + private IEnumerable<Buttons> GetPressedButtons() + { + foreach (var pair in this.ButtonStates) + { + if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button)) + yield return button; + } + } + + /// <summary>Get a bitmask representing the given buttons.</summary> + /// <param name="buttons">The buttons to represent.</param> + private Buttons GetBitmask(IEnumerable<Buttons> buttons) + { + Buttons flag = 0; + foreach (Buttons button in buttons) + flag |= button; + return flag; + } + } +} diff --git a/src/SMAPI/Framework/Input/InputState.cs b/src/SMAPI/Framework/Input/InputState.cs deleted file mode 100644 index 8b0108ae..00000000 --- a/src/SMAPI/Framework/Input/InputState.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; -using StardewValley; - -namespace StardewModdingAPI.Framework.Input -{ - /// <summary>A summary of input changes during an update frame.</summary> - internal class InputState - { - /********* - ** Accessors - *********/ - /// <summary>The underlying controller state.</summary> - public GamePadState ControllerState { get; } - - /// <summary>The underlying keyboard state.</summary> - public KeyboardState KeyboardState { get; } - - /// <summary>The underlying mouse state.</summary> - public MouseState MouseState { get; } - - /// <summary>The mouse position on the screen adjusted for the zoom level.</summary> - public Point MousePosition { get; } - - /// <summary>The buttons which were pressed, held, or released.</summary> - public IDictionary<SButton, InputStatus> ActiveButtons { get; } = new Dictionary<SButton, InputStatus>(); - - - /********* - ** Public methods - *********/ - /// <summary>Construct an empty instance.</summary> - public InputState() { } - - /// <summary>Construct an instance.</summary> - /// <param name="previousState">The previous input state.</param> - /// <param name="controllerState">The current controller state.</param> - /// <param name="keyboardState">The current keyboard state.</param> - /// <param name="mouseState">The current mouse state.</param> - public InputState(InputState previousState, GamePadState controllerState, KeyboardState keyboardState, MouseState mouseState) - { - // init properties - this.ControllerState = controllerState; - this.KeyboardState = keyboardState; - this.MouseState = mouseState; - this.MousePosition = new Point((int)(mouseState.X * (1.0 / Game1.options.zoomLevel)), (int)(mouseState.Y * (1.0 / Game1.options.zoomLevel))); // derived from Game1::getMouseX - - // get button states - SButton[] down = InputState.GetPressedButtons(keyboardState, mouseState, controllerState).ToArray(); - foreach (SButton button in down) - this.ActiveButtons[button] = this.GetStatus(previousState.GetStatus(button), isDown: true); - foreach (KeyValuePair<SButton, InputStatus> prev in previousState.ActiveButtons) - { - if (prev.Value.IsDown() && !this.ActiveButtons.ContainsKey(prev.Key)) - this.ActiveButtons[prev.Key] = InputStatus.Released; - } - } - - /// <summary>Get the status of a button.</summary> - /// <param name="button">The button to check.</param> - public InputStatus GetStatus(SButton button) - { - return this.ActiveButtons.TryGetValue(button, out InputStatus status) ? status : InputStatus.None; - } - - /// <summary>Get whether a given button was pressed or held.</summary> - /// <param name="button">The button to check.</param> - public bool IsDown(SButton button) - { - return this.GetStatus(button).IsDown(); - } - - /// <summary>Get the current input state.</summary> - /// <param name="previousState">The previous input state.</param> - public static InputState GetState(InputState previousState) - { - GamePadState controllerState = GamePad.GetState(PlayerIndex.One); - KeyboardState keyboardState = Keyboard.GetState(); - MouseState mouseState = Mouse.GetState(); - - return new InputState(previousState, controllerState, keyboardState, mouseState); - } - - /********* - ** Private methods - *********/ - /// <summary>Get the status of a button.</summary> - /// <param name="oldStatus">The previous button status.</param> - /// <param name="isDown">Whether the button is currently down.</param> - public InputStatus GetStatus(InputStatus oldStatus, bool isDown) - { - if (isDown && oldStatus.IsDown()) - return InputStatus.Held; - if (isDown) - return InputStatus.Pressed; - return InputStatus.Released; - } - - /// <summary>Get the buttons pressed in the given stats.</summary> - /// <param name="keyboard">The keyboard state.</param> - /// <param name="mouse">The mouse state.</param> - /// <param name="controller">The controller state.</param> - private static IEnumerable<SButton> GetPressedButtons(KeyboardState keyboard, MouseState mouse, GamePadState controller) - { - // keyboard - foreach (Keys key in keyboard.GetPressedKeys()) - yield return key.ToSButton(); - - // mouse - if (mouse.LeftButton == ButtonState.Pressed) - yield return SButton.MouseLeft; - if (mouse.RightButton == ButtonState.Pressed) - yield return SButton.MouseRight; - if (mouse.MiddleButton == ButtonState.Pressed) - yield return SButton.MouseMiddle; - if (mouse.XButton1 == ButtonState.Pressed) - yield return SButton.MouseX1; - if (mouse.XButton2 == ButtonState.Pressed) - yield return SButton.MouseX2; - - // controller - if (controller.IsConnected) - { - if (controller.Buttons.A == ButtonState.Pressed) - yield return SButton.ControllerA; - if (controller.Buttons.B == ButtonState.Pressed) - yield return SButton.ControllerB; - if (controller.Buttons.Back == ButtonState.Pressed) - yield return SButton.ControllerBack; - if (controller.Buttons.BigButton == ButtonState.Pressed) - yield return SButton.BigButton; - if (controller.Buttons.LeftShoulder == ButtonState.Pressed) - yield return SButton.LeftShoulder; - if (controller.Buttons.LeftStick == ButtonState.Pressed) - yield return SButton.LeftStick; - if (controller.Buttons.RightShoulder == ButtonState.Pressed) - yield return SButton.RightShoulder; - if (controller.Buttons.RightStick == ButtonState.Pressed) - yield return SButton.RightStick; - if (controller.Buttons.Start == ButtonState.Pressed) - yield return SButton.ControllerStart; - if (controller.Buttons.X == ButtonState.Pressed) - yield return SButton.ControllerX; - if (controller.Buttons.Y == ButtonState.Pressed) - yield return SButton.ControllerY; - if (controller.DPad.Up == ButtonState.Pressed) - yield return SButton.DPadUp; - if (controller.DPad.Down == ButtonState.Pressed) - yield return SButton.DPadDown; - if (controller.DPad.Left == ButtonState.Pressed) - yield return SButton.DPadLeft; - if (controller.DPad.Right == ButtonState.Pressed) - yield return SButton.DPadRight; - if (controller.Triggers.Left > 0.2f) - yield return SButton.LeftTrigger; - if (controller.Triggers.Right > 0.2f) - yield return SButton.RightTrigger; - } - } - } -} diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs new file mode 100644 index 00000000..0228db0d --- /dev/null +++ b/src/SMAPI/Framework/Input/SInputState.cs @@ -0,0 +1,382 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using StardewValley; + +#pragma warning disable 809 // obsolete override of non-obsolete method (this is deliberate) +namespace StardewModdingAPI.Framework.Input +{ + /// <summary>Manages the game's input state.</summary> + internal sealed class SInputState : InputState + { + /********* + ** Accessors + *********/ + /// <summary>The maximum amount of direction to ignore for the left thumbstick.</summary> + private const float LeftThumbstickDeadZone = 0.2f; + + /// <summary>The cursor position on the screen adjusted for the zoom level.</summary> + private CursorPosition CursorPositionImpl; + + + /********* + ** Accessors + *********/ + /// <summary>The controller state as of the last update.</summary> + public GamePadState RealController { get; private set; } + + /// <summary>The keyboard state as of the last update.</summary> + public KeyboardState RealKeyboard { get; private set; } + + /// <summary>The mouse state as of the last update.</summary> + public MouseState RealMouse { get; private set; } + + /// <summary>A derivative of <see cref="RealController"/> which suppresses the buttons in <see cref="SuppressButtons"/>.</summary> + public GamePadState SuppressedController { get; private set; } + + /// <summary>A derivative of <see cref="RealKeyboard"/> which suppresses the buttons in <see cref="SuppressButtons"/>.</summary> + public KeyboardState SuppressedKeyboard { get; private set; } + + /// <summary>A derivative of <see cref="RealMouse"/> which suppresses the buttons in <see cref="SuppressButtons"/>.</summary> + public MouseState SuppressedMouse { get; private set; } + + /// <summary>The cursor position on the screen adjusted for the zoom level.</summary> + public ICursorPosition CursorPosition => this.CursorPositionImpl; + + /// <summary>The buttons which were pressed, held, or released.</summary> + public IDictionary<SButton, InputStatus> ActiveButtons { get; private set; } = new Dictionary<SButton, InputStatus>(); + + /// <summary>The buttons to suppress when the game next handles input. Each button is suppressed until it's released.</summary> + public HashSet<SButton> SuppressButtons { get; } = new HashSet<SButton>(); + + + /********* + ** Public methods + *********/ + /// <summary>Get a copy of the current state.</summary> + public SInputState Clone() + { + return new SInputState + { + ActiveButtons = this.ActiveButtons, + RealController = this.RealController, + RealKeyboard = this.RealKeyboard, + RealMouse = this.RealMouse, + CursorPositionImpl = this.CursorPositionImpl + }; + } + + /// <summary>This method is called by the game, and does nothing since SMAPI will already have updated by that point.</summary> + [Obsolete("This method should only be called by the game itself.")] + public override void Update() { } + + /// <summary>Update the current button statuses for the given tick.</summary> + public void TrueUpdate() + { + try + { + // get new states + GamePadState realController = GamePad.GetState(PlayerIndex.One); + KeyboardState realKeyboard = Keyboard.GetState(); + MouseState realMouse = Mouse.GetState(); + var activeButtons = this.DeriveStatuses(this.ActiveButtons, realKeyboard, realMouse, realController); + Vector2 cursorAbsolutePos = new Vector2(realMouse.X + Game1.viewport.X, realMouse.Y + Game1.viewport.Y); + + // update real states + this.ActiveButtons = activeButtons; + this.RealController = realController; + this.RealKeyboard = realKeyboard; + this.RealMouse = realMouse; + if (this.CursorPositionImpl?.AbsolutePixels != cursorAbsolutePos) + this.CursorPositionImpl = this.GetCursorPosition(realMouse, cursorAbsolutePos); + + // update suppressed states + this.SuppressButtons.RemoveWhere(p => !this.GetStatus(activeButtons, p).IsDown()); + this.UpdateSuppression(); + } + catch (InvalidOperationException) + { + // GetState() may crash for some players if window doesn't have focus but game1.IsActive == true + } + } + + /// <summary>Apply input suppression to current input.</summary> + public void UpdateSuppression() + { + GamePadState suppressedController = this.RealController; + KeyboardState suppressedKeyboard = this.RealKeyboard; + MouseState suppressedMouse = this.RealMouse; + + this.SuppressGivenStates(this.ActiveButtons, ref suppressedKeyboard, ref suppressedMouse, ref suppressedController); + + this.SuppressedController = suppressedController; + this.SuppressedKeyboard = suppressedKeyboard; + this.SuppressedMouse = suppressedMouse; + } + + /// <summary>Get the gamepad state visible to the game.</summary> + [Obsolete("This method should only be called by the game itself.")] + public override GamePadState GetGamePadState() + { + return this.ShouldSuppressNow() + ? this.SuppressedController + : this.RealController; + } + + /// <summary>Get the keyboard state visible to the game.</summary> + [Obsolete("This method should only be called by the game itself.")] + public override KeyboardState GetKeyboardState() + { + return this.ShouldSuppressNow() + ? this.SuppressedKeyboard + : this.RealKeyboard; + } + + /// <summary>Get the keyboard state visible to the game.</summary> + [Obsolete("This method should only be called by the game itself.")] + public override MouseState GetMouseState() + { + return this.ShouldSuppressNow() + ? this.SuppressedMouse + : this.RealMouse; + } + + /// <summary>Get whether a given button was pressed or held.</summary> + /// <param name="button">The button to check.</param> + public bool IsDown(SButton button) + { + return this.GetStatus(this.ActiveButtons, button).IsDown(); + } + + /// <summary>Get whether any of the given buttons were pressed or held.</summary> + /// <param name="buttons">The buttons to check.</param> + public bool IsAnyDown(InputButton[] buttons) + { + return buttons.Any(button => this.IsDown(button.ToSButton())); + } + + + /********* + ** Private methods + *********/ + /// <summary>Get the current cursor position.</summary> + /// <param name="mouseState">The current mouse state.</param> + /// <param name="absolutePixels">The absolute pixel position relative to the map.</param> + private CursorPosition GetCursorPosition(MouseState mouseState, Vector2 absolutePixels) + { + Vector2 rawPixels = new Vector2(mouseState.X, mouseState.Y); + Vector2 screenPixels = rawPixels * new Vector2((float)1.0 / Game1.options.zoomLevel); // derived from Game1::getMouseX + Vector2 tile = new Vector2((int)((Game1.viewport.X + screenPixels.X) / Game1.tileSize), (int)((Game1.viewport.Y + screenPixels.Y) / Game1.tileSize)); + Vector2 grabTile = (Game1.mouseCursorTransparency > 0 && Utility.tileWithinRadiusOfPlayer((int)tile.X, (int)tile.Y, 1, Game1.player)) // derived from Game1.pressActionButton + ? tile + : Game1.player.GetGrabTile(); + return new CursorPosition(absolutePixels, screenPixels, tile, grabTile); + } + + /// <summary>Whether input should be suppressed in the current context.</summary> + private bool ShouldSuppressNow() + { + return Game1.chatBox == null || !Game1.chatBox.isActive(); + } + + /// <summary>Apply input suppression to the given input states.</summary> + /// <param name="activeButtons">The current button states to check.</param> + /// <param name="keyboardState">The game's keyboard state for the current tick.</param> + /// <param name="mouseState">The game's mouse state for the current tick.</param> + /// <param name="gamePadState">The game's controller state for the current tick.</param> + private void SuppressGivenStates(IDictionary<SButton, InputStatus> activeButtons, ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState) + { + if (this.SuppressButtons.Count == 0) + return; + + // gather info + HashSet<Keys> suppressKeys = new HashSet<Keys>(); + HashSet<SButton> suppressButtons = new HashSet<SButton>(); + HashSet<SButton> suppressMouse = new HashSet<SButton>(); + foreach (SButton button in this.SuppressButtons) + { + if (button == SButton.MouseLeft || button == SButton.MouseMiddle || button == SButton.MouseRight || button == SButton.MouseX1 || button == SButton.MouseX2) + suppressMouse.Add(button); + else if (button.TryGetKeyboard(out Keys key)) + suppressKeys.Add(key); + else if (gamePadState.IsConnected && button.TryGetController(out Buttons _)) + suppressButtons.Add(button); + } + + // suppress keyboard keys + if (keyboardState.GetPressedKeys().Any() && suppressKeys.Any()) + keyboardState = new KeyboardState(keyboardState.GetPressedKeys().Except(suppressKeys).ToArray()); + + // suppress controller keys + if (gamePadState.IsConnected && suppressButtons.Any()) + { + GamePadStateBuilder builder = new GamePadStateBuilder(gamePadState); + builder.SuppressButtons(suppressButtons); + gamePadState = builder.ToGamePadState(); + } + + // suppress mouse buttons + if (suppressMouse.Any()) + { + mouseState = new MouseState( + x: mouseState.X, + y: mouseState.Y, + scrollWheel: mouseState.ScrollWheelValue, + leftButton: suppressMouse.Contains(SButton.MouseLeft) ? ButtonState.Released : mouseState.LeftButton, + middleButton: suppressMouse.Contains(SButton.MouseMiddle) ? ButtonState.Released : mouseState.MiddleButton, + rightButton: suppressMouse.Contains(SButton.MouseRight) ? ButtonState.Released : mouseState.RightButton, + xButton1: suppressMouse.Contains(SButton.MouseX1) ? ButtonState.Released : mouseState.XButton1, + xButton2: suppressMouse.Contains(SButton.MouseX2) ? ButtonState.Released : mouseState.XButton2 + ); + } + } + + /// <summary>Get the status of all pressed or released buttons relative to their previous status.</summary> + /// <param name="previousStatuses">The previous button statuses.</param> + /// <param name="keyboard">The keyboard state.</param> + /// <param name="mouse">The mouse state.</param> + /// <param name="controller">The controller state.</param> + private IDictionary<SButton, InputStatus> DeriveStatuses(IDictionary<SButton, InputStatus> previousStatuses, KeyboardState keyboard, MouseState mouse, GamePadState controller) + { + IDictionary<SButton, InputStatus> activeButtons = new Dictionary<SButton, InputStatus>(); + + // handle pressed keys + SButton[] down = this.GetPressedButtons(keyboard, mouse, controller).ToArray(); + foreach (SButton button in down) + activeButtons[button] = this.DeriveStatus(this.GetStatus(previousStatuses, button), isDown: true); + + // handle released keys + foreach (KeyValuePair<SButton, InputStatus> prev in previousStatuses) + { + if (prev.Value.IsDown() && !activeButtons.ContainsKey(prev.Key)) + activeButtons[prev.Key] = InputStatus.Released; + } + + return activeButtons; + } + + /// <summary>Get the status of a button relative to its previous status.</summary> + /// <param name="oldStatus">The previous button status.</param> + /// <param name="isDown">Whether the button is currently down.</param> + private InputStatus DeriveStatus(InputStatus oldStatus, bool isDown) + { + if (isDown && oldStatus.IsDown()) + return InputStatus.Held; + if (isDown) + return InputStatus.Pressed; + return InputStatus.Released; + } + + /// <summary>Get the status of a button.</summary> + /// <param name="activeButtons">The current button states to check.</param> + /// <param name="button">The button to check.</param> + private InputStatus GetStatus(IDictionary<SButton, InputStatus> activeButtons, SButton button) + { + return activeButtons.TryGetValue(button, out InputStatus status) ? status : InputStatus.None; + } + + /// <summary>Get the buttons pressed in the given stats.</summary> + /// <param name="keyboard">The keyboard state.</param> + /// <param name="mouse">The mouse state.</param> + /// <param name="controller">The controller state.</param> + /// <remarks>Thumbstick direction logic derived from <see cref="ButtonCollection"/>.</remarks> + private IEnumerable<SButton> GetPressedButtons(KeyboardState keyboard, MouseState mouse, GamePadState controller) + { + // keyboard + foreach (Keys key in keyboard.GetPressedKeys()) + yield return key.ToSButton(); + + // mouse + if (mouse.LeftButton == ButtonState.Pressed) + yield return SButton.MouseLeft; + if (mouse.RightButton == ButtonState.Pressed) + yield return SButton.MouseRight; + if (mouse.MiddleButton == ButtonState.Pressed) + yield return SButton.MouseMiddle; + if (mouse.XButton1 == ButtonState.Pressed) + yield return SButton.MouseX1; + if (mouse.XButton2 == ButtonState.Pressed) + yield return SButton.MouseX2; + + // controller + if (controller.IsConnected) + { + // main buttons + if (controller.Buttons.A == ButtonState.Pressed) + yield return SButton.ControllerA; + if (controller.Buttons.B == ButtonState.Pressed) + yield return SButton.ControllerB; + if (controller.Buttons.X == ButtonState.Pressed) + yield return SButton.ControllerX; + if (controller.Buttons.Y == ButtonState.Pressed) + yield return SButton.ControllerY; + if (controller.Buttons.LeftStick == ButtonState.Pressed) + yield return SButton.LeftStick; + if (controller.Buttons.RightStick == ButtonState.Pressed) + yield return SButton.RightStick; + if (controller.Buttons.Start == ButtonState.Pressed) + yield return SButton.ControllerStart; + + // directional pad + if (controller.DPad.Up == ButtonState.Pressed) + yield return SButton.DPadUp; + if (controller.DPad.Down == ButtonState.Pressed) + yield return SButton.DPadDown; + if (controller.DPad.Left == ButtonState.Pressed) + yield return SButton.DPadLeft; + if (controller.DPad.Right == ButtonState.Pressed) + yield return SButton.DPadRight; + + // secondary buttons + if (controller.Buttons.Back == ButtonState.Pressed) + yield return SButton.ControllerBack; + if (controller.Buttons.BigButton == ButtonState.Pressed) + yield return SButton.BigButton; + + // shoulders + if (controller.Buttons.LeftShoulder == ButtonState.Pressed) + yield return SButton.LeftShoulder; + if (controller.Buttons.RightShoulder == ButtonState.Pressed) + yield return SButton.RightShoulder; + + // triggers + if (controller.Triggers.Left > 0.2f) + yield return SButton.LeftTrigger; + if (controller.Triggers.Right > 0.2f) + yield return SButton.RightTrigger; + + // left thumbstick direction + if (controller.ThumbSticks.Left.Y > SInputState.LeftThumbstickDeadZone) + yield return SButton.LeftThumbstickUp; + if (controller.ThumbSticks.Left.Y < -SInputState.LeftThumbstickDeadZone) + yield return SButton.LeftThumbstickDown; + if (controller.ThumbSticks.Left.X > SInputState.LeftThumbstickDeadZone) + yield return SButton.LeftThumbstickRight; + if (controller.ThumbSticks.Left.X < -SInputState.LeftThumbstickDeadZone) + yield return SButton.LeftThumbstickLeft; + + // right thumbstick direction + if (this.IsRightThumbstickOutsideDeadZone(controller.ThumbSticks.Right)) + { + if (controller.ThumbSticks.Right.Y > 0) + yield return SButton.RightThumbstickUp; + if (controller.ThumbSticks.Right.Y < 0) + yield return SButton.RightThumbstickDown; + if (controller.ThumbSticks.Right.X > 0) + yield return SButton.RightThumbstickRight; + if (controller.ThumbSticks.Right.X < 0) + yield return SButton.RightThumbstickLeft; + } + } + } + + /// <summary>Get whether the right thumbstick should be considered outside the dead zone.</summary> + /// <param name="direction">The right thumbstick value.</param> + private bool IsRightThumbstickOutsideDeadZone(Vector2 direction) + { + return direction.Length() > 0.9f; + } + } +} |