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