A game about forced loneliness, made by TACStudios
1using System;
2using System.ComponentModel;
3using System.Runtime.InteropServices;
4using UnityEngine.InputSystem.Controls;
5using UnityEngine.InputSystem.Haptics;
6using UnityEngine.InputSystem.Layouts;
7using UnityEngine.InputSystem.LowLevel;
8using UnityEngine.InputSystem.Utilities;
9using UnityEngine.Scripting;
10
11////TODO: come up with consistent naming for buttons; (xxxButton? xxx?)
12
13////REVIEW: should we add a gyro as a standard feature of gamepads?
14
15////TODO: allow to be used for mouse simulation
16
17namespace UnityEngine.InputSystem.LowLevel
18{
19 /// <summary>
20 /// Default state layout for gamepads.
21 /// </summary>
22 /// <remarks>
23 /// Be aware that unlike some other devices such as <see cref="Mouse"/> or <see cref="Touchscreen"/>,
24 /// gamepad devices tend to have wildly varying state formats, i.e. forms in which they internally
25 /// store their input data. In practice, even on the same platform gamepads will often store
26 /// their data in different formats. This means that <see cref="GamepadState"/> will often <em>not</em>
27 /// be the format in which a particular gamepad (such as <see cref="XInput.XInputController"/>,
28 /// for example) stores its data.
29 ///
30 /// If your gamepad data is arriving in a different format, you should extend the "Gamepad" layout and customize its Controls.
31 ///
32 /// A real-world example of this is the Xbox Controller on macOS, which is supported through HID. Its layout looks like this:
33 ///
34 /// <example>
35 /// <code>
36 /// {
37 /// "name" : "XboxGamepadOSX",
38 /// "extend" : "Gamepad",
39 /// "format" : "HID",
40 /// "device" : { "interface" : "HID", "product" : "Xbox.*Controller" },
41 /// "controls" : [
42 /// { "name" : "leftShoulder", "offset" : 2, "bit" : 8 },
43 /// { "name" : "rightShoulder", "offset" : 2, "bit" : 9 },
44 /// { "name" : "leftStickPress", "offset" : 2, "bit" : 14 },
45 /// { "name" : "rightStickPress", "offset" : 2, "bit" : 15 },
46 /// { "name" : "buttonSouth", "offset" : 2, "bit" : 12 },
47 /// { "name" : "buttonEast", "offset" : 2, "bit" : 13 },
48 /// { "name" : "buttonWest", "offset" : 2, "bit" : 14 },
49 /// { "name" : "buttonNorth", "offset" : 2, "bit" : 15 },
50 /// { "name" : "dpad", "offset" : 2 },
51 /// { "name" : "dpad/up", "offset" : 0, "bit" : 8 },
52 /// { "name" : "dpad/down", "offset" : 0, "bit" : 9 },
53 /// { "name" : "dpad/left", "offset" : 0, "bit" : 10 },
54 /// { "name" : "dpad/right", "offset" : 0, "bit" : 11 },
55 /// { "name" : "start", "offset" : 2, "bit" : 4 },
56 /// { "name" : "select", "offset" : 2, "bit" : 5 },
57 /// { "name" : "xbox", "offset" : 2, "bit" : 2, "layout" : "Button" },
58 /// { "name" : "leftTrigger", "offset" : 4, "format" : "BYTE" },
59 /// { "name" : "rightTrigger", "offset" : 5, "format" : "BYTE" },
60 /// { "name" : "leftStick", "offset" : 6, "format" : "VC2S" },
61 /// { "name" : "leftStick/x", "offset" : 0, "format" : "SHRT", "parameters" : "normalize,normalizeMin=-0.5,normalizeMax=0.5" },
62 /// { "name" : "leftStick/y", "offset" : 2, "format" : "SHRT", "parameters" : "invert,normalize,normalizeMin=-0.5,normalizeMax=0.5" },
63 /// { "name" : "rightStick", "offset" : 10, "format" : "VC2S" },
64 /// { "name" : "rightStick/x", "offset" : 0, "format" : "SHRT", "parameters" : "normalize,normalizeMin=-0.5,normalizeMax=0.5" },
65 /// { "name" : "rightStick/y", "offset" : 2, "format" : "SHRT", "parameters" : "invert,normalize,normalizeMin=-0.5,normalizeMax=0.5" }
66 /// ]
67 /// }
68 /// </code>
69 /// </example>
70 ///
71 /// The same principle applies if some buttons on your Device are swapped, for example. In this case, you can remap their offsets.
72 ///
73 ///
74 ///
75 ///
76 /// </remarks>
77 /// <seealso cref="Gamepad"/>
78 // NOTE: Must match GamepadInputState in native.
79 [StructLayout(LayoutKind.Explicit, Size = 28)]
80 public struct GamepadState : IInputStateTypeInfo
81 {
82 public static FourCC Format => new FourCC('G', 'P', 'A', 'D');
83
84 // On Sony consoles, we use the platform defaults as the gamepad-wide short default names.
85 #if UNITY_PS4 || UNITY_PS5
86 internal const string ButtonSouthShortDisplayName = "Cross";
87 internal const string ButtonNorthShortDisplayName = "Triangle";
88 internal const string ButtonWestShortDisplayName = "Square";
89 internal const string ButtonEastShortDisplayName = "Circle";
90 #elif UNITY_SWITCH
91 internal const string ButtonSouthShortDisplayName = "B";
92 internal const string ButtonNorthShortDisplayName = "X";
93 internal const string ButtonWestShortDisplayName = "Y";
94 internal const string ButtonEastShortDisplayName = "A";
95 #else
96 internal const string ButtonSouthShortDisplayName = "A";
97 internal const string ButtonNorthShortDisplayName = "Y";
98 internal const string ButtonWestShortDisplayName = "X";
99 internal const string ButtonEastShortDisplayName = "B";
100 #endif
101
102 /// <summary>
103 /// Button bit mask.
104 /// </summary>
105 /// <value>Button bit mask.</value>
106 /// <seealso cref="GamepadButton"/>
107 /// <seealso cref="Gamepad.buttonSouth"/>
108 /// <seealso cref="Gamepad.buttonNorth"/>
109 /// <seealso cref="Gamepad.buttonWest"/>
110 /// <seealso cref="Gamepad.buttonSouth"/>
111 /// <seealso cref="Gamepad.leftShoulder"/>
112 /// <seealso cref="Gamepad.rightShoulder"/>
113 /// <seealso cref="Gamepad.startButton"/>
114 /// <seealso cref="Gamepad.selectButton"/>
115 /// <seealso cref="Gamepad.leftStickButton"/>
116 /// <seealso cref="Gamepad.rightStickButton"/>
117 ////REVIEW: do we want the name to correspond to what's actually on the device?
118 [InputControl(name = "dpad", layout = "Dpad", usage = "Hatswitch", displayName = "D-Pad", format = "BIT", sizeInBits = 4, bit = 0)]
119 [InputControl(name = "buttonSouth", layout = "Button", bit = (uint)GamepadButton.South, usages = new[] { "PrimaryAction", "Submit" }, aliases = new[] { "a", "cross" }, displayName = "Button South", shortDisplayName = ButtonSouthShortDisplayName)]
120 [InputControl(name = "buttonWest", layout = "Button", bit = (uint)GamepadButton.West, usage = "SecondaryAction", aliases = new[] { "x", "square" }, displayName = "Button West", shortDisplayName = ButtonWestShortDisplayName)]
121 [InputControl(name = "buttonNorth", layout = "Button", bit = (uint)GamepadButton.North, aliases = new[] { "y", "triangle" }, displayName = "Button North", shortDisplayName = ButtonNorthShortDisplayName)]
122 [InputControl(name = "buttonEast", layout = "Button", bit = (uint)GamepadButton.East, usages = new[] { "Back", "Cancel" }, aliases = new[] { "b", "circle" }, displayName = "Button East", shortDisplayName = ButtonEastShortDisplayName)]
123 ////FIXME: 'Press' naming is inconsistent with 'Button' naming
124 [InputControl(name = "leftStickPress", layout = "Button", bit = (uint)GamepadButton.LeftStick, displayName = "Left Stick Press")]
125 [InputControl(name = "rightStickPress", layout = "Button", bit = (uint)GamepadButton.RightStick, displayName = "Right Stick Press")]
126 [InputControl(name = "leftShoulder", layout = "Button", bit = (uint)GamepadButton.LeftShoulder, displayName = "Left Shoulder", shortDisplayName = "LB")]
127 [InputControl(name = "rightShoulder", layout = "Button", bit = (uint)GamepadButton.RightShoulder, displayName = "Right Shoulder", shortDisplayName = "RB")]
128 ////REVIEW: seems like these two should get less ambiguous names as well
129 [InputControl(name = "start", layout = "Button", bit = (uint)GamepadButton.Start, usage = "Menu", displayName = "Start")]
130 [InputControl(name = "select", layout = "Button", bit = (uint)GamepadButton.Select, displayName = "Select")]
131 [FieldOffset(0)]
132 public uint buttons;
133
134 /// <summary>
135 /// Left stick position. Each axis goes from -1 to 1 with
136 /// 0 being center position.
137 /// </summary>
138 /// <value>Left stick position.</value>
139 /// <seealso cref="Gamepad.leftStick"/>
140 [InputControl(layout = "Stick", usage = "Primary2DMotion", processors = "stickDeadzone", displayName = "Left Stick", shortDisplayName = "LS")]
141 [FieldOffset(4)]
142 public Vector2 leftStick;
143
144 /// <summary>
145 /// Right stick position. Each axis from -1 to 1 with
146 /// 0 being center position.
147 /// </summary>
148 /// <value>Right stick position.</value>
149 /// <seealso cref="Gamepad.rightStick"/>
150 [InputControl(layout = "Stick", usage = "Secondary2DMotion", processors = "stickDeadzone", displayName = "Right Stick", shortDisplayName = "RS")]
151 [FieldOffset(12)]
152 public Vector2 rightStick;
153
154 ////REVIEW: should left and right trigger get deadzones?
155
156 /// <summary>
157 /// Position of the left trigger. Goes from 0 (not pressed) to 1 (fully pressed).
158 /// </summary>
159 /// <value>Position of left trigger.</value>
160 /// <seealso cref="Gamepad.leftTrigger"/>
161 [InputControl(layout = "Button", format = "FLT", usage = "SecondaryTrigger", displayName = "Left Trigger", shortDisplayName = "LT")]
162 [FieldOffset(20)]
163 public float leftTrigger;
164
165 /// <summary>
166 /// Position of the right trigger. Goes from 0 (not pressed) to 1 (fully pressed).
167 /// </summary>
168 /// <value>Position of right trigger.</value>
169 /// <seealso cref="Gamepad.rightTrigger"/>
170 [InputControl(layout = "Button", format = "FLT", usage = "SecondaryTrigger", displayName = "Right Trigger", shortDisplayName = "RT")]
171 [FieldOffset(24)]
172 public float rightTrigger;
173
174 /// <summary>
175 /// State format tag for GamepadState.
176 /// </summary>
177 /// <value>Returns "GPAD".</value>
178 public FourCC format => Format;
179
180 /// <summary>
181 /// Create a gamepad state with the given buttons being pressed.
182 /// </summary>
183 /// <param name="buttons">Buttons to put into pressed state.</param>
184 /// <exception cref="ArgumentNullException"><paramref name="buttons"/> is <c>null</c>.</exception>
185 public GamepadState(params GamepadButton[] buttons)
186 : this()
187 {
188 if (buttons == null)
189 throw new ArgumentNullException(nameof(buttons));
190
191 foreach (var button in buttons)
192 {
193 Debug.Assert((int)button < 32, $"Expected button < 32, so we fit into the 32 bit wide bitmask");
194 var bit = 1U << (int)button;
195 this.buttons |= bit;
196 }
197 }
198
199 /// <summary>
200 /// Set the specific buttons to be pressed or unpressed.
201 /// </summary>
202 /// <param name="button">A gamepad button.</param>
203 /// <param name="value">Whether to set <paramref name="button"/> to be pressed or not pressed in
204 /// <see cref="buttons"/>.</param>
205 /// <returns>GamepadState with a modified <see cref="buttons"/> mask.</returns>
206 public GamepadState WithButton(GamepadButton button, bool value = true)
207 {
208 Debug.Assert((int)button < 32, $"Expected button < 32, so we fit into the 32 bit wide bitmask");
209 var bit = 1U << (int)button;
210 if (value)
211 buttons |= bit;
212 else
213 buttons &= ~bit;
214 return this;
215 }
216 }
217
218 ////NOTE: The bit positions here based on the enum value are also used in native.
219 /// <summary>
220 /// Enum of common gamepad buttons.
221 /// </summary>
222 /// <remarks>
223 /// Can be used as an array indexer on the <see cref="Gamepad"/> class to get individual button controls.
224 /// </remarks>
225 public enum GamepadButton
226 {
227 // Dpad buttons. Important to be first in the bitfield as we'll
228 // point the DpadControl to it.
229 // IMPORTANT: Order has to match what is expected by DpadControl.
230
231 /// <summary>
232 /// The up button on a gamepad's dpad.
233 /// </summary>
234 DpadUp = 0,
235
236 /// <summary>
237 /// The down button on a gamepad's dpad.
238 /// </summary>
239 DpadDown = 1,
240
241 /// <summary>
242 /// The left button on a gamepad's dpad.
243 /// </summary>
244 DpadLeft = 2,
245
246 /// <summary>
247 /// The right button on a gamepad's dpad.
248 /// </summary>
249 DpadRight = 3,
250
251 // Face buttons. We go with a north/south/east/west naming as that
252 // clearly disambiguates where we expect the respective button to be.
253
254 /// <summary>
255 /// The upper action button on a gamepad.
256 /// </summary>
257 /// <remarks>
258 /// Identical to <see cref="Y"/> and <see cref="Triangle"/> which are the Xbox and PlayStation controller names for this button.
259 /// </remarks>
260 North = 4,
261
262 /// <summary>
263 /// The right action button on a gamepad.
264 /// </summary>
265 /// <remarks>
266 /// Identical to <see cref="B"/> and <see cref="Circle"/> which are the Xbox and PlayStation controller names for this button.
267 /// </remarks>
268 East = 5,
269
270 /// <summary>
271 /// The lower action button on a gamepad.
272 /// </summary>
273 /// <remarks>
274 /// Identical to <see cref="A"/> and <see cref="Cross"/> which are the Xbox and PlayStation controller names for this button.
275 /// </remarks>
276 South = 6,
277
278 /// <summary>
279 /// The left action button on a gamepad.
280 /// </summary>
281 /// <remarks>
282 /// Identical to <see cref="X"/> and <see cref="Square"/> which are the Xbox and PlayStation controller names for this button.
283 /// </remarks>
284 West = 7,
285
286
287 /// <summary>
288 /// The button pressed by pressing down the left stick on a gamepad.
289 /// </summary>
290 LeftStick = 8,
291
292 /// <summary>
293 /// The button pressed by pressing down the right stick on a gamepad.
294 /// </summary>
295 RightStick = 9,
296
297 /// <summary>
298 /// The left shoulder button on a gamepad.
299 /// </summary>
300 LeftShoulder = 10,
301
302 /// <summary>
303 /// The right shoulder button on a gamepad.
304 /// </summary>
305 RightShoulder = 11,
306
307 /// <summary>
308 /// The start button.
309 /// </summary>
310 Start = 12,
311
312 /// <summary>
313 /// The select button.
314 /// </summary>
315 Select = 13,
316
317 // For values that are not part of the buttons bitmask in GamepadState, assign large values that are outside
318 // the 32bit bit range.
319
320 /// <summary>
321 /// The left trigger button on a gamepad.
322 /// </summary>
323 LeftTrigger = 32,
324
325 /// <summary>
326 /// The right trigger button on a gamepad.
327 /// </summary>
328 RightTrigger = 33,
329
330 /// <summary>
331 /// The X button on an Xbox controller.
332 /// </summary>
333 /// <remarks>
334 /// Identical to <see cref="West"/>, which is the generic name of this button.
335 /// </remarks>
336 X = West,
337 /// <summary>
338 /// The Y button on an Xbox controller.
339 /// </summary>
340 /// <remarks>
341 /// Identical to <see cref="North"/>, which is the generic name of this button.
342 /// </remarks>
343 Y = North,
344 /// <summary>
345 /// The A button on an Xbox controller.
346 /// </summary>
347 /// <remarks>
348 /// Identical to <see cref="South"/>, which is the generic name of this button.
349 /// </remarks>
350 A = South,
351 /// <summary>
352 /// The B button on an Xbox controller.
353 /// </summary>
354 /// <remarks>
355 /// Identical to <see cref="East"/>, which is the generic name of this button.
356 /// </remarks>
357 B = East,
358
359 /// <summary>
360 /// The cross button on a PlayStation controller.
361 /// </summary>
362 /// <remarks>
363 /// Identical to <see cref="South"/>, which is the generic name of this button.
364 /// </remarks>
365 Cross = South,
366 /// <summary>
367 /// The square button on a PlayStation controller.
368 /// </summary>
369 /// <remarks>
370 /// Identical to <see cref="West"/>, which is the generic name of this button.
371 /// </remarks>
372 Square = West,
373 /// <summary>
374 /// The triangle button on a PlayStation controller.
375 /// </summary>
376 /// <remarks>
377 /// Identical to <see cref="North"/>, which is the generic name of this button.
378 /// </remarks>
379 Triangle = North,
380 /// <summary>
381 /// The circle button on a PlayStation controller.
382 /// </summary>
383 /// <remarks>
384 /// Identical to <see cref="East"/>, which is the generic name of this button.
385 /// </remarks>
386 Circle = East,
387 }
388}
389
390namespace UnityEngine.InputSystem
391{
392 /// <summary>
393 /// An Xbox-style gamepad with two sticks, a D-Pad, four face buttons, two triggers,
394 /// two shoulder buttons, and two menu buttons that usually sit in the midsection of the gamepad.
395 /// </summary>
396 /// <remarks>
397 /// The Gamepad layout provides a standardized layouts for gamepads. Generally, if a specific
398 /// device is represented as a Gamepad, the controls, such as the face buttons, are guaranteed
399 /// to be mapped correctly and consistently. If, based on the set of supported devices available
400 /// to the input system, this cannot be guaranteed, a given device is usually represented as a
401 /// generic <see cref="Joystick"/> or as just a plain <see cref="HID.HID"/> instead.
402 ///
403 /// <example>
404 /// <code>
405 /// // Show all gamepads in the system.
406 /// Debug.Log(string.Join("\n", Gamepad.all));
407 ///
408 /// // Check whether the X button on the current gamepad is pressed.
409 /// if (Gamepad.current.xButton.wasPressedThisFrame)
410 /// Debug.Log("Pressed");
411 ///
412 /// // Rumble the left motor on the current gamepad slightly.
413 /// Gamepad.current.SetMotorSpeeds(0.2f, 0.
414 /// </code>
415 /// </example>
416 /// </remarks>
417 [InputControlLayout(stateType = typeof(GamepadState), isGenericTypeOfDevice = true)]
418 public class Gamepad : InputDevice, IDualMotorRumble
419 {
420 /// <summary>
421 /// The left face button of the gamepad.
422 /// </summary>
423 /// <value>Control representing the X/Square face button.</value>
424 /// <remarks>
425 /// On an Xbox controller, this is the X button and on the PS4 controller, this is the
426 /// square button.
427 /// </remarks>
428 /// <seealso cref="xButton"/>
429 /// <seealso cref="squareButton"/>
430 public ButtonControl buttonWest { get; protected set; }
431
432 /// <summary>
433 /// The top face button of the gamepad.
434 /// </summary>
435 /// <value>Control representing the Y/Triangle face button.</value>
436 /// <remarks>
437 /// On an Xbox controller, this is the Y button and on the PS4 controller, this is the
438 /// triangle button.
439 /// </remarks>
440 /// <seealso cref="yButton"/>
441 /// <seealso cref="triangleButton"/>
442 public ButtonControl buttonNorth { get; protected set; }
443
444 /// <summary>
445 /// The bottom face button of the gamepad.
446 /// </summary>
447 /// <value>Control representing the A/Cross face button.</value>
448 /// <remarks>
449 /// On an Xbox controller, this is the A button and on the PS4 controller, this is the
450 /// cross button.
451 /// </remarks>
452 /// <seealso cref="aButton"/>
453 /// <seealso cref="crossButton"/>
454 public ButtonControl buttonSouth { get; protected set; }
455
456 /// <summary>
457 /// The right face button of the gamepad.
458 /// </summary>
459 /// <value>Control representing the B/Circle face button.</value>
460 /// <remarks>
461 /// On an Xbox controller, this is the B button and on the PS4 controller, this is the
462 /// circle button.
463 /// </remarks>
464 /// <seealso cref="bButton"/>
465 /// <seealso cref="circleButton"/>
466 public ButtonControl buttonEast { get; protected set; }
467
468 /// <summary>
469 /// The button that gets triggered when <see cref="leftStick"/> is pressed down.
470 /// </summary>
471 /// <value>Control representing a click with the left stick.</value>
472 public ButtonControl leftStickButton { get; protected set; }
473
474 /// <summary>
475 /// The button that gets triggered when <see cref="rightStick"/> is pressed down.
476 /// </summary>
477 /// <value>Control representing a click with the right stick.</value>
478 public ButtonControl rightStickButton { get; protected set; }
479
480 /// <summary>
481 /// The right button in the middle section of the gamepad (called "menu" on Xbox
482 /// controllers and "options" on PS4 controllers).
483 /// </summary>
484 /// <value>Control representing the right button in midsection.</value>
485 public ButtonControl startButton { get; protected set; }
486
487 /// <summary>
488 /// The left button in the middle section of the gamepad (called "view" on Xbox
489 /// controllers and "share" on PS4 controllers).
490 /// </summary>
491 /// <value>Control representing the left button in midsection.</value>
492 public ButtonControl selectButton { get; protected set; }
493
494 /// <summary>
495 /// The 4-way directional pad on the gamepad.
496 /// </summary>
497 /// <value>Control representing the d-pad.</value>
498 public DpadControl dpad { get; protected set; }
499
500 /// <summary>
501 /// The left shoulder/bumper button that sits on top of <see cref="leftTrigger"/>.
502 /// </summary>
503 /// <value>Control representing the left shoulder button.</value>
504 /// <remarks>
505 /// On Xbox controllers, this is usually called "left bumper" whereas on PS4
506 /// controllers, this button is referred to as "L1".
507 /// </remarks>
508 public ButtonControl leftShoulder { get; protected set; }
509
510 /// <summary>
511 /// The right shoulder/bumper button that sits on top of <see cref="rightTrigger"/>.
512 /// </summary>
513 /// <value>Control representing the right shoulder button.</value>
514 /// <remarks>
515 /// On Xbox controllers, this is usually called "right bumper" whereas on PS4
516 /// controllers, this button is referred to as "R1".
517 /// </remarks>
518 public ButtonControl rightShoulder { get; protected set; }
519
520 /// <summary>
521 /// The left thumbstick on the gamepad.
522 /// </summary>
523 /// <value>Control representing the left thumbstick.</value>
524 public StickControl leftStick { get; protected set; }
525
526 /// <summary>
527 /// The right thumbstick on the gamepad.
528 /// </summary>
529 /// <value>Control representing the right thumbstick.</value>
530 public StickControl rightStick { get; protected set; }
531
532 /// <summary>
533 /// The left trigger button sitting below <see cref="leftShoulder"/>.
534 /// </summary>
535 /// <value>Control representing the left trigger button.</value>
536 /// <remarks>
537 /// On PS4 controllers, this button is referred to as "L2".
538 /// </remarks>
539 public ButtonControl leftTrigger { get; protected set; }
540
541 /// <summary>
542 /// The right trigger button sitting below <see cref="rightShoulder"/>.
543 /// </summary>
544 /// <value>Control representing the right trigger button.</value>
545 /// <remarks>
546 /// On PS4 controllers, this button is referred to as "R2".
547 /// </remarks>
548 public ButtonControl rightTrigger { get; protected set; }
549
550 /// <summary>
551 /// Same as <see cref="buttonSouth"/>. Xbox-style alias.
552 /// </summary>
553 /// <value>Same as <see cref="buttonSouth"/>.</value>
554 public ButtonControl aButton => buttonSouth;
555
556 /// <summary>
557 /// Same as <see cref="buttonEast"/>. Xbox-style alias.
558 /// </summary>
559 /// <value>Same as <see cref="buttonEast"/>.</value>
560 public ButtonControl bButton => buttonEast;
561
562 /// <summary>
563 /// Same as <see cref="buttonWest"/> Xbox-style alias.
564 /// </summary>
565 /// <value>Same as <see cref="buttonWest"/>.</value>
566 public ButtonControl xButton => buttonWest;
567
568 /// <summary>
569 /// Same as <see cref="buttonNorth"/>. Xbox-style alias.
570 /// </summary>
571 /// <value>Same as <see cref="buttonNorth"/>.</value>
572 public ButtonControl yButton => buttonNorth;
573
574 /// <summary>
575 /// Same as <see cref="buttonNorth"/>. PS4-style alias.
576 /// </summary>
577 /// <value>Same as <see cref="buttonNorth"/>.</value>
578 public ButtonControl triangleButton => buttonNorth;
579
580 /// <summary>
581 /// Same as <see cref="buttonWest"/>. PS4-style alias.
582 /// </summary>
583 /// <value>Same as <see cref="buttonWest"/>.</value>
584 public ButtonControl squareButton => buttonWest;
585
586 /// <summary>
587 /// Same as <see cref="buttonEast"/>. PS4-style alias.
588 /// </summary>
589 /// <value>Same as <see cref="buttonEast"/>.</value>
590 public ButtonControl circleButton => buttonEast;
591
592 /// <summary>
593 /// Same as <see cref="buttonSouth"/>. PS4-style alias.
594 /// </summary>
595 /// <value>Same as <see cref="buttonSouth"/>.</value>
596 public ButtonControl crossButton => buttonSouth;
597
598 /// <summary>
599 /// Retrieve a gamepad button by its <see cref="GamepadButton"/> enumeration
600 /// constant.
601 /// </summary>
602 /// <param name="button">Button to retrieve.</param>
603 /// <exception cref="ArgumentException"><paramref name="button"/> is not a valid gamepad
604 /// button value.</exception>
605 public ButtonControl this[GamepadButton button]
606 {
607 get
608 {
609 switch (button)
610 {
611 case GamepadButton.North: return buttonNorth;
612 case GamepadButton.South: return buttonSouth;
613 case GamepadButton.East: return buttonEast;
614 case GamepadButton.West: return buttonWest;
615 case GamepadButton.Start: return startButton;
616 case GamepadButton.Select: return selectButton;
617 case GamepadButton.LeftShoulder: return leftShoulder;
618 case GamepadButton.RightShoulder: return rightShoulder;
619 case GamepadButton.LeftTrigger: return leftTrigger;
620 case GamepadButton.RightTrigger: return rightTrigger;
621 case GamepadButton.LeftStick: return leftStickButton;
622 case GamepadButton.RightStick: return rightStickButton;
623 case GamepadButton.DpadUp: return dpad.up;
624 case GamepadButton.DpadDown: return dpad.down;
625 case GamepadButton.DpadLeft: return dpad.left;
626 case GamepadButton.DpadRight: return dpad.right;
627 default:
628 throw new InvalidEnumArgumentException(nameof(button), (int)button, typeof(GamepadButton));
629 }
630 }
631 }
632
633 /// <summary>
634 /// The gamepad last used/connected by the player or <c>null</c> if there is no gamepad connected
635 /// to the system.
636 /// </summary>
637 /// <remarks>
638 /// When added, a device is automatically made current (see <see cref="InputDevice.MakeCurrent"/>), so
639 /// when connecting a gamepad, it will also become current. After that, it will only become current again
640 /// when input change on non-noisy controls (see <see cref="InputControl.noisy"/>) is received.
641 ///
642 /// For local multiplayer scenarios (or whenever there are multiple gamepads that need to be usable
643 /// in a concurrent fashion), it is not recommended to rely on this property. Instead, it is recommended
644 /// to use <see cref="PlayerInput"/> or <see cref="Users.InputUser"/>.
645 /// </remarks>
646 /// <seealso cref="InputDevice.MakeCurrent"/>
647 /// <seealso cref="all"/>
648 public static Gamepad current { get; private set; }
649
650 /// <summary>
651 /// A list of gamepads currently connected to the system.
652 /// </summary>
653 /// <value>All currently connected gamepads.</value>
654 /// <remarks>
655 /// Does not cause GC allocation.
656 ///
657 /// Do <em>not</em> hold on to the value returned by this getter but rather query it whenever
658 /// you need it. Whenever the gamepad setup changes, the value returned by this getter
659 /// is invalidated.
660 /// </remarks>
661 /// <seealso cref="current"/>
662 public new static ReadOnlyArray<Gamepad> all => new ReadOnlyArray<Gamepad>(s_Gamepads, 0, s_GamepadCount);
663
664 /// <inheritdoc />
665 protected override void FinishSetup()
666 {
667 ////REVIEW: what's actually faster/better... storing these in properties or doing the lookup on the fly?
668 buttonWest = GetChildControl<ButtonControl>("buttonWest");
669 buttonNorth = GetChildControl<ButtonControl>("buttonNorth");
670 buttonSouth = GetChildControl<ButtonControl>("buttonSouth");
671 buttonEast = GetChildControl<ButtonControl>("buttonEast");
672
673 startButton = GetChildControl<ButtonControl>("start");
674 selectButton = GetChildControl<ButtonControl>("select");
675
676 leftStickButton = GetChildControl<ButtonControl>("leftStickPress");
677 rightStickButton = GetChildControl<ButtonControl>("rightStickPress");
678
679 dpad = GetChildControl<DpadControl>("dpad");
680
681 leftShoulder = GetChildControl<ButtonControl>("leftShoulder");
682 rightShoulder = GetChildControl<ButtonControl>("rightShoulder");
683
684 leftStick = GetChildControl<StickControl>("leftStick");
685 rightStick = GetChildControl<StickControl>("rightStick");
686
687 leftTrigger = GetChildControl<ButtonControl>("leftTrigger");
688 rightTrigger = GetChildControl<ButtonControl>("rightTrigger");
689
690 base.FinishSetup();
691 }
692
693 /// <summary>
694 /// Make the gamepad the <see cref="current"/> gamepad.
695 /// </summary>
696 /// <remarks>
697 /// This is called automatically by the system when there is input on a gamepad.
698 /// </remarks>
699 public override void MakeCurrent()
700 {
701 base.MakeCurrent();
702 current = this;
703 }
704
705 /// <summary>
706 /// Called when the gamepad is added to the system.
707 /// </summary>
708 protected override void OnAdded()
709 {
710 ArrayHelpers.AppendWithCapacity(ref s_Gamepads, ref s_GamepadCount, this);
711 }
712
713 /// <summary>
714 /// Called when the gamepad is removed from the system.
715 /// </summary>
716 protected override void OnRemoved()
717 {
718 if (current == this)
719 current = null;
720
721 // Remove from `all`.
722 var index = ArrayHelpers.IndexOfReference(s_Gamepads, this, s_GamepadCount);
723 if (index != -1)
724 ArrayHelpers.EraseAtWithCapacity(s_Gamepads, ref s_GamepadCount, index);
725 else
726 {
727 Debug.Assert(false,
728 $"Gamepad {this} seems to not have been added but is being removed (gamepad list: {string.Join(", ", all)})"); // Put in else to not allocate on normal path.
729 }
730 }
731
732 /// <summary>
733 /// Pause rumble effects on the gamepad. Resume with <see cref="ResumeHaptics"/>.
734 /// </summary>
735 /// <seealso cref="IDualMotorRumble"/>
736 public virtual void PauseHaptics()
737 {
738 m_Rumble.PauseHaptics(this);
739 }
740
741 /// <summary>
742 /// Resume rumble affects on the gamepad that have been paused with <see cref="PauseHaptics"/>.
743 /// </summary>
744 /// <seealso cref="IDualMotorRumble"/>
745 public virtual void ResumeHaptics()
746 {
747 m_Rumble.ResumeHaptics(this);
748 }
749
750 /// <summary>
751 /// Reset rumble effects on the gamepad. Puts the gamepad rumble motors back into their
752 /// default state.
753 /// </summary>
754 /// <seealso cref="IDualMotorRumble"/>
755 public virtual void ResetHaptics()
756 {
757 m_Rumble.ResetHaptics(this);
758 }
759
760 /// <inheritdoc />
761 public virtual void SetMotorSpeeds(float lowFrequency, float highFrequency)
762 {
763 m_Rumble.SetMotorSpeeds(this, lowFrequency, highFrequency);
764 }
765
766 private DualMotorRumble m_Rumble;
767
768 private static int s_GamepadCount;
769 private static Gamepad[] s_Gamepads;
770 }
771}