DiscreteButtonControl.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. using System;
  2. using UnityEngine.InputSystem.LowLevel;
  3. using UnityEngine.InputSystem.Layouts;
  4. using UnityEngine.InputSystem.Utilities;
  5. ////TODO: hide in UI
  6. namespace UnityEngine.InputSystem.Controls
  7. {
  8. /// <summary>
  9. /// A button that is considered pressed if the underlying state has a value in the specific range.
  10. /// </summary>
  11. /// <remarks>
  12. /// This control is most useful for handling HID-style hat switches. Unlike <see cref="DpadControl"/>,
  13. /// which by default is stored as a bitfield of four bits that each represent a direction on the pad,
  14. /// these hat switches enumerate the possible directions that the switch can be moved in. For example,
  15. /// the value 1 could indicate that the switch is moved to the left whereas 3 could indicate it is
  16. /// moved up.
  17. /// </remarks>
  18. [Scripting.Preserve]
  19. public class DiscreteButtonControl : ButtonControl
  20. {
  21. /// <summary>
  22. /// Value (inclusive) at which to start considering the button to be pressed.
  23. /// </summary>
  24. /// <remarks>
  25. /// <see cref="minValue"/> is allowed to be larger than <see cref="maxValue"/>. This indicates
  26. /// a setup where the value wraps around beyond <see cref="minValue"/>, skips <see cref="nullValue"/>,
  27. /// and then goes all the way up to <see cref="maxValue"/>.
  28. ///
  29. /// For example, if the underlying state represents a circular D-pad and enumerates its
  30. /// 9 possible positions (including null state) going clock-wise from 0 to 8 and with 1
  31. /// indicating that the D-pad is pressed to the left, then 1, 2, and 8 would indicate
  32. /// that the "left" button is held on the D-pad. To set this up, set <see cref="minValue"/>
  33. /// to 8, <see cref="maxValue"/> to 2, and <see cref="nullValue"/> to 0 (the default).
  34. /// </remarks>
  35. public int minValue;
  36. /// <summary>
  37. /// Value (inclusive) beyond which to stop considering the button to be pressed.
  38. /// </summary>
  39. public int maxValue;
  40. public int wrapAtValue;
  41. public int nullValue;
  42. protected override void FinishSetup()
  43. {
  44. base.FinishSetup();
  45. if (!stateBlock.format.IsIntegerFormat())
  46. throw new NotSupportedException(
  47. $"Non-integer format '{stateBlock.format}' is not supported for DiscreteButtonControl '{this}'");
  48. }
  49. public override unsafe float ReadUnprocessedValueFromState(void* statePtr)
  50. {
  51. var valuePtr = (byte*)statePtr + (int)m_StateBlock.byteOffset;
  52. var intValue = MemoryHelpers.ReadIntFromMultipleBits(valuePtr, m_StateBlock.bitOffset, m_StateBlock.sizeInBits);
  53. var value = 0.0f;
  54. if (minValue > maxValue)
  55. {
  56. // If no wrapping point is set, default to wrapping around exactly
  57. // at the point of minValue.
  58. if (wrapAtValue == nullValue)
  59. wrapAtValue = minValue;
  60. if ((intValue >= minValue && intValue <= wrapAtValue)
  61. || (intValue != nullValue && intValue <= maxValue))
  62. value = 1.0f;
  63. }
  64. else
  65. {
  66. value = intValue >= minValue && intValue <= maxValue ? 1.0f : 0.0f;
  67. }
  68. return Preprocess(value);
  69. }
  70. public override unsafe void WriteValueIntoState(float value, void* statePtr)
  71. {
  72. throw new NotImplementedException();
  73. }
  74. }
  75. }