NpadReader.cs 4.3 KB

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