summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/Input/InputState.cs
blob: 8b0108ae7570a9ca0727474a3d142dccf46ae715 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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;
            }
        }
    }
}