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}