aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE/UI/Input
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.HLE/UI/Input')
-rw-r--r--src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs6
-rw-r--r--src/Ryujinx.HLE/UI/Input/NpadReader.cs140
2 files changed, 146 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs b/src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs
new file mode 100644
index 00000000..73c30661
--- /dev/null
+++ b/src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs
@@ -0,0 +1,6 @@
+using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
+
+namespace Ryujinx.HLE.UI.Input
+{
+ delegate void NpadButtonHandler(int npadIndex, NpadButton button);
+}
diff --git a/src/Ryujinx.HLE/UI/Input/NpadReader.cs b/src/Ryujinx.HLE/UI/Input/NpadReader.cs
new file mode 100644
index 00000000..8276d616
--- /dev/null
+++ b/src/Ryujinx.HLE/UI/Input/NpadReader.cs
@@ -0,0 +1,140 @@
+using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
+using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
+
+namespace Ryujinx.HLE.UI.Input
+{
+ /// <summary>
+ /// Class that converts Hid entries for the Npad into pressed / released events.
+ /// </summary>
+ class NpadReader
+ {
+ private readonly Switch _device;
+ private readonly NpadCommonState[] _lastStates;
+
+ public event NpadButtonHandler NpadButtonUpEvent;
+ public event NpadButtonHandler NpadButtonDownEvent;
+
+ public NpadReader(Switch device)
+ {
+ _device = device;
+ _lastStates = new NpadCommonState[_device.Hid.SharedMemory.Npads.Length];
+ }
+
+ public NpadButton GetCurrentButtonsOfNpad(int npadIndex)
+ {
+ return _lastStates[npadIndex].Buttons;
+ }
+
+ public NpadButton GetCurrentButtonsOfAllNpads()
+ {
+ NpadButton buttons = 0;
+
+ foreach (var state in _lastStates)
+ {
+ buttons |= state.Buttons;
+ }
+
+ return buttons;
+ }
+
+ private static ref RingLifo<NpadCommonState> GetCommonStateLifo(ref NpadInternalState npad)
+ {
+ switch (npad.StyleSet)
+ {
+ case NpadStyleTag.FullKey:
+ return ref npad.FullKey;
+ case NpadStyleTag.Handheld:
+ return ref npad.Handheld;
+ case NpadStyleTag.JoyDual:
+ return ref npad.JoyDual;
+ case NpadStyleTag.JoyLeft:
+ return ref npad.JoyLeft;
+ case NpadStyleTag.JoyRight:
+ return ref npad.JoyRight;
+ case NpadStyleTag.Palma:
+ return ref npad.Palma;
+ default:
+ return ref npad.SystemExt;
+ }
+ }
+
+ public void Update(bool supressEvents = false)
+ {
+ ref var npads = ref _device.Hid.SharedMemory.Npads;
+
+ // Process each input individually.
+ for (int npadIndex = 0; npadIndex < npads.Length; npadIndex++)
+ {
+ UpdateNpad(npadIndex, supressEvents);
+ }
+ }
+
+ private void UpdateNpad(int npadIndex, bool supressEvents)
+ {
+ const int MaxEntries = 1024;
+
+ ref var npadState = ref _device.Hid.SharedMemory.Npads[npadIndex];
+ ref var lastEntry = ref _lastStates[npadIndex];
+
+ var fullKeyEntries = GetCommonStateLifo(ref npadState.InternalState).ReadEntries(MaxEntries);
+
+ int firstEntryNum;
+
+ // Scan the LIFO for the first entry that is newer that what's already processed.
+ for (firstEntryNum = fullKeyEntries.Length - 1;
+ firstEntryNum >= 0 && fullKeyEntries[firstEntryNum].Object.SamplingNumber <= lastEntry.SamplingNumber;
+ firstEntryNum--)
+ {
+ }
+
+ if (firstEntryNum == -1)
+ {
+ return;
+ }
+
+ for (; firstEntryNum >= 0; firstEntryNum--)
+ {
+ var entry = fullKeyEntries[firstEntryNum];
+
+ // The interval of valid entries should be contiguous.
+ if (entry.SamplingNumber < lastEntry.SamplingNumber)
+ {
+ break;
+ }
+
+ if (!supressEvents)
+ {
+ ProcessNpadButtons(npadIndex, entry.Object.Buttons);
+ }
+
+ lastEntry = entry.Object;
+ }
+ }
+
+ private void ProcessNpadButtons(int npadIndex, NpadButton buttons)
+ {
+ NpadButton lastButtons = _lastStates[npadIndex].Buttons;
+
+ for (ulong buttonMask = 1; buttonMask != 0; buttonMask <<= 1)
+ {
+ NpadButton currentButton = (NpadButton)buttonMask & buttons;
+ NpadButton lastButton = (NpadButton)buttonMask & lastButtons;
+
+ if (lastButton != 0)
+ {
+ if (currentButton == 0)
+ {
+ NpadButtonUpEvent?.Invoke(npadIndex, lastButton);
+ }
+ }
+ else
+ {
+ if (currentButton != 0)
+ {
+ NpadButtonDownEvent?.Invoke(npadIndex, currentButton);
+ }
+ }
+ }
+ }
+ }
+}