aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/Ui/Input
diff options
context:
space:
mode:
authorCaian Benedicto <caianbene@gmail.com>2021-10-12 16:54:21 -0300
committerGitHub <noreply@github.com>2021-10-12 21:54:21 +0200
commit380b95bc59e7dc419f89df951cdc086e792cb0ff (patch)
tree59a636b48db991d8e13132d7d3f41464d9b04b24 /Ryujinx.HLE/Ui/Input
parent69093cf2d69490862aff974f170cee63a0016fd0 (diff)
Inline software keyboard without input pop up dialog (#2180)
* Initial implementation * Refactor dynamic text input keys out to facilitate configuration via UI * Fix code styling * Add per applet indirect layer handles * Remove static functions from SoftwareKeyboardRenderer * Remove inline keyboard reset delay * Remove inline keyboard V2 responses * Add inline keyboard soft-lock recovering * Add comments * Forward accept and cancel key names to the keyboard and add soft-lock prevention line * Add dummy window to handle paste events * Rework inline keyboard state machine and graphics * Implement IHostUiHandler interfaces on headless WindowBase class * Add inline keyboard assets * Fix coding style * Fix coding style * Change mode cycling shortcut to F6 * Fix invalid calc size error in games using extended calc * Remove unnecessary namespaces
Diffstat (limited to 'Ryujinx.HLE/Ui/Input')
-rw-r--r--Ryujinx.HLE/Ui/Input/NpadButtonHandler.cs6
-rw-r--r--Ryujinx.HLE/Ui/Input/NpadReader.cs137
2 files changed, 143 insertions, 0 deletions
diff --git a/Ryujinx.HLE/Ui/Input/NpadButtonHandler.cs b/Ryujinx.HLE/Ui/Input/NpadButtonHandler.cs
new file mode 100644
index 00000000..cd41f5c8
--- /dev/null
+++ b/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/Ryujinx.HLE/Ui/Input/NpadReader.cs b/Ryujinx.HLE/Ui/Input/NpadReader.cs
new file mode 100644
index 00000000..bc3fb396
--- /dev/null
+++ b/Ryujinx.HLE/Ui/Input/NpadReader.cs
@@ -0,0 +1,137 @@
+using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
+using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
+using System;
+
+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 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 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);
+ }
+ }
+ }
+ }
+ }
+}