NpadReader.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
  2. using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
  3. namespace Ryujinx.HLE.Ui.Input
  4. {
  5. /// <summary>
  6. /// Class that converts Hid entries for the Npad into pressed / released events.
  7. /// </summary>
  8. class NpadReader
  9. {
  10. private readonly Switch _device;
  11. private NpadCommonState[] _lastStates;
  12. public event NpadButtonHandler NpadButtonUpEvent;
  13. public event NpadButtonHandler NpadButtonDownEvent;
  14. public NpadReader(Switch device)
  15. {
  16. _device = device;
  17. _lastStates = new NpadCommonState[_device.Hid.SharedMemory.Npads.Length];
  18. }
  19. public NpadButton GetCurrentButtonsOfNpad(int npadIndex)
  20. {
  21. return _lastStates[npadIndex].Buttons;
  22. }
  23. public NpadButton GetCurrentButtonsOfAllNpads()
  24. {
  25. NpadButton buttons = 0;
  26. foreach (var state in _lastStates)
  27. {
  28. buttons |= state.Buttons;
  29. }
  30. return buttons;
  31. }
  32. private ref RingLifo<NpadCommonState> GetCommonStateLifo(ref NpadInternalState npad)
  33. {
  34. switch (npad.StyleSet)
  35. {
  36. case NpadStyleTag.FullKey:
  37. return ref npad.FullKey;
  38. case NpadStyleTag.Handheld:
  39. return ref npad.Handheld;
  40. case NpadStyleTag.JoyDual:
  41. return ref npad.JoyDual;
  42. case NpadStyleTag.JoyLeft:
  43. return ref npad.JoyLeft;
  44. case NpadStyleTag.JoyRight:
  45. return ref npad.JoyRight;
  46. case NpadStyleTag.Palma:
  47. return ref npad.Palma;
  48. default:
  49. return ref npad.SystemExt;
  50. }
  51. }
  52. public void Update(bool supressEvents=false)
  53. {
  54. ref var npads = ref _device.Hid.SharedMemory.Npads;
  55. // Process each input individually.
  56. for (int npadIndex = 0; npadIndex < npads.Length; npadIndex++)
  57. {
  58. UpdateNpad(npadIndex, supressEvents);
  59. }
  60. }
  61. private void UpdateNpad(int npadIndex, bool supressEvents)
  62. {
  63. const int MaxEntries = 1024;
  64. ref var npadState = ref _device.Hid.SharedMemory.Npads[npadIndex];
  65. ref var lastEntry = ref _lastStates[npadIndex];
  66. var fullKeyEntries = GetCommonStateLifo(ref npadState.InternalState).ReadEntries(MaxEntries);
  67. int firstEntryNum;
  68. // Scan the LIFO for the first entry that is newer that what's already processed.
  69. for (firstEntryNum = fullKeyEntries.Length - 1; firstEntryNum >= 0 && fullKeyEntries[firstEntryNum].Object.SamplingNumber <= lastEntry.SamplingNumber; firstEntryNum--) ;
  70. if (firstEntryNum == -1)
  71. {
  72. return;
  73. }
  74. for (; firstEntryNum >= 0; firstEntryNum--)
  75. {
  76. var entry = fullKeyEntries[firstEntryNum];
  77. // The interval of valid entries should be contiguous.
  78. if (entry.SamplingNumber < lastEntry.SamplingNumber)
  79. {
  80. break;
  81. }
  82. if (!supressEvents)
  83. {
  84. ProcessNpadButtons(npadIndex, entry.Object.Buttons);
  85. }
  86. lastEntry = entry.Object;
  87. }
  88. }
  89. private void ProcessNpadButtons(int npadIndex, NpadButton buttons)
  90. {
  91. NpadButton lastButtons = _lastStates[npadIndex].Buttons;
  92. for (ulong buttonMask = 1; buttonMask != 0; buttonMask <<= 1)
  93. {
  94. NpadButton currentButton = (NpadButton)buttonMask & buttons;
  95. NpadButton lastButton = (NpadButton)buttonMask & lastButtons;
  96. if (lastButton != 0)
  97. {
  98. if (currentButton == 0)
  99. {
  100. NpadButtonUpEvent?.Invoke(npadIndex, lastButton);
  101. }
  102. }
  103. else
  104. {
  105. if (currentButton != 0)
  106. {
  107. NpadButtonDownEvent?.Invoke(npadIndex, currentButton);
  108. }
  109. }
  110. }
  111. }
  112. }
  113. }