From 2365ddfc363e76ac1ac9d2e32ef9b36b85463431 Mon Sep 17 00:00:00 2001
From: mageven <62494521+mageven@users.noreply.github.com>
Date: Fri, 3 Apr 2020 05:40:02 +0530
Subject: [PATCH] HID SharedMem Rework (#1003)

* Delete old HLE.Input

* Add new HLE Input.

git shows Hid.cs as modified because of the same name. It is new.

* Change HID Service

* Change Ryujinx UI to reflect new Input

* Add basic ControllerApplet

* Add DebugPad

Should fix Kirby Star Allies

* Address Ac_K's comments

* Moved all of HLE.Input to Services.Hid
* Separated all structs and enums each to a file
* Removed vars
* Made some naming changes to align with switchbrew
* Added official joycon colors

As an aside, fixed a mistake in touchscreen headers and added checks to
important SharedMem structs at init time.

* Further address Ac_K's comments

* Addressed gdkchan's and some more Ac_K's comments

* Address AcK's review comments

* Address AcK's second review comments

* Replace missed Marshal.SizeOf and address gdkchan's comments
---
 Ryujinx.HLE/DeviceMemory.cs                   |   6 +
 .../InvalidStructLayoutException.cs           |  15 +
 Ryujinx.HLE/HOS/Applets/AppletManager.cs      |   1 +
 .../Applets/Controller/ControllerApplet.cs    | 114 ++++++
 .../Controller/ControllerSupportArg.cs        |  11 +
 .../Controller/ControllerSupportArgHeader.cs  |  13 +
 .../Controller/ControllerSupportArgPrivate.cs |  14 +
 .../Controller/ControllerSupportMode.cs       |   9 +
 .../Controller/ControllerSupportResultInfo.cs |  10 +
 Ryujinx.HLE/HOS/Applets/IApplet.cs            |   6 +
 .../SoftwareKeyboardApplet.cs                 |  17 +-
 Ryujinx.HLE/HOS/Services/Hid/Hid.cs           |  88 +++++
 .../HOS/Services/Hid/HidDevices/BaseDevice.cs |  29 ++
 .../Services/Hid/HidDevices/DebugPadDevice.cs |  24 ++
 .../Services/Hid/HidDevices/KeyboardDevice.cs |  32 ++
 .../Services/Hid/HidDevices/MouseDevice.cs    |  37 ++
 .../Services/Hid/HidDevices/NpadDevices.cs    | 332 ++++++++++++++++++
 .../Services/Hid/HidDevices/TouchDevice.cs    |  46 +++
 .../Hid/HidDevices/Types/ControllerConfig.cs  |   8 +
 .../Hid/HidDevices/Types/GamepadInput.cs      |  10 +
 .../Hid/HidDevices}/Types/JoystickPosition.cs |   2 +-
 .../Hid/HidDevices/Types/KeyboardInput.cs     |   8 +
 .../Hid/HidDevices/Types/TouchPoint.cs        |  11 +
 .../HOS/Services/Hid/HidServer/HidUtils.cs    |  65 ++--
 .../Npad/HidNpadHandheldActivationMode.cs     |   0
 .../Types/Npad/HidNpadJoyAssignmentMode.cs    |   0
 .../Types/Npad/HidNpadJoyDeviceType.cs        |   0
 .../SixAxis/HidAccelerometerParameters.cs     |   0
 .../SixAxis/HidGyroscopeZeroDriftMode.cs      |   0
 .../SixAxis/HidSensorFusionParameters.cs      |   0
 .../Vibration/HidVibrationDevicePosition.cs   |   0
 .../Types/Vibration/HidVibrationDeviceType.cs |   0
 .../Vibration/HidVibrationDeviceValue.cs      |   0
 .../Types/Vibration/HidVibrationValue.cs      |   0
 Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs    |  85 +++--
 .../HOS/Services/Hid/Irs/IIrSensorServer.cs   |  11 +-
 .../HOS/Services/Hid/Types/Boolean32.cs       |   9 +
 .../Services/Hid/Types/Npad/ControllerKeys.cs |  45 +++
 .../Services/Hid/Types/Npad/ControllerType.cs |  19 +
 .../Hid/Types/Npad/HidNpadJoyHoldType.cs      |   8 -
 .../Services/Hid/Types/Npad/HidNpadStyle.cs   |  16 -
 .../HOS/Services/Hid/Types/Npad/NpadColor.cs  |  37 ++
 .../Npad/{HidNpadIdType.cs => NpadIdType.cs}  |   2 +-
 .../Services/Hid/Types/Npad/PlayerIndex.cs    |  17 +
 .../Types/SharedMem/CommonEntriesHeader.cs    |  11 +
 .../Hid/Types/SharedMem/DebugPad/DebugPad.cs  |   9 +
 .../Types/SharedMem/DebugPad/DebugPadEntry.cs |   8 +
 .../Hid/Types/SharedMem/HidSharedMemory.cs    |  24 ++
 .../Hid/Types/SharedMem/Keyboard/Keyboard.cs  |   9 +
 .../Types/SharedMem/Keyboard/KeyboardState.cs |  10 +
 .../Hid/Types/SharedMem/Mouse/Mouse.cs        |  10 +
 .../Types/SharedMem/Mouse/MousePosition.cs    |  12 +
 .../Hid/Types/SharedMem/Mouse/MouseState.cs   |  10 +
 .../Hid/Types/SharedMem/Npad/BatterCharge.cs  |  11 +
 .../Hid/Types/SharedMem/Npad/DeviceType.cs    |  26 ++
 .../Hid/Types/SharedMem/Npad/HidVector.cs     |   9 +
 .../Services/Hid/Types/SharedMem/Npad/Npad.cs |  21 ++
 .../SharedMem/Npad/NpadColorDescription.cs}   |   4 +-
 .../SharedMem/Npad/NpadConnectionState.cs     |  13 +
 .../Types/SharedMem/Npad/NpadJoyHoldType.cs   |   8 +
 .../Hid/Types/SharedMem/Npad/NpadLayout.cs    |   8 +
 .../Types/SharedMem/Npad/NpadLayoutsIndex.cs  |  13 +
 .../Hid/Types/SharedMem/Npad/NpadSixAxis.cs   |   8 +
 .../Hid/Types/SharedMem/Npad/NpadState.cs     |  14 +
 .../Types/SharedMem/Npad/NpadStatesHeader.cs  |  16 +
 .../SharedMem/Npad/NpadSystemProperties.cs    |  22 ++
 .../Hid/Types/SharedMem/Npad/SixAxisState.cs  |  14 +
 .../Hid/Types/SharedMem/StructArrayHelpers.cs |  53 +++
 .../SharedMem/Touchscreen/TouchScreen.cs      |   9 +
 .../SharedMem/Touchscreen/TouchScreenState.cs |  10 +
 .../Touchscreen/TouchScreenStateData.cs       |  15 +
 .../HOS/Services/Nfc/Nfp/UserManager/IUser.cs |   4 +-
 .../Nfc/Nfp/UserManager/Types/Device.cs       |   5 +-
 .../Input/Controller/BaseController.cs        | 142 --------
 .../Input/Controller/NpadController.cs        |  68 ----
 Ryujinx.HLE/Input/Controller/ProController.cs |  42 ---
 .../Input/Controller/Types/BatteryState.cs    |  12 -
 .../Controller/Types/ControllerButtons.cs     |  35 --
 .../Types/ControllerConnectionState.cs        |  11 -
 .../Controller/Types/ControllerDeviceState.cs |  18 -
 .../Controller/Types/ControllerDeviceType.cs  |  12 -
 .../Controller/Types/ControllerHeader.cs      |  19 -
 .../Input/Controller/Types/ControllerId.cs    |  16 -
 .../Controller/Types/ControllerLayouts.cs     |  13 -
 .../Input/Controller/Types/ControllerState.cs |  15 -
 .../Controller/Types/ControllerStateHeader.cs |  13 -
 .../Controller/Types/ControllerStatus.cs      |  14 -
 .../Input/Controller/Types/DeviceFlags.cs     |  22 --
 .../Input/Controller/Types/HotkeyButtons.cs   |  10 -
 .../Input/Controller/Types/NpadColor.cs       |  23 --
 Ryujinx.HLE/Input/Hid.cs                      | 218 ------------
 Ryujinx.HLE/Input/HidValues.cs                |  63 ----
 Ryujinx.HLE/Input/IHidDevice.cs               |   8 -
 Ryujinx.HLE/Input/Keyboard/Keyboard.cs        |   8 -
 Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs   |  15 -
 Ryujinx.HLE/Input/Keyboard/KeyboardHeader.cs  |  13 -
 Ryujinx.HLE/Input/Touch/TouchData.cs          |  18 -
 Ryujinx.HLE/Input/Touch/TouchEntry.cs         |  11 -
 Ryujinx.HLE/Input/Touch/TouchHeader.cs        |  14 -
 Ryujinx.HLE/Input/Touch/TouchPoint.cs         |  11 -
 Ryujinx.HLE/Switch.cs                         |   3 +-
 Ryujinx/Ui/GLRenderer.cs                      |  28 +-
 Ryujinx/Ui/KeyboardControls.cs                |  51 +--
 Ryujinx/Ui/MainWindow.cs                      |  15 +-
 Ryujinx/Ui/NpadController.cs                  |  40 +--
 105 files changed, 1500 insertions(+), 1044 deletions(-)
 create mode 100644 Ryujinx.HLE/Exceptions/InvalidStructLayoutException.cs
 create mode 100644 Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs
 create mode 100644 Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArg.cs
 create mode 100644 Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgHeader.cs
 create mode 100644 Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgPrivate.cs
 create mode 100644 Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportMode.cs
 create mode 100644 Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportResultInfo.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Hid.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/ControllerConfig.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/GamepadInput.cs
 rename Ryujinx.HLE/{Input/Controller => HOS/Services/Hid/HidDevices}/Types/JoystickPosition.cs (70%)
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/Npad/HidNpadHandheldActivationMode.cs (100%)
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/Npad/HidNpadJoyAssignmentMode.cs (100%)
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/Npad/HidNpadJoyDeviceType.cs (100%)
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/SixAxis/HidAccelerometerParameters.cs (100%)
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/SixAxis/HidGyroscopeZeroDriftMode.cs (100%)
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/SixAxis/HidSensorFusionParameters.cs (100%)
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/Vibration/HidVibrationDevicePosition.cs (100%)
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/Vibration/HidVibrationDeviceType.cs (100%)
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/Vibration/HidVibrationDeviceValue.cs (100%)
 rename Ryujinx.HLE/HOS/Services/Hid/{ => HidServer}/Types/Vibration/HidVibrationValue.cs (100%)
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerKeys.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerType.cs
 delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs
 delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs
 rename Ryujinx.HLE/HOS/Services/Hid/Types/Npad/{HidNpadIdType.cs => NpadIdType.cs} (89%)
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/PlayerIndex.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/CommonEntriesHeader.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPad.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPadEntry.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/HidSharedMemory.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/Keyboard.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/KeyboardState.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MousePosition.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MouseState.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/BatterCharge.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/DeviceType.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/HidVector.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs
 rename Ryujinx.HLE/{Input/Controller/Types/ControllerColorDescription.cs => HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs} (54%)
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayoutsIndex.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSixAxis.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadState.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadStatesHeader.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSystemProperties.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisState.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/StructArrayHelpers.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreen.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenState.cs
 create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenStateData.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/BaseController.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/NpadController.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/ProController.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/BatteryState.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerDeviceType.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerHeader.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerId.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerState.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerStateHeader.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs
 delete mode 100644 Ryujinx.HLE/Input/Controller/Types/NpadColor.cs
 delete mode 100644 Ryujinx.HLE/Input/Hid.cs
 delete mode 100644 Ryujinx.HLE/Input/HidValues.cs
 delete mode 100644 Ryujinx.HLE/Input/IHidDevice.cs
 delete mode 100644 Ryujinx.HLE/Input/Keyboard/Keyboard.cs
 delete mode 100644 Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs
 delete mode 100644 Ryujinx.HLE/Input/Keyboard/KeyboardHeader.cs
 delete mode 100644 Ryujinx.HLE/Input/Touch/TouchData.cs
 delete mode 100644 Ryujinx.HLE/Input/Touch/TouchEntry.cs
 delete mode 100644 Ryujinx.HLE/Input/Touch/TouchHeader.cs
 delete mode 100644 Ryujinx.HLE/Input/Touch/TouchPoint.cs

diff --git a/Ryujinx.HLE/DeviceMemory.cs b/Ryujinx.HLE/DeviceMemory.cs
index 38864bc2d7..22945b83c0 100644
--- a/Ryujinx.HLE/DeviceMemory.cs
+++ b/Ryujinx.HLE/DeviceMemory.cs
@@ -1,6 +1,7 @@
 using ARMeilleure.Memory;
 using System;
 using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
 
 namespace Ryujinx.HLE
 {
@@ -64,6 +65,11 @@ namespace Ryujinx.HLE
             return Marshal.PtrToStructure<T>((IntPtr)(_ramPtr + position));
         }
 
+        public unsafe ref T GetStructRef<T>(long position)
+        {
+            return ref Unsafe.AsRef<T>((void*)(IntPtr)(_ramPtr + position));
+        }
+
         public void WriteSByte(long position, sbyte value)
         {
             WriteByte(position, (byte)value);
diff --git a/Ryujinx.HLE/Exceptions/InvalidStructLayoutException.cs b/Ryujinx.HLE/Exceptions/InvalidStructLayoutException.cs
new file mode 100644
index 0000000000..f4ccb7ba0a
--- /dev/null
+++ b/Ryujinx.HLE/Exceptions/InvalidStructLayoutException.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.HLE.Exceptions
+{
+    public class InvalidStructLayoutException<T> : Exception 
+    {
+        static readonly Type _structType = typeof(T);
+
+        public InvalidStructLayoutException(string message) : base(message) {}
+        
+        public InvalidStructLayoutException(int expectedSize) : 
+            base($"Type {_structType.Name} has the wrong size. Expected: {expectedSize} bytes, Got: {Unsafe.SizeOf<T>()} bytes") {}
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Applets/AppletManager.cs b/Ryujinx.HLE/HOS/Applets/AppletManager.cs
index e731454048..1cba9ec91b 100644
--- a/Ryujinx.HLE/HOS/Applets/AppletManager.cs
+++ b/Ryujinx.HLE/HOS/Applets/AppletManager.cs
@@ -13,6 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets
             _appletMapping = new Dictionary<AppletId, Type>
             {
                 { AppletId.PlayerSelect,     typeof(PlayerSelectApplet)     },
+                { AppletId.Controller,       typeof(ControllerApplet)       },
                 { AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) }
             };
         }
diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs
new file mode 100644
index 0000000000..5bfffdb25f
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs
@@ -0,0 +1,114 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Services.Hid;
+using Ryujinx.HLE.HOS.Services.Am.AppletAE;
+
+using static Ryujinx.HLE.HOS.Services.Hid.HidServer.HidUtils;
+
+namespace Ryujinx.HLE.HOS.Applets
+{
+    internal class ControllerApplet : IApplet
+    {
+        private Horizon _system;
+
+        private AppletSession _normalSession;
+
+        public event EventHandler AppletStateChanged;
+
+        public ControllerApplet(Horizon system)
+        {
+            _system = system;
+        }
+
+        unsafe public ResultCode Start(AppletSession normalSession,
+                                       AppletSession interactiveSession)
+        {
+            _normalSession = normalSession;
+
+            byte[] launchParams = _normalSession.Pop();
+            byte[] controllerSupportArgPrivate = _normalSession.Pop();
+            ControllerSupportArgPrivate privateArg = IApplet.ReadStruct<ControllerSupportArgPrivate>(controllerSupportArgPrivate);
+
+            Logger.PrintStub(LogClass.ServiceHid, $"ControllerApplet ArgPriv {privateArg.PrivateSize} {privateArg.ArgSize} {privateArg.Mode}" +
+                        $"HoldType:{(NpadJoyHoldType)privateArg.NpadJoyHoldType} StyleSets:{(ControllerType)privateArg.NpadStyleSet}");
+
+            if (privateArg.Mode != ControllerSupportMode.ShowControllerSupport)
+            {
+                _normalSession.Push(BuildResponse()); // Dummy response for other modes
+                AppletStateChanged?.Invoke(this, null);
+
+                return ResultCode.Success;
+            }
+
+            byte[] controllerSupportArg = _normalSession.Pop();
+
+            ControllerSupportArgHeader argHeader;
+
+            if (privateArg.ArgSize == Marshal.SizeOf<ControllerSupportArg>())
+            {
+                ControllerSupportArg arg = IApplet.ReadStruct<ControllerSupportArg>(controllerSupportArg);
+                argHeader = arg.Header;
+                // Read enable text here?
+            }
+            else
+            {
+                Logger.PrintStub(LogClass.ServiceHid, $"Unknown revision of ControllerSupportArg.");
+
+                argHeader = IApplet.ReadStruct<ControllerSupportArgHeader>(controllerSupportArg); // Read just the header
+            }
+
+            Logger.PrintStub(LogClass.ServiceHid, $"ControllerApplet Arg {argHeader.PlayerCountMin} {argHeader.PlayerCountMax} {argHeader.EnableTakeOverConnection} {argHeader.EnableSingleMode}");
+
+            // Currently, the only purpose of this applet is to help 
+            // choose the primary input controller for the game
+            // TODO: Ideally should hook back to HID.Controller. When applet is called, can choose appropriate controller and attach to appropriate id.
+            if (argHeader.PlayerCountMin > 1)
+            {
+                Logger.PrintWarning(LogClass.ServiceHid, "More than one controller was requested.");
+            }
+
+            ControllerSupportResultInfo result = new ControllerSupportResultInfo
+            {
+                PlayerCount = 1,
+                SelectedId = (uint)GetNpadIdTypeFromIndex(_system.Device.Hid.Npads.PrimaryController)
+            };
+
+            Logger.PrintStub(LogClass.ServiceHid, $"ControllerApplet ReturnResult {result.PlayerCount} {result.SelectedId}");
+
+            _normalSession.Push(BuildResponse(result));
+            AppletStateChanged?.Invoke(this, null);
+
+            return ResultCode.Success;
+        }
+
+        public ResultCode GetResult()
+        {
+            return ResultCode.Success;
+        }
+
+        private byte[] BuildResponse(ControllerSupportResultInfo result)
+        {
+            using (MemoryStream stream = new MemoryStream())
+            using (BinaryWriter writer = new BinaryWriter(stream))
+            {
+                writer.Write(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref result, Unsafe.SizeOf<ControllerSupportResultInfo>())));
+
+                return stream.ToArray();
+            }
+        }
+
+        private byte[] BuildResponse()
+        {
+            using (MemoryStream stream = new MemoryStream())
+            using (BinaryWriter writer = new BinaryWriter(stream))
+            {
+                writer.Write((ulong)ResultCode.Success);
+
+                return stream.ToArray();
+            }
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArg.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArg.cs
new file mode 100644
index 0000000000..62ebff3000
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArg.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.HLE.HOS.Applets
+{
+    // (8.0.0+ version)
+    unsafe struct ControllerSupportArg
+    {
+        public ControllerSupportArgHeader Header;
+        public fixed uint IdentificationColor[8];
+        public byte EnableExplainText;
+        public fixed byte ExplainText[8 * 0x81];
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgHeader.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgHeader.cs
new file mode 100644
index 0000000000..dfe2609340
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgHeader.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.HLE.HOS.Applets
+{
+    struct ControllerSupportArgHeader
+    {
+        public sbyte PlayerCountMin;
+        public sbyte PlayerCountMax;
+        public byte EnableTakeOverConnection;
+        public byte EnableLeftJustify;
+        public byte EnablePermitJoyDual;
+        public byte EnableSingleMode;
+        public byte EnableIdentificationColor;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgPrivate.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgPrivate.cs
new file mode 100644
index 0000000000..2e393de47b
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgPrivate.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.HLE.HOS.Applets
+{
+    struct ControllerSupportArgPrivate
+    {
+        public uint PrivateSize;
+        public uint ArgSize;
+        public byte Flag0;
+        public byte Flag1;
+        public ControllerSupportMode Mode;
+        public byte ControllerSupportCaller;
+        public uint NpadStyleSet;
+        public uint NpadJoyHoldType;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportMode.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportMode.cs
new file mode 100644
index 0000000000..9496c1dd6d
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportMode.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.HLE.HOS.Applets
+{
+    enum ControllerSupportMode : byte
+    {
+        ShowControllerSupport = 0,
+        ShowControllerStrapGuide = 1,
+        ShowControllerFirmwareUpdate = 2
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportResultInfo.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportResultInfo.cs
new file mode 100644
index 0000000000..4fcd37db42
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportResultInfo.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.HLE.HOS.Applets
+{
+    unsafe struct ControllerSupportResultInfo
+    {
+        public sbyte PlayerCount;
+        fixed byte _padding[3];
+        public uint SelectedId;
+        public uint Result;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Applets/IApplet.cs b/Ryujinx.HLE/HOS/Applets/IApplet.cs
index c2d4aada1f..b10ede68f6 100644
--- a/Ryujinx.HLE/HOS/Applets/IApplet.cs
+++ b/Ryujinx.HLE/HOS/Applets/IApplet.cs
@@ -1,5 +1,6 @@
 using Ryujinx.HLE.HOS.Services.Am.AppletAE;
 using System;
+using System.Runtime.InteropServices;
 
 namespace Ryujinx.HLE.HOS.Applets
 {
@@ -11,5 +12,10 @@ namespace Ryujinx.HLE.HOS.Applets
                          AppletSession interactiveSession);
 
         ResultCode GetResult();
+
+        static T ReadStruct<T>(ReadOnlySpan<byte> data) where T : struct
+        {
+            return MemoryMarshal.Cast<byte, T>(data)[0];
+        }
     }
 }
diff --git a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs
index e142838cab..ed54eb98f4 100644
--- a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs
+++ b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs
@@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Applets
             var keyboardConfig = _normalSession.Pop();
             var transferMemory = _normalSession.Pop();
 
-            _keyboardConfig = ReadStruct<SoftwareKeyboardConfig>(keyboardConfig);
+            _keyboardConfig = IApplet.ReadStruct<SoftwareKeyboardConfig>(keyboardConfig);
 
             if (_keyboardConfig.UseUtf8)
             {
@@ -176,20 +176,5 @@ namespace Ryujinx.HLE.HOS.Applets
                 return stream.ToArray();
             }
         }
-
-        private static T ReadStruct<T>(byte[] data)
-            where T : struct
-        {
-            GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
-
-            try
-            {    
-                return Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
-            }
-            finally
-            {
-                handle.Free();
-            }
-        }
     }
 }
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Hid.cs b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs
new file mode 100644
index 0000000000..e07577eda1
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs
@@ -0,0 +1,88 @@
+using Ryujinx.Common;
+using Ryujinx.HLE.Exceptions;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public class Hid
+    {
+        private readonly Switch _device;
+        private long _hidMemoryAddress;
+
+        internal ref HidSharedMemory SharedMemory => ref _device.Memory.GetStructRef<HidSharedMemory>(_hidMemoryAddress);
+        internal const int SharedMemEntryCount = 17;
+
+        public DebugPadDevice DebugPad;
+        public TouchDevice Touchscreen;
+        public MouseDevice Mouse;
+        public KeyboardDevice Keyboard;
+        public NpadDevices Npads;
+
+        static Hid()
+        {
+            if (Unsafe.SizeOf<ShMemDebugPad>() != 0x400)
+            {
+                throw new InvalidStructLayoutException<ShMemDebugPad>(0x400);
+            }
+            if (Unsafe.SizeOf<ShMemTouchScreen>() != 0x3000)
+            {
+                throw new InvalidStructLayoutException<ShMemTouchScreen>(0x3000);
+            }
+            if (Unsafe.SizeOf<ShMemKeyboard>() != 0x400)
+            {
+                throw new InvalidStructLayoutException<ShMemKeyboard>(0x400);
+            }
+            if (Unsafe.SizeOf<ShMemMouse>() != 0x400)
+            {
+                throw new InvalidStructLayoutException<ShMemMouse>(0x400);
+            }
+            if (Unsafe.SizeOf<ShMemNpad>() != 0x5000)
+            {
+                throw new InvalidStructLayoutException<ShMemNpad>(0x5000);
+            }
+            if (Unsafe.SizeOf<HidSharedMemory>() != Horizon.HidSize)
+            {
+                throw new InvalidStructLayoutException<HidSharedMemory>(Horizon.HidSize);
+            }
+        }
+
+        public Hid(in Switch device, long sharedHidMemoryAddress)
+        {
+            _device = device;
+            _hidMemoryAddress = sharedHidMemoryAddress;
+
+            device.Memory.FillWithZeros(sharedHidMemoryAddress, Horizon.HidSize);
+        }
+
+        public void InitDevices()
+        {
+            DebugPad = new DebugPadDevice(_device, true);
+            Touchscreen = new TouchDevice(_device, true);
+            Mouse = new MouseDevice(_device, false);
+            Keyboard = new KeyboardDevice(_device, false);
+            Npads = new NpadDevices(_device, true);
+        }
+
+        public ControllerKeys UpdateStickButtons(JoystickPosition leftStick, JoystickPosition rightStick)
+        {
+            ControllerKeys result = 0;
+
+            result |= (leftStick.Dx < 0) ? ControllerKeys.LStickLeft : result;
+            result |= (leftStick.Dx > 0) ? ControllerKeys.LStickRight : result;
+            result |= (leftStick.Dy < 0) ? ControllerKeys.LStickDown : result;
+            result |= (leftStick.Dy > 0) ? ControllerKeys.LStickUp : result;
+
+            result |= (rightStick.Dx < 0) ? ControllerKeys.RStickLeft : result;
+            result |= (rightStick.Dx > 0) ? ControllerKeys.RStickRight : result;
+            result |= (rightStick.Dy < 0) ? ControllerKeys.RStickDown : result;
+            result |= (rightStick.Dy > 0) ? ControllerKeys.RStickUp : result;
+
+            return result;
+        }
+
+        internal static ulong GetTimestampTicks()
+        {
+            return (ulong)PerformanceCounter.ElapsedMilliseconds * 19200;
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs
new file mode 100644
index 0000000000..59d6dfa3eb
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs
@@ -0,0 +1,29 @@
+using static Ryujinx.HLE.HOS.Services.Hid.Hid;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public abstract class BaseDevice
+    {
+        protected readonly Switch _device;
+        public bool Active;
+
+        public BaseDevice(Switch device, bool active)
+        {
+            _device = device;
+            Active = active;
+        }
+
+        internal static int UpdateEntriesHeader(ref CommonEntriesHeader header, out int previousEntry)
+        {
+            header.NumEntries = SharedMemEntryCount;
+            header.MaxEntryIndex = SharedMemEntryCount - 1;
+
+            previousEntry = (int)header.LatestEntry;
+            header.LatestEntry = (header.LatestEntry + 1) % SharedMemEntryCount;
+
+            header.TimestampTicks = GetTimestampTicks();
+
+            return (int)header.LatestEntry; // EntryCount shouldn't overflow int
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs
new file mode 100644
index 0000000000..77e9205f00
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs
@@ -0,0 +1,24 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public class DebugPadDevice : BaseDevice
+    {
+        public DebugPadDevice(Switch device, bool active) : base(device, active) { }
+
+        public void Update()
+        {
+            ref ShMemDebugPad debugPad = ref _device.Hid.SharedMemory.DebugPad;
+
+            int currentIndex = UpdateEntriesHeader(ref debugPad.Header, out int previousIndex);
+
+            if (!Active)
+            {
+                return;
+            }
+
+            ref DebugPadEntry currentEntry = ref debugPad.Entries[currentIndex];
+            DebugPadEntry previousEntry = debugPad.Entries[previousIndex];
+
+            currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs
new file mode 100644
index 0000000000..e8ed6a3e6a
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs
@@ -0,0 +1,32 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public class KeyboardDevice : BaseDevice
+    {
+        public KeyboardDevice(Switch device, bool active) : base(device, active) { }
+
+        public unsafe void Update(KeyboardInput keyState)
+        {
+            ref ShMemKeyboard keyboard = ref _device.Hid.SharedMemory.Keyboard;
+
+            int currentIndex = UpdateEntriesHeader(ref keyboard.Header, out int previousIndex);
+
+            if (!Active)
+            {
+                return;
+            }
+
+            ref KeyboardState currentEntry = ref keyboard.Entries[currentIndex];
+            KeyboardState previousEntry = keyboard.Entries[previousIndex];
+
+            currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
+            currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1;
+
+            for (int i = 0; i < 8; ++i)
+            {
+                currentEntry.Keys[i] = (uint)keyState.Keys[i];
+            }
+
+            currentEntry.Modifier = (ulong)keyState.Modifier;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs
new file mode 100644
index 0000000000..ee58a563f8
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs
@@ -0,0 +1,37 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public class MouseDevice : BaseDevice
+    {
+        public MouseDevice(Switch device, bool active) : base(device, active) { }
+
+        public void Update(int mouseX, int mouseY, int buttons = 0, int scrollX = 0, int scrollY = 0)
+        {
+            ref ShMemMouse mouse = ref _device.Hid.SharedMemory.Mouse;
+
+            int currentIndex = UpdateEntriesHeader(ref mouse.Header, out int previousIndex);
+
+            if (!Active)
+            {
+                return;
+            }
+
+            ref MouseState currentEntry = ref mouse.Entries[currentIndex];
+            MouseState previousEntry = mouse.Entries[previousIndex];
+
+            currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
+            currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1;
+
+            currentEntry.Buttons = (ulong)buttons;
+
+            currentEntry.Position = new MousePosition
+            {
+                X = mouseX,
+                Y = mouseY,
+                VelocityX = mouseX - previousEntry.Position.X,
+                VelocityY = mouseY - previousEntry.Position.Y,
+                ScrollVelocityX = scrollX,
+                ScrollVelocityY = scrollY
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
new file mode 100644
index 0000000000..ff33031276
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
@@ -0,0 +1,332 @@
+using System;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Common.Logging;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public class NpadDevices : BaseDevice
+    {
+        internal NpadJoyHoldType JoyHold = NpadJoyHoldType.Vertical;
+        internal bool SixAxisActive = false; // TODO: link to hidserver when implemented
+
+        enum FilterState
+        {
+            Unconfigured = 0,
+            Configured = 1,
+            Accepted = 2
+        }
+
+        struct NpadConfig
+        {
+            public ControllerType ConfiguredType;
+            public FilterState State;
+        }
+
+        private const int _maxControllers = 9; // Players1-8 and Handheld
+        private NpadConfig[] _configuredNpads;
+
+        private ControllerType _supportedStyleSets = ControllerType.ProController |
+                                                     ControllerType.JoyconPair |
+                                                     ControllerType.JoyconLeft |
+                                                     ControllerType.JoyconRight |
+                                                     ControllerType.Handheld;
+
+        public ControllerType SupportedStyleSets
+        {
+            get { return _supportedStyleSets; }
+            set
+            {
+                if (_supportedStyleSets != value) // Deal with spamming
+                {
+                    _supportedStyleSets = value;
+                    MatchControllers();
+                }
+            }
+        }
+
+        public PlayerIndex PrimaryController { get; set; } = PlayerIndex.Unknown;
+
+        KEvent[] _styleSetUpdateEvents;
+
+        static readonly Array3<BatteryCharge> _fullBattery;
+
+        public NpadDevices(Switch device, bool active = true) : base(device, active)
+        {
+            _configuredNpads = new NpadConfig[_maxControllers];
+
+            _styleSetUpdateEvents = new KEvent[_maxControllers];
+
+            for (int i = 0; i < _styleSetUpdateEvents.Length; ++i)
+            {
+                _styleSetUpdateEvents[i] = new KEvent(_device.System);
+            }
+
+            _fullBattery[0] = _fullBattery[1] = _fullBattery[2] = BatteryCharge.Percent100;
+        }
+
+        public void AddControllers(params ControllerConfig[] configs)
+        {
+            for (int i = 0; i < configs.Length; ++i)
+            {
+                PlayerIndex player = configs[i].Player;
+                ControllerType controllerType = configs[i].Type;
+
+                if (player > PlayerIndex.Handheld)
+                {
+                    throw new ArgumentOutOfRangeException("Player must be Player1-8 or Handheld");
+                }
+
+                if (controllerType == ControllerType.Handheld)
+                {
+                    player = PlayerIndex.Handheld;
+                }
+
+                _configuredNpads[(int)player] = new NpadConfig { ConfiguredType = controllerType, State = FilterState.Configured };
+            }
+
+            MatchControllers();
+        }
+
+        void MatchControllers()
+        {
+            PrimaryController = PlayerIndex.Unknown;
+
+            for (int i = 0; i < _configuredNpads.Length; ++i)
+            {
+                ref NpadConfig config = ref _configuredNpads[i];
+
+                if (config.State == FilterState.Unconfigured)
+                {
+                    continue; // Ignore unconfigured
+                }
+
+                if ((config.ConfiguredType & _supportedStyleSets) == 0)
+                {
+                    Logger.PrintWarning(LogClass.Hid, $"ControllerType {config.ConfiguredType} (connected to {(PlayerIndex)i}) not supported by game. Removing...");
+
+                    config.State = FilterState.Configured;
+                    _device.Hid.SharedMemory.Npads[i] = new ShMemNpad(); // Zero it
+
+                    continue;
+                }
+
+                InitController((PlayerIndex)i, config.ConfiguredType);
+            }
+
+            // Couldn't find any matching configuration. Reassign to something that works.
+            if (PrimaryController == PlayerIndex.Unknown)
+            {
+                ControllerType[] npadsTypeList = (ControllerType[])Enum.GetValues(typeof(ControllerType));
+
+                // Skip None Type
+                for (int i = 1; i < npadsTypeList.Length; ++i)
+                {
+                    ControllerType controllerType = npadsTypeList[i];
+                    if ((controllerType & _supportedStyleSets) != 0)
+                    {
+                        Logger.PrintWarning(LogClass.Hid, $"No matching controllers found. Reassigning input as ControllerType {controllerType}...");
+
+                        InitController(controllerType == ControllerType.Handheld ? PlayerIndex.Handheld : PlayerIndex.Player1, controllerType);
+
+                        return;
+                    }
+                }
+
+                Logger.PrintError(LogClass.Hid, "Couldn't find any appropriate controller.");
+            }
+        }
+
+        internal ref KEvent GetStyleSetUpdateEvent(PlayerIndex player)
+        {
+            return ref _styleSetUpdateEvents[(int)player];
+        }
+
+        void InitController(PlayerIndex player, ControllerType type)
+        {
+            if (type == ControllerType.Handheld)
+            {
+                player = PlayerIndex.Handheld;
+            }
+
+            ref ShMemNpad controller = ref _device.Hid.SharedMemory.Npads[(int)player];
+
+            controller = new ShMemNpad(); // Zero it
+
+            // TODO: Allow customizing colors at config
+            NpadStateHeader defaultHeader = new NpadStateHeader
+            {
+                IsHalf = false,
+                SingleColorBody = NpadColor.BodyGray,
+                SingleColorButtons = NpadColor.ButtonGray,
+                LeftColorBody = NpadColor.BodyNeonBlue,
+                LeftColorButtons = NpadColor.ButtonGray,
+                RightColorBody = NpadColor.BodyNeonRed,
+                RightColorButtons = NpadColor.ButtonGray
+            };
+
+            controller.SystemProperties = NpadSystemProperties.PowerInfo0Connected |
+                                          NpadSystemProperties.PowerInfo1Connected |
+                                          NpadSystemProperties.PowerInfo2Connected;
+
+            controller.BatteryState = _fullBattery;
+
+            switch (type)
+            {
+                case ControllerType.ProController:
+                    defaultHeader.Type = ControllerType.ProController;
+                    controller.DeviceType = DeviceType.FullKey;
+                    controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented |
+                                                   NpadSystemProperties.PlusButtonCapability |
+                                                   NpadSystemProperties.MinusButtonCapability;
+                    break;
+                case ControllerType.Handheld:
+                    defaultHeader.Type = ControllerType.Handheld;
+                    controller.DeviceType = DeviceType.HandheldLeft |
+                                                   DeviceType.HandheldRight;
+                    controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented |
+                                                   NpadSystemProperties.PlusButtonCapability |
+                                                   NpadSystemProperties.MinusButtonCapability;
+                    break;
+                case ControllerType.JoyconPair:
+                    defaultHeader.Type = ControllerType.JoyconPair;
+                    controller.DeviceType = DeviceType.JoyLeft |
+                                                   DeviceType.JoyRight;
+                    controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented |
+                                                   NpadSystemProperties.PlusButtonCapability |
+                                                   NpadSystemProperties.MinusButtonCapability;
+                    break;
+                case ControllerType.JoyconLeft:
+                    defaultHeader.Type = ControllerType.JoyconLeft;
+                    defaultHeader.IsHalf = true;
+                    controller.DeviceType = DeviceType.JoyLeft;
+                    controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented |
+                                                   NpadSystemProperties.MinusButtonCapability;
+                    break;
+                case ControllerType.JoyconRight:
+                    defaultHeader.Type = ControllerType.JoyconRight;
+                    defaultHeader.IsHalf = true;
+                    controller.DeviceType = DeviceType.JoyRight;
+                    controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented |
+                                                   NpadSystemProperties.PlusButtonCapability;
+                    break;
+                case ControllerType.Pokeball:
+                    defaultHeader.Type = ControllerType.Pokeball;
+                    controller.DeviceType = DeviceType.Palma;
+                    break;
+            }
+
+            controller.Header = defaultHeader;
+
+            if (PrimaryController == PlayerIndex.Unknown)
+            {
+                PrimaryController = player;
+            }
+
+            _configuredNpads[(int)player].State = FilterState.Accepted;
+
+            _styleSetUpdateEvents[(int)player].ReadableEvent.Signal();
+
+            Logger.PrintInfo(LogClass.Hid, $"Connected ControllerType {type} to PlayerIndex {player}");
+        }
+
+        static NpadLayoutsIndex ControllerTypeToLayout(ControllerType controllerType)
+        => controllerType switch
+        {
+            ControllerType.ProController => NpadLayoutsIndex.ProController,
+            ControllerType.Handheld => NpadLayoutsIndex.Handheld,
+            ControllerType.JoyconPair => NpadLayoutsIndex.JoyDual,
+            ControllerType.JoyconLeft => NpadLayoutsIndex.JoyLeft,
+            ControllerType.JoyconRight => NpadLayoutsIndex.JoyRight,
+            ControllerType.Pokeball => NpadLayoutsIndex.Pokeball,
+            _ => NpadLayoutsIndex.SystemExternal
+        };
+
+        public void SetGamepadsInput(params GamepadInput[] states)
+        {
+            UpdateAllEntries();
+
+            for (int i = 0; i < states.Length; ++i)
+            {
+                SetGamepadState(states[i].PlayerId, states[i].Buttons, states[i].LStick, states[i].RStick);
+            }
+        }
+
+        void SetGamepadState(PlayerIndex player, ControllerKeys buttons,
+                    JoystickPosition leftJoystick, JoystickPosition rightJoystick)
+        {
+            if (player == PlayerIndex.Auto)
+            {
+                player = PrimaryController;
+            }
+
+            if (player == PlayerIndex.Unknown)
+            {
+                return;
+            }
+
+            if (_configuredNpads[(int)player].State != FilterState.Accepted)
+            {
+                return;
+            }
+
+            ref ShMemNpad currentNpad = ref _device.Hid.SharedMemory.Npads[(int)player];
+            ref NpadLayout currentLayout = ref currentNpad.Layouts[(int)ControllerTypeToLayout(currentNpad.Header.Type)];
+            ref NpadState currentEntry = ref currentLayout.Entries[(int)currentLayout.Header.LatestEntry];
+
+            currentEntry.Buttons = buttons;
+            currentEntry.LStickX = leftJoystick.Dx;
+            currentEntry.LStickY = leftJoystick.Dy;
+            currentEntry.RStickX = rightJoystick.Dx;
+            currentEntry.RStickY = rightJoystick.Dy;
+
+            // Mirror data to Default layout just in case
+            ref NpadLayout mainLayout = ref currentNpad.Layouts[(int)NpadLayoutsIndex.SystemExternal];
+            mainLayout.Entries[(int)mainLayout.Header.LatestEntry] = currentEntry;
+        }
+
+        void UpdateAllEntries()
+        {
+            ref Array10<ShMemNpad> controllers = ref _device.Hid.SharedMemory.Npads;
+            for (int i = 0; i < controllers.Length; ++i)
+            {
+                ref Array7<NpadLayout> layouts = ref controllers[i].Layouts;
+                for (int l = 0; l < layouts.Length; ++l)
+                {
+                    ref NpadLayout currentLayout = ref layouts[l];
+                    int currentIndex = UpdateEntriesHeader(ref currentLayout.Header, out int previousIndex);
+
+                    ref NpadState currentEntry = ref currentLayout.Entries[currentIndex];
+                    NpadState previousEntry = currentLayout.Entries[previousIndex];
+
+                    currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
+                    currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1;
+
+                    if (controllers[i].Header.Type == ControllerType.None)
+                    {
+                        continue;
+                    }
+
+                    currentEntry.ConnectionState = NpadConnectionState.ControllerStateConnected;
+
+                    switch (controllers[i].Header.Type)
+                    {
+                        case ControllerType.Handheld:
+                        case ControllerType.ProController:
+                            currentEntry.ConnectionState |= NpadConnectionState.ControllerStateWired;
+                            break;
+                        case ControllerType.JoyconPair:
+                            currentEntry.ConnectionState |= NpadConnectionState.JoyLeftConnected |
+                                                            NpadConnectionState.JoyRightConnected;
+                            break;
+                        case ControllerType.JoyconLeft:
+                            currentEntry.ConnectionState |= NpadConnectionState.JoyLeftConnected;
+                            break;
+                        case ControllerType.JoyconRight:
+                            currentEntry.ConnectionState |= NpadConnectionState.JoyRightConnected;
+                            break;
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
new file mode 100644
index 0000000000..10c3445304
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public class TouchDevice : BaseDevice
+    {
+        public TouchDevice(Switch device, bool active) : base(device, active) { }
+
+        public void Update(params TouchPoint[] points)
+        {
+            ref ShMemTouchScreen touchscreen = ref _device.Hid.SharedMemory.TouchScreen;
+
+            int currentIndex = UpdateEntriesHeader(ref touchscreen.Header, out int previousIndex);
+
+            if (!Active)
+            {
+                return;
+            }
+
+            ref TouchScreenState currentEntry = ref touchscreen.Entries[currentIndex];
+            TouchScreenState previousEntry = touchscreen.Entries[previousIndex];
+
+            currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
+            currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1;
+
+            currentEntry.NumTouches = (ulong)points.Length;
+
+            int pointsLength = Math.Min(points.Length, currentEntry.Touches.Length);
+
+            for (int i = 0; i < pointsLength; ++i)
+            {
+                TouchPoint pi = points[i];
+                currentEntry.Touches[i] = new TouchScreenStateData
+                {
+                    SampleTimestamp = currentEntry.SampleTimestamp,
+                    X = pi.X,
+                    Y = pi.Y,
+                    TouchIndex = (uint)i,
+                    DiameterX = pi.DiameterX,
+                    DiameterY = pi.DiameterY,
+                    Angle = pi.Angle
+                };
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/ControllerConfig.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/ControllerConfig.cs
new file mode 100644
index 0000000000..e59ba312d5
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/ControllerConfig.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public struct ControllerConfig
+    {
+        public PlayerIndex Player;
+        public ControllerType Type;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/GamepadInput.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/GamepadInput.cs
new file mode 100644
index 0000000000..2488057ed7
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/GamepadInput.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public struct GamepadInput
+    {
+        public PlayerIndex PlayerId;
+        public ControllerKeys Buttons;
+        public JoystickPosition LStick;
+        public JoystickPosition RStick;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs
similarity index 70%
rename from Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs
index 1442bc60cd..6df477d6c9 100644
--- a/Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.HLE.Input
+namespace Ryujinx.HLE.HOS.Services.Hid
 {
     public struct JoystickPosition
     {
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs
new file mode 100644
index 0000000000..2668127092
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public struct KeyboardInput
+    {
+        public int Modifier;
+        public int[] Keys;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
new file mode 100644
index 0000000000..d1172dd06b
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public struct TouchPoint
+    {
+        public uint X;
+        public uint Y;
+        public uint DiameterX;
+        public uint DiameterY;
+        public uint Angle;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs
index c89ea3067b..c2cd843291 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs
@@ -1,46 +1,39 @@
-using Ryujinx.HLE.Input;
-using System;
+using System;
 
 namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
 {
     static class HidUtils
     {
-        public static ControllerId GetIndexFromNpadIdType(HidNpadIdType npadIdType)
+        public static PlayerIndex GetIndexFromNpadIdType(NpadIdType npadIdType)
+        => npadIdType switch
         {
-            switch (npadIdType)
-            {
-                case HidNpadIdType.Player1:  return ControllerId.ControllerPlayer1;
-                case HidNpadIdType.Player2:  return ControllerId.ControllerPlayer2;
-                case HidNpadIdType.Player3:  return ControllerId.ControllerPlayer3;
-                case HidNpadIdType.Player4:  return ControllerId.ControllerPlayer4;
-                case HidNpadIdType.Player5:  return ControllerId.ControllerPlayer5;
-                case HidNpadIdType.Player6:  return ControllerId.ControllerPlayer6;
-                case HidNpadIdType.Player7:  return ControllerId.ControllerPlayer7;
-                case HidNpadIdType.Player8:  return ControllerId.ControllerPlayer8;
-                case HidNpadIdType.Handheld: return ControllerId.ControllerHandheld;
-                case HidNpadIdType.Unknown:  return ControllerId.ControllerUnknown;
+            NpadIdType.Player1  => PlayerIndex.Player1,
+            NpadIdType.Player2  => PlayerIndex.Player2,
+            NpadIdType.Player3  => PlayerIndex.Player3,
+            NpadIdType.Player4  => PlayerIndex.Player4,
+            NpadIdType.Player5  => PlayerIndex.Player5,
+            NpadIdType.Player6  => PlayerIndex.Player6,
+            NpadIdType.Player7  => PlayerIndex.Player7,
+            NpadIdType.Player8  => PlayerIndex.Player8,
+            NpadIdType.Handheld => PlayerIndex.Handheld,
+            NpadIdType.Unknown  => PlayerIndex.Unknown,
+            _                   => throw new ArgumentOutOfRangeException(nameof(npadIdType))
+        };
 
-                default: throw new ArgumentOutOfRangeException(nameof(npadIdType));
-            }
-        }
-
-        public static HidNpadIdType GetNpadIdTypeFromIndex(ControllerId index)
+        public static NpadIdType GetNpadIdTypeFromIndex(PlayerIndex index)
+        => index switch
         {
-            switch (index)
-            {
-                case ControllerId.ControllerPlayer1:  return HidNpadIdType.Player1;
-                case ControllerId.ControllerPlayer2:  return HidNpadIdType.Player2;
-                case ControllerId.ControllerPlayer3:  return HidNpadIdType.Player3;
-                case ControllerId.ControllerPlayer4:  return HidNpadIdType.Player4;
-                case ControllerId.ControllerPlayer5:  return HidNpadIdType.Player5;
-                case ControllerId.ControllerPlayer6:  return HidNpadIdType.Player6;
-                case ControllerId.ControllerPlayer7:  return HidNpadIdType.Player7;
-                case ControllerId.ControllerPlayer8:  return HidNpadIdType.Player8;
-                case ControllerId.ControllerHandheld: return HidNpadIdType.Handheld;
-                case ControllerId.ControllerUnknown:  return HidNpadIdType.Unknown;
-
-                default: throw new ArgumentOutOfRangeException(nameof(index));
-            }
-        }
+            PlayerIndex.Player1  => NpadIdType.Player1,
+            PlayerIndex.Player2  => NpadIdType.Player2,
+            PlayerIndex.Player3  => NpadIdType.Player3,
+            PlayerIndex.Player4  => NpadIdType.Player4,
+            PlayerIndex.Player5  => NpadIdType.Player5,
+            PlayerIndex.Player6  => NpadIdType.Player6,
+            PlayerIndex.Player7  => NpadIdType.Player7,
+            PlayerIndex.Player8  => NpadIdType.Player8,
+            PlayerIndex.Handheld => NpadIdType.Handheld,
+            PlayerIndex.Unknown  => NpadIdType.Unknown,
+            _                    => throw new ArgumentOutOfRangeException(nameof(index))
+        };
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadHandheldActivationMode.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadHandheldActivationMode.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadHandheldActivationMode.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadHandheldActivationMode.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyAssignmentMode.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadJoyAssignmentMode.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyAssignmentMode.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadJoyAssignmentMode.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyDeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadJoyDeviceType.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyDeviceType.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadJoyDeviceType.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidAccelerometerParameters.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidAccelerometerParameters.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidAccelerometerParameters.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidAccelerometerParameters.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidGyroscopeZeroDriftMode.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidGyroscopeZeroDriftMode.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidGyroscopeZeroDriftMode.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidGyroscopeZeroDriftMode.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidSensorFusionParameters.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidSensorFusionParameters.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidSensorFusionParameters.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidSensorFusionParameters.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDevicePosition.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDevicePosition.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDevicePosition.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDevicePosition.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceType.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceValue.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceValue.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceValue.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceValue.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationValue.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs
similarity index 100%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationValue.cs
rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs
diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
index 1af9baf872..e34c421344 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
@@ -3,7 +3,6 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Hid.HidServer;
-using Ryujinx.HLE.Input;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Hid
@@ -11,7 +10,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
     [Service("hid")]
     class IHidServer : IpcService
     {
-        private KEvent _npadStyleSetUpdateEvent;
         private KEvent _xpadIdEvent;
         private KEvent _palmaOperationCompleteEvent;
 
@@ -22,8 +20,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         private bool _vibrationPermitted;
         private bool _usbFullKeyControllerEnabled;
 
-        private HidNpadJoyHoldType            _npadJoyHoldType;
-        private HidNpadStyle                  _npadStyleSet;
         private HidNpadJoyAssignmentMode      _npadJoyAssignmentMode;
         private HidNpadHandheldActivationMode _npadHandheldActivationMode;
         private HidGyroscopeZeroDriftMode     _gyroscopeZeroDriftMode;
@@ -39,12 +35,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
 
         public IHidServer(ServiceCtx context)
         {
-            _npadStyleSetUpdateEvent     = new KEvent(context.Device.System);
             _xpadIdEvent                 = new KEvent(context.Device.System);
             _palmaOperationCompleteEvent = new KEvent(context.Device.System);
 
-            _npadJoyHoldType            = HidNpadJoyHoldType.Vertical;
-            _npadStyleSet               = HidNpadStyle.FullKey | HidNpadStyle.Dual | HidNpadStyle.Left | HidNpadStyle.Right | HidNpadStyle.Handheld;
             _npadJoyAssignmentMode      = HidNpadJoyAssignmentMode.Dual;
             _npadHandheldActivationMode = HidNpadHandheldActivationMode.Dual;
             _gyroscopeZeroDriftMode     = HidGyroscopeZeroDriftMode.Standard;
@@ -85,6 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             long appletResourceUserId = context.RequestData.ReadInt64();
 
+            context.Device.Hid.Touchscreen.Active = true;
             Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
 
             return ResultCode.Success;
@@ -96,6 +90,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             long appletResourceUserId = context.RequestData.ReadInt64();
 
+            context.Device.Hid.Mouse.Active = true;
             Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
 
             return ResultCode.Success;
@@ -107,6 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             long appletResourceUserId = context.RequestData.ReadInt64();
 
+            context.Device.Hid.Keyboard.Active = true;
             Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
 
             return ResultCode.Success;
@@ -542,13 +538,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetSupportedNpadStyleSet(nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
         public ResultCode SetSupportedNpadStyleSet(ServiceCtx context)
         {
-            _npadStyleSet = (HidNpadStyle)context.RequestData.ReadInt32();
-
+            ControllerType type = (ControllerType)context.RequestData.ReadInt32();
             long appletResourceUserId = context.RequestData.ReadInt64();
 
-            Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadStyleSet });
+            Logger.PrintStub(LogClass.ServiceHid, new { 
+                    appletResourceUserId, 
+                    type 
+                });
 
-            _npadStyleSetUpdateEvent.ReadableEvent.Signal();
+            context.Device.Hid.Npads.SupportedStyleSets = type;
 
             return ResultCode.Success;
         }
@@ -559,9 +557,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             long appletResourceUserId = context.RequestData.ReadInt64();
 
-            context.ResponseData.Write((int)_npadStyleSet);
+            context.ResponseData.Write((int)context.Device.Hid.Npads.SupportedStyleSets);
 
-            Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadStyleSet });
+            Logger.PrintStub(LogClass.ServiceHid, new { 
+                    appletResourceUserId,
+                    context.Device.Hid.Npads.SupportedStyleSets 
+                });
 
             return ResultCode.Success;
         }
@@ -570,10 +571,17 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetSupportedNpadIdType(nn::applet::AppletResourceUserId, array<NpadIdType, 9>)
         public ResultCode SetSupportedNpadIdType(ServiceCtx context)
         {
-            long         appletResourceUserId  = context.RequestData.ReadInt64();
-            ControllerId npadIdType            = (ControllerId)context.RequestData.ReadInt64();
+            long appletResourceUserId = context.RequestData.ReadInt64();
+            long arraySize = context.Request.PtrBuff[0].Size / 4;
 
-            Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType });
+            NpadIdType[] supportedPlayerIds = new NpadIdType[arraySize];
+
+            for (int i = 0; i < arraySize; ++i)
+            {
+                supportedPlayerIds[i] = (NpadIdType)context.Memory.ReadInt32(context.Request.PtrBuff[0].Position + i * 4);
+            }
+
+            Logger.PrintStub(LogClass.ServiceHid, $"{arraySize} " + string.Join(",", supportedPlayerIds));
 
             return ResultCode.Success;
         }
@@ -584,6 +592,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             long appletResourceUserId = context.RequestData.ReadInt64();
 
+            context.Device.Hid.Npads.Active = true;
             Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
 
             return ResultCode.Success;
@@ -595,6 +604,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             long appletResourceUserId = context.RequestData.ReadInt64();
 
+            context.Device.Hid.Npads.Active = false;
             Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
 
             return ResultCode.Success;
@@ -604,11 +614,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // AcquireNpadStyleSetUpdateEventHandle(nn::applet::AppletResourceUserId, uint, ulong) -> nn::sf::NativeHandle
         public ResultCode AcquireNpadStyleSetUpdateEventHandle(ServiceCtx context)
         {
-            long appletResourceUserId = context.RequestData.ReadInt64();
-            int  npadId               = context.RequestData.ReadInt32();
-            long npadStyleSet         = context.RequestData.ReadInt64();
+            PlayerIndex npadId               = HidUtils.GetIndexFromNpadIdType((NpadIdType)context.RequestData.ReadInt32());
+            long        appletResourceUserId = context.RequestData.ReadInt64();
+            long        npadStyleSet         = context.RequestData.ReadInt64();
 
-            if (context.Process.HandleTable.GenerateHandle(_npadStyleSetUpdateEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            KEvent evnt = context.Device.Hid.Npads.GetStyleSetUpdateEvent(npadId);
+            if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out int handle) != KernelResult.Success)
             {
                 throw new InvalidOperationException("Out of handles!");
             }
@@ -624,8 +635,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // DisconnectNpad(nn::applet::AppletResourceUserId, uint NpadIdType)
         public ResultCode DisconnectNpad(ServiceCtx context)
         {
-            long appletResourceUserId = context.RequestData.ReadInt64();
-            int  npadIdType           = context.RequestData.ReadInt32();
+            NpadIdType npadIdType           = (NpadIdType)context.RequestData.ReadInt32();
+            long       appletResourceUserId = context.RequestData.ReadInt64();
 
             Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType });
 
@@ -651,10 +662,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // ActivateNpadWithRevision(nn::applet::AppletResourceUserId, int Unknown)
         public ResultCode ActivateNpadWithRevision(ServiceCtx context)
         {
+            int  revision             = context.RequestData.ReadInt32();
             long appletResourceUserId = context.RequestData.ReadInt64();
-            int  unknown              = context.RequestData.ReadInt32();
 
-            Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, unknown });
+            Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, revision });
 
             return ResultCode.Success;
         }
@@ -664,9 +675,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         public ResultCode SetNpadJoyHoldType(ServiceCtx context)
         {
             long appletResourceUserId = context.RequestData.ReadInt64();
-            _npadJoyHoldType          = (HidNpadJoyHoldType)context.RequestData.ReadInt64();
+            context.Device.Hid.Npads.JoyHold = (NpadJoyHoldType)context.RequestData.ReadInt64();
 
-            Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadJoyHoldType });
+            Logger.PrintStub(LogClass.ServiceHid, new { 
+                    appletResourceUserId, 
+                    context.Device.Hid.Npads.JoyHold 
+                });
 
             return ResultCode.Success;
         }
@@ -677,9 +691,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             long appletResourceUserId = context.RequestData.ReadInt64();
 
-            context.ResponseData.Write((long)_npadJoyHoldType);
+            context.ResponseData.Write((long)context.Device.Hid.Npads.JoyHold);
 
-            Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadJoyHoldType });
+            Logger.PrintStub(LogClass.ServiceHid, new { 
+                    appletResourceUserId, 
+                    context.Device.Hid.Npads.JoyHold 
+                });
 
             return ResultCode.Success;
         }
@@ -688,8 +705,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetNpadJoyAssignmentModeSingleByDefault(uint HidControllerId, nn::applet::AppletResourceUserId)
         public ResultCode SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx context)
         {
-            ControllerId hidControllerId      = (ControllerId)context.RequestData.ReadInt32();
-            long         appletResourceUserId = context.RequestData.ReadInt64();
+            PlayerIndex hidControllerId      = (PlayerIndex)context.RequestData.ReadInt32();
+            long        appletResourceUserId = context.RequestData.ReadInt64();
 
             _npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Single;
 
@@ -702,7 +719,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetNpadJoyAssignmentModeSingle(uint HidControllerId, nn::applet::AppletResourceUserId, long HidNpadJoyDeviceType)
         public ResultCode SetNpadJoyAssignmentModeSingle(ServiceCtx context)
         {
-            ControllerId         hidControllerId      = (ControllerId)context.RequestData.ReadInt32();
+            PlayerIndex          hidControllerId      = (PlayerIndex)context.RequestData.ReadInt32();
             long                 appletResourceUserId = context.RequestData.ReadInt64();
             HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64();
 
@@ -717,8 +734,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetNpadJoyAssignmentModeDual(uint HidControllerId, nn::applet::AppletResourceUserId)
         public ResultCode SetNpadJoyAssignmentModeDual(ServiceCtx context)
         {
-            ControllerId hidControllerId      = (ControllerId)context.RequestData.ReadInt32();
-            long         appletResourceUserId = context.RequestData.ReadInt64();
+            PlayerIndex hidControllerId      = HidUtils.GetIndexFromNpadIdType((NpadIdType)context.RequestData.ReadInt32());
+            long        appletResourceUserId = context.RequestData.ReadInt64();
 
             _npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual;
 
@@ -831,7 +848,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetNpadJoyAssignmentModeSingleWithDestination(uint HidControllerId, long HidNpadJoyDeviceType, nn::applet::AppletResourceUserId) -> bool Unknown0, uint Unknown1
         public ResultCode SetNpadJoyAssignmentModeSingleWithDestination(ServiceCtx context)
         {
-            ControllerId         hidControllerId      = (ControllerId)context.RequestData.ReadInt32();
+            PlayerIndex          hidControllerId      = (PlayerIndex)context.RequestData.ReadInt32();
             HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64();
             long                 appletResourceUserId = context.RequestData.ReadInt64();
 
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
index cd571f11e4..4851a25988 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
@@ -2,7 +2,6 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Services.Hid.HidServer;
-using Ryujinx.HLE.Input;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Hid.Irs
@@ -57,16 +56,16 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
         // GetNpadIrCameraHandle(u32) -> nn::irsensor::IrCameraHandle
         public ResultCode GetNpadIrCameraHandle(ServiceCtx context)
         {
-            HidNpadIdType npadIdType = (HidNpadIdType)context.RequestData.ReadUInt32();
+            NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32();
 
-            if (npadIdType >  HidNpadIdType.Player8 && 
-                npadIdType != HidNpadIdType.Unknown && 
-                npadIdType != HidNpadIdType.Handheld)
+            if (npadIdType >  NpadIdType.Player8 && 
+                npadIdType != NpadIdType.Unknown && 
+                npadIdType != NpadIdType.Handheld)
             {
                 return ResultCode.NpadIdOutOfRange;
             }
 
-            ControllerId irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType);
+            PlayerIndex irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType);
 
             context.ResponseData.Write((int)irCameraHandle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs
new file mode 100644
index 0000000000..5a8d51c6e3
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct Boolean32
+    {
+        private uint _value;
+        public static implicit operator bool(Boolean32 value) => (value._value & 1) != 0;
+        public static implicit operator Boolean32(bool value) => new Boolean32() { _value = value ? 1u : 0u };
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerKeys.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerKeys.cs
new file mode 100644
index 0000000000..db0319edaa
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerKeys.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    [Flags]
+    public enum ControllerKeys : long
+    {
+        A = 1 << 0,
+        B = 1 << 1,
+        X = 1 << 2,
+        Y = 1 << 3,
+        LStick = 1 << 4,
+        RStick = 1 << 5,
+        L = 1 << 6,
+        R = 1 << 7,
+        Zl = 1 << 8,
+        Zr = 1 << 9,
+        Plus = 1 << 10,
+        Minus = 1 << 11,
+        DpadLeft = 1 << 12,
+        DpadUp = 1 << 13,
+        DpadRight = 1 << 14,
+        DpadDown = 1 << 15,
+        LStickLeft = 1 << 16,
+        LStickUp = 1 << 17,
+        LStickRight = 1 << 18,
+        LStickDown = 1 << 19,
+        RStickLeft = 1 << 20,
+        RStickUp = 1 << 21,
+        RStickRight = 1 << 22,
+        RStickDown = 1 << 23,
+        SlLeft = 1 << 24,
+        SrLeft = 1 << 25,
+        SlRight = 1 << 26,
+        SrRight = 1 << 27,
+
+        // Generic Catch-all
+        Up = DpadUp | LStickUp | RStickUp,
+        Down = DpadDown | LStickDown | RStickDown,
+        Left = DpadLeft | LStickLeft | RStickLeft,
+        Right = DpadRight | LStickRight | RStickRight,
+        Sl = SlLeft | SlRight,
+        Sr = SrLeft | SrRight
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerType.cs
new file mode 100644
index 0000000000..f65c307995
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerType.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    [Flags]
+    public enum ControllerType : int
+    {
+        None,
+        ProController = 1 << 0,
+        Handheld = 1 << 1,
+        JoyconPair = 1 << 2,
+        JoyconLeft = 1 << 3,
+        JoyconRight = 1 << 4,
+        Invalid = 1 << 5,
+        Pokeball = 1 << 6,
+        SystemExternal = 1 << 29,
+        System = 1 << 30
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs
deleted file mode 100644
index 3bd3aa914d..0000000000
--- a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Hid
-{
-    public enum HidNpadJoyHoldType
-    {
-        Vertical,
-        Horizontal
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs
deleted file mode 100644
index 93717acf16..0000000000
--- a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.HOS.Services.Hid
-{
-    [Flags]
-    public enum HidNpadStyle
-    {
-        None,
-        FullKey  = 1 << 0,
-        Handheld = 1 << 1,
-        Dual     = 1 << 2,
-        Left     = 1 << 3,
-        Right    = 1 << 4,
-        Invalid  = 1 << 5
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs
new file mode 100644
index 0000000000..57b4b36669
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs
@@ -0,0 +1,37 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public enum NpadColor : int 
+    {
+        BodyGray                                      = 0x828282,
+        BodyNeonRed                                   = 0xFF3C28,
+        BodyNeonBlue                                  = 0x0AB9E6,
+        BodyNeonYellow                                = 0xE6FF00,
+        BodyNeonGreen                                 = 0x1EDC00,
+        BodyNeonPink                                  = 0xFF3278,
+        BodyRed                                       = 0xE10F00,
+        BodyBlue                                      = 0x4655F5,
+        BodyNeonPurple                                = 0xB400E6,
+        BodyNeonOrange                                = 0xFAA005,
+        BodyPokemonLetsGoPikachu                      = 0xFFDC00,
+        BodyPokemonLetsGoEevee                        = 0xC88C32,
+        BodyNintendoLaboCreatorsContestEdition        = 0xD7AA73,
+        BodyAnimalCrossingSpecialEditionLeftJoyCon    = 0x82FF96,
+        BodyAnimalCrossingSpecialEditionRightJoyCon   = 0x96F5F5,
+
+        ButtonGray                                    = 0x0F0F0F,
+        ButtonNeonRed                                 = 0x1E0A0A,
+        ButtonNeonBlue                                = 0x001E1E,
+        ButtonNeonYellow                              = 0x142800,
+        ButtonNeonGreen                               = 0x002800,
+        ButtonNeonPink                                = 0x28001E,
+        ButtonRed                                     = 0x280A0A,
+        ButtonBlue                                    = 0x00000A,
+        ButtonNeonPurple                              = 0x140014,
+        ButtonNeonOrange                              = 0x0F0A00,
+        ButtonPokemonLetsGoPikachu                    = 0x322800,
+        ButtonPokemonLetsGoEevee                      = 0x281900,
+        ButtonNintendoLaboCreatorsContestEdition      = 0x1E1914,
+        ButtonAnimalCrossingSpecialEditionLeftJoyCon  = 0x0A1E0A,
+        ButtonAnimalCrossingSpecialEditionRightJoyCon = 0x0A1E28
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadIdType.cs
similarity index 89%
rename from Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs
rename to Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadIdType.cs
index 9a3989de66..5f6a68cb05 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadIdType.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.HLE.HOS.Services.Hid
 {
-    public enum HidNpadIdType
+    public enum NpadIdType
     {
         Player1  = 0,
         Player2  = 1,
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/PlayerIndex.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/PlayerIndex.cs
new file mode 100644
index 0000000000..f4ced5df5e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/PlayerIndex.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    public enum PlayerIndex : int
+    {
+        Player1  = 0,
+        Player2  = 1,
+        Player3  = 2,
+        Player4  = 3,
+        Player5  = 4,
+        Player6  = 5,
+        Player7  = 6,
+        Player8  = 7,
+        Handheld = 8,
+        Unknown  = 9,
+        Auto     = 10    // Shouldn't be used directly
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/CommonEntriesHeader.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/CommonEntriesHeader.cs
new file mode 100644
index 0000000000..f83fdcdf52
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/CommonEntriesHeader.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct CommonEntriesHeader
+    {
+        public ulong TimestampTicks;
+        public ulong NumEntries;
+        public ulong LatestEntry;
+        public ulong MaxEntryIndex;
+    }
+}
+
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPad.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPad.cs
new file mode 100644
index 0000000000..e68924daf7
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPad.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    unsafe struct ShMemDebugPad
+    {
+        public CommonEntriesHeader Header;
+        public Array17<DebugPadEntry> Entries;
+        fixed byte _padding[0x138];
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPadEntry.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPadEntry.cs
new file mode 100644
index 0000000000..4a3e7a2e12
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPadEntry.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    unsafe struct DebugPadEntry
+    {
+        public ulong SampleTimestamp;
+        fixed byte _unknown[0x20];
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/HidSharedMemory.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/HidSharedMemory.cs
new file mode 100644
index 0000000000..d2bd8a2334
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/HidSharedMemory.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    // TODO: Add missing structs
+    unsafe struct HidSharedMemory
+    {
+        public ShMemDebugPad DebugPad;
+        public ShMemTouchScreen TouchScreen;
+        public ShMemMouse Mouse;
+        public ShMemKeyboard Keyboard;
+        public fixed byte BasicXpad[0x4 * 0x400];
+        public fixed byte HomeButton[0x200];
+        public fixed byte SleepButton[0x200];
+        public fixed byte CaptureButton[0x200];
+        public fixed byte InputDetector[0x10 * 0x80];
+        public fixed byte UniquePad[0x10 * 0x400];
+        public Array10<ShMemNpad> Npads;
+        public fixed byte Gesture[0x800];
+        public fixed byte ConsoleSixAxisSensor[0x20];
+        fixed byte _padding[0x3de0];
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/Keyboard.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/Keyboard.cs
new file mode 100644
index 0000000000..dcfa5aa158
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/Keyboard.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    unsafe struct ShMemKeyboard
+    {
+        public CommonEntriesHeader Header;
+        public Array17<KeyboardState> Entries;
+        fixed byte _padding[0x28];
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/KeyboardState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/KeyboardState.cs
new file mode 100644
index 0000000000..1f54a4fd57
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/KeyboardState.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    unsafe struct KeyboardState
+    {
+        public ulong SampleTimestamp;
+        public ulong SampleTimestamp2;
+        public ulong Modifier;
+        public fixed uint Keys[8];
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs
new file mode 100644
index 0000000000..c1f45c5c86
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs
@@ -0,0 +1,10 @@
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    unsafe struct ShMemMouse
+    {
+        public CommonEntriesHeader Header;
+        public Array17<MouseState> Entries;
+        fixed byte _padding[0xB0];
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MousePosition.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MousePosition.cs
new file mode 100644
index 0000000000..e94c9e0cd8
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MousePosition.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct MousePosition
+    {
+        public int X;
+        public int Y;
+        public int VelocityX;
+        public int VelocityY;
+        public int ScrollVelocityX;
+        public int ScrollVelocityY;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MouseState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MouseState.cs
new file mode 100644
index 0000000000..7856b09d2d
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MouseState.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct MouseState
+    {
+        public ulong SampleTimestamp;
+        public ulong SampleTimestamp2;
+        public MousePosition Position;
+        public ulong Buttons;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/BatterCharge.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/BatterCharge.cs
new file mode 100644
index 0000000000..b94ab172c0
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/BatterCharge.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    enum BatteryCharge : int
+    {
+        Percent0 = 0,
+        Percent25 = 1,
+        Percent50 = 2,
+        Percent75 = 3,
+        Percent100 = 4
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/DeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/DeviceType.cs
new file mode 100644
index 0000000000..f6d7b783c7
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/DeviceType.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    [Flags]
+    enum DeviceType : int
+    {
+        FullKey = 1 << 0,
+        DebugPad = 1 << 1,
+        HandheldLeft = 1 << 2,
+        HandheldRight = 1 << 3,
+        JoyLeft = 1 << 4,
+        JoyRight = 1 << 5,
+        Palma = 1 << 6, // Poké Ball Plus
+        FamicomLeft = 1 << 7,
+        FamicomRight = 1 << 8,
+        NESLeft = 1 << 9,
+        NESRight = 1 << 10,
+        HandheldFamicomLeft = 1 << 11,
+        HandheldFamicomRight = 1 << 12,
+        HandheldNESLeft = 1 << 13,
+        HandheldNESRight = 1 << 14,
+        Lucia = 1 << 15,
+        System = 1 << 31
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/HidVector.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/HidVector.cs
new file mode 100644
index 0000000000..b41bcb2e8e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/HidVector.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct HidVector
+    {
+        public float X;
+        public float Y;
+        public float Z;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs
new file mode 100644
index 0000000000..0bb2628f3e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    // TODO: Add missing structs
+    unsafe struct ShMemNpad
+    {
+        public NpadStateHeader Header;
+        public Array7<NpadLayout> Layouts; // One for each NpadLayoutsIndex
+        public Array6<NpadSixAxis> Sixaxis;
+        public DeviceType DeviceType;
+        uint _padding1;
+        public NpadSystemProperties SystemProperties;
+        public uint NpadSystemButtonProperties;
+        public Array3<BatteryCharge> BatteryState;
+        public fixed byte NfcXcdDeviceHandleHeader[0x20];
+        public fixed byte NfcXcdDeviceHandleState[0x20 * 2];
+        public ulong Mutex;
+        public fixed byte NpadGcTriggerHeader[0x20];
+        public fixed byte NpadGcTriggerState[0x18 * 17];
+        fixed byte _padding2[0xC38];
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs
similarity index 54%
rename from Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs
rename to Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs
index c31f41a3f7..ccc7cb8df8 100644
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs
@@ -1,9 +1,9 @@
 using System;
 
-namespace Ryujinx.HLE.Input
+namespace Ryujinx.HLE.HOS.Services.Hid
 {
     [Flags]
-    public enum ControllerColorDescription : int
+    enum NpadColorDescription : int
     {
         ColorDescriptionColorsNonexistent = (1 << 1)
     }
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs
new file mode 100644
index 0000000000..60f64fd37c
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    [Flags]
+    enum NpadConnectionState : long
+    {
+        ControllerStateConnected = (1 << 0),
+        ControllerStateWired = (1 << 1),
+        JoyLeftConnected = (1 << 2),
+        JoyRightConnected = (1 << 4)
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs
new file mode 100644
index 0000000000..a6f2976065
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    enum NpadJoyHoldType
+    {
+        Vertical,
+        Horizontal
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs
new file mode 100644
index 0000000000..9851a6b116
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct NpadLayout
+    {
+        public CommonEntriesHeader Header;
+        public Array17<NpadState> Entries;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayoutsIndex.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayoutsIndex.cs
new file mode 100644
index 0000000000..29eb8d3d5e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayoutsIndex.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    enum NpadLayoutsIndex : int
+    {
+        ProController = 0,
+        Handheld = 1,
+        JoyDual = 2,
+        JoyLeft = 3,
+        JoyRight = 4,
+        Pokeball = 5,
+        SystemExternal = 6
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSixAxis.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSixAxis.cs
new file mode 100644
index 0000000000..5f65db3908
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSixAxis.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct NpadSixAxis
+    {
+        public CommonEntriesHeader Header;
+        public Array17<SixAxisState> Entries;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadState.cs
new file mode 100644
index 0000000000..60a5f9d36d
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadState.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct NpadState
+    {
+        public ulong SampleTimestamp;
+        public ulong SampleTimestamp2;
+        public ControllerKeys Buttons;
+        public int LStickX;
+        public int LStickY;
+        public int RStickX;
+        public int RStickY;
+        public NpadConnectionState ConnectionState;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadStatesHeader.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadStatesHeader.cs
new file mode 100644
index 0000000000..006d4357f4
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadStatesHeader.cs
@@ -0,0 +1,16 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct NpadStateHeader
+    {
+        public ControllerType Type;
+        public Boolean32 IsHalf;
+        public NpadColorDescription SingleColorsDescriptor;
+        public NpadColor SingleColorBody;
+        public NpadColor SingleColorButtons;
+        public NpadColorDescription SplitColorsDescriptor;
+        public NpadColor LeftColorBody;
+        public NpadColor LeftColorButtons;
+        public NpadColor RightColorBody;
+        public NpadColor RightColorButtons;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSystemProperties.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSystemProperties.cs
new file mode 100644
index 0000000000..708f7da9c4
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSystemProperties.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    [Flags]
+    enum NpadSystemProperties : long
+    {
+        PowerInfo0Charging = 1 << 0,
+        PowerInfo1Charging = 1 << 1,
+        PowerInfo2Charging = 1 << 2,
+        PowerInfo0Connected = 1 << 3,
+        PowerInfo1Connected = 1 << 4,
+        PowerInfo2Connected = 1 << 5,
+        UnsupportedButtonPressedNpadSystem = 1 << 9,
+        UnsupportedButtonPressedNpadSystemExt = 1 << 10,
+        AbxyButtonOriented = 1 << 11,
+        SlSrButtonOriented = 1 << 12,
+        PlusButtonCapability = 1 << 13,
+        MinusButtonCapability = 1 << 14,
+        DirectionalButtonsSupported = 1 << 15
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisState.cs
new file mode 100644
index 0000000000..0a79991625
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisState.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    unsafe struct SixAxisState
+    {
+        public ulong SampleTimestamp;
+        ulong _unknown1;
+        public ulong SampleTimestamp2;
+        public HidVector Accelerometer;
+        public HidVector Gyroscope;
+        HidVector unknownSensor;
+        public fixed float Orientation[9];
+        ulong _unknown2;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/StructArrayHelpers.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/StructArrayHelpers.cs
new file mode 100644
index 0000000000..f513cf8b57
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/StructArrayHelpers.cs
@@ -0,0 +1,53 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct Array2<T> where T : unmanaged
+    {
+        T e0, e1;
+        public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 2)[index];
+        public int Length => 2;
+    }
+
+    struct Array3<T> where T : unmanaged
+    {
+        T e0, e1, e2;
+        public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 3)[index];
+        public int Length => 3;
+    }
+
+    struct Array6<T> where T : unmanaged
+    {
+        T e0, e1, e2, e3, e4, e5;
+        public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 6)[index];
+        public int Length => 6;
+    }
+
+    struct Array7<T> where T : unmanaged
+    {
+        T e0, e1, e2, e3, e4, e5, e6;
+        public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 7)[index];
+        public int Length => 7;
+    }
+
+    struct Array10<T> where T : unmanaged
+    {
+        T e0, e1, e2, e3, e4, e5, e6, e7, e8, e9;
+        public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 10)[index];
+        public int Length => 10;
+    }
+
+    struct Array16<T> where T : unmanaged
+    {
+        T e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15;
+        public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 16)[index];
+        public int Length => 16;
+    }
+
+    struct Array17<T> where T : unmanaged
+    {
+        T e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16;
+        public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 17)[index];
+        public int Length => 17;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreen.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreen.cs
new file mode 100644
index 0000000000..618ddd989e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreen.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    unsafe struct ShMemTouchScreen
+    {
+        public CommonEntriesHeader Header;
+        public Array17<TouchScreenState> Entries;
+        fixed byte _padding[0x3c8];
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenState.cs
new file mode 100644
index 0000000000..a0a9cf23bb
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenState.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct TouchScreenState
+    {
+        public ulong SampleTimestamp;
+        public ulong SampleTimestamp2;
+        public ulong NumTouches;
+        public Array16<TouchScreenStateData> Touches;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenStateData.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenStateData.cs
new file mode 100644
index 0000000000..872064b314
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenStateData.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+    struct TouchScreenStateData
+    {
+        public ulong SampleTimestamp;
+        uint _padding;
+        public uint TouchIndex;
+        public uint X;
+        public uint Y;
+        public uint DiameterX;
+        public uint DiameterY;
+        public uint Angle;
+        uint _padding2;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs
index d26b4eb943..3f6518e57a 100644
--- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs
@@ -43,8 +43,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             // TODO: When we will be able to add multiple controllers add one entry by controller here.
             Device device1 = new Device
             {
-                NpadIdType = HidNpadIdType.Player1,
-                Handle     = HidUtils.GetIndexFromNpadIdType(HidNpadIdType.Player1),
+                NpadIdType = NpadIdType.Player1,
+                Handle     = HidUtils.GetIndexFromNpadIdType(NpadIdType.Player1),
                 State      = DeviceState.Initialized
             };
 
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs
index 40e7c8808b..7eaf4ac866 100644
--- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs
@@ -1,6 +1,5 @@
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Hid;
-using Ryujinx.HLE.Input;
 
 namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager
 {
@@ -14,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager
 
         public DeviceState State = DeviceState.Unavailable;
 
-        public ControllerId  Handle;
-        public HidNpadIdType NpadIdType;
+        public PlayerIndex Handle;
+        public NpadIdType NpadIdType;
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Controller/BaseController.cs b/Ryujinx.HLE/Input/Controller/BaseController.cs
deleted file mode 100644
index dfd54a8324..0000000000
--- a/Ryujinx.HLE/Input/Controller/BaseController.cs
+++ /dev/null
@@ -1,142 +0,0 @@
-using static Ryujinx.HLE.Input.Hid;
-
-namespace Ryujinx.HLE.Input
-{
-    public abstract class BaseController : IHidDevice
-    {
-        protected ControllerStatus HidControllerType;
-        protected ControllerId     ControllerId;
-
-        private long _currentLayoutOffset;
-        private long _mainLayoutOffset;
-
-        protected long DeviceStateOffset => Offset + 0x4188;
-
-        protected Switch Device { get; }
-
-        public long Offset    { get; private set; }
-        public bool Connected { get; protected set; }
-
-        public ControllerHeader            Header             { get; private set; }
-        public ControllerStateHeader       CurrentStateHeader { get; private set; }
-        public ControllerDeviceState       DeviceState        { get; private set; }
-        public ControllerLayouts           CurrentLayout      { get; private set; }
-        public ControllerState             LastInputState     { get; set; }
-        public ControllerConnectionState   ConnectionState    { get; protected set; }
-
-        public BaseController(Switch device, ControllerStatus controllerType)
-        {
-            Device            = device;
-            HidControllerType = controllerType;
-        }
-
-        protected void Initialize(
-            bool isHalf,
-            (NpadColor left, NpadColor right) bodyColors,
-            (NpadColor left, NpadColor right) buttonColors,
-            ControllerColorDescription        singleColorDesc   = 0,
-            ControllerColorDescription        splitColorDesc    = 0,
-            NpadColor                         singleBodyColor   = 0,
-            NpadColor                         singleButtonColor = 0
-            )
-        {
-            Header = new ControllerHeader()
-            {
-                IsJoyConHalf           = isHalf ? 1 : 0,
-                LeftBodyColor          = bodyColors.left,
-                LeftButtonColor        = buttonColors.left,
-                RightBodyColor         = bodyColors.right,
-                RightButtonColor       = buttonColors.right,
-                Status                 = HidControllerType,
-                SingleBodyColor        = singleBodyColor,
-                SingleButtonColor      = singleButtonColor,
-                SplitColorDescription  = splitColorDesc,
-                SingleColorDescription = singleColorDesc,
-            };
-
-            CurrentStateHeader = new ControllerStateHeader
-            {
-                EntryCount        = HidEntryCount,
-                MaxEntryCount     = HidEntryCount - 1,
-                CurrentEntryIndex = -1
-            };
-
-            DeviceState = new ControllerDeviceState()
-            {
-                PowerInfo0BatteryState = BatteryState.Percent100,
-                PowerInfo1BatteryState = BatteryState.Percent100,
-                PowerInfo2BatteryState = BatteryState.Percent100,
-                DeviceType             = ControllerDeviceType.NPadLeftController | ControllerDeviceType.NPadRightController,
-                DeviceFlags            = DeviceFlags.PowerInfo0Connected
-                                            | DeviceFlags.PowerInfo1Connected
-                                            | DeviceFlags.PowerInfo2Connected
-            };
-
-            LastInputState = new ControllerState()
-            {
-                SamplesTimestamp  = -1,
-                SamplesTimestamp2 = -1
-            };
-        }
-
-        public virtual void Connect(ControllerId controllerId)
-        {
-            ControllerId = controllerId;
-
-            Offset = Device.Hid.HidPosition + HidControllersOffset + (int)controllerId * HidControllerSize;
-
-            _mainLayoutOffset = Offset + HidControllerHeaderSize
-                + ((int)ControllerLayouts.Main * HidControllerLayoutsSize);
-
-            Device.Memory.FillWithZeros(Offset, 0x5000);
-            Device.Memory.WriteStruct(Offset, Header);
-            Device.Memory.WriteStruct(DeviceStateOffset, DeviceState);
-
-            Connected = true;
-        }
-
-        public void SetLayout(ControllerLayouts controllerLayout)
-        {
-            CurrentLayout = controllerLayout;
-
-            _currentLayoutOffset = Offset + HidControllerHeaderSize
-                + ((int)controllerLayout * HidControllerLayoutsSize);
-        }
-
-        public void SendInput(
-            ControllerButtons buttons,
-            JoystickPosition  leftStick,
-            JoystickPosition  rightStick)
-        {
-            ControllerState currentInput = new ControllerState()
-            {
-                SamplesTimestamp  = (long)LastInputState.SamplesTimestamp + 1,
-                SamplesTimestamp2 = (long)LastInputState.SamplesTimestamp + 1,
-                ButtonState       = buttons,
-                ConnectionState   = ConnectionState,
-                LeftStick         = leftStick,
-                RightStick        = rightStick
-            };
-
-            ControllerStateHeader newInputStateHeader = new ControllerStateHeader
-            {
-                EntryCount        = HidEntryCount,
-                MaxEntryCount     = HidEntryCount - 1,
-                CurrentEntryIndex = (CurrentStateHeader.CurrentEntryIndex + 1) % HidEntryCount,
-                Timestamp         = GetTimestamp(),
-            };
-
-            Device.Memory.WriteStruct(_currentLayoutOffset, newInputStateHeader);
-            Device.Memory.WriteStruct(_mainLayoutOffset,    newInputStateHeader);
-
-            long currentInputStateOffset = HidControllersLayoutHeaderSize
-                + newInputStateHeader.CurrentEntryIndex * HidControllersInputEntrySize;
-
-            Device.Memory.WriteStruct(_currentLayoutOffset + currentInputStateOffset, currentInput);
-            Device.Memory.WriteStruct(_mainLayoutOffset + currentInputStateOffset,    currentInput);
-
-            LastInputState     = currentInput;
-            CurrentStateHeader = newInputStateHeader;
-        }
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/NpadController.cs b/Ryujinx.HLE/Input/Controller/NpadController.cs
deleted file mode 100644
index b4304b8f3f..0000000000
--- a/Ryujinx.HLE/Input/Controller/NpadController.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public class NpadController : BaseController
-    {
-        private (NpadColor Left, NpadColor Right) _npadBodyColors;
-        private (NpadColor Left, NpadColor Right) _npadButtonColors;
-
-        private bool _isHalf;
-
-        public NpadController(
-            ControllerStatus       controllerStatus,
-            Switch                 device,
-            (NpadColor, NpadColor) npadBodyColors,
-            (NpadColor, NpadColor) npadButtonColors) : base(device, controllerStatus)
-        {
-            _npadBodyColors   = npadBodyColors;
-            _npadButtonColors = npadButtonColors;
-        }
-
-        public override void Connect(ControllerId controllerId)
-        {
-            if (HidControllerType != ControllerStatus.NpadLeft && HidControllerType != ControllerStatus.NpadRight)
-            {
-                _isHalf = false;
-            }
-
-            ConnectionState = ControllerConnectionState.ControllerStateConnected;
-
-            if (controllerId == ControllerId.ControllerHandheld)
-                ConnectionState |= ControllerConnectionState.ControllerStateWired;
-
-            ControllerColorDescription singleColorDesc =
-                ControllerColorDescription.ColorDescriptionColorsNonexistent;
-
-            ControllerColorDescription splitColorDesc = 0;
-
-            NpadColor singleBodyColor   = NpadColor.Black;
-            NpadColor singleButtonColor = NpadColor.Black;
-
-            Initialize(_isHalf,
-                (_npadBodyColors.Left,   _npadBodyColors.Right),
-                (_npadButtonColors.Left, _npadButtonColors.Right),
-                singleColorDesc,
-                splitColorDesc,
-                singleBodyColor,
-                singleButtonColor );
-
-            base.Connect(controllerId);
-
-            var _currentLayout = ControllerLayouts.HandheldJoined;
-
-            switch (HidControllerType)
-            {
-                case ControllerStatus.NpadLeft:
-                    _currentLayout = ControllerLayouts.Left;
-                    break;
-                case ControllerStatus.NpadRight:
-                    _currentLayout = ControllerLayouts.Right;
-                    break;
-                case ControllerStatus.NpadPair:
-                    _currentLayout = ControllerLayouts.Joined;
-                    break;
-            }
-
-            SetLayout(_currentLayout);
-        }
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/ProController.cs b/Ryujinx.HLE/Input/Controller/ProController.cs
deleted file mode 100644
index ae574260fd..0000000000
--- a/Ryujinx.HLE/Input/Controller/ProController.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public class ProController : BaseController
-    {
-        private bool _wired = false;
-
-        private NpadColor _bodyColor;
-        private NpadColor _buttonColor;
-
-        public ProController(Switch    device,
-                             NpadColor bodyColor,
-                             NpadColor buttonColor) : base(device, ControllerStatus.ProController)
-        {
-            _wired = true;
-
-            _bodyColor   = bodyColor;
-            _buttonColor = buttonColor;
-        }
-
-        public override void Connect(ControllerId controllerId)
-        {
-            ControllerColorDescription singleColorDesc =
-                ControllerColorDescription.ColorDescriptionColorsNonexistent;
-
-            ControllerColorDescription splitColorDesc = 0;
-
-            ConnectionState = ControllerConnectionState.ControllerStateConnected | ControllerConnectionState.ControllerStateWired;
-
-            Initialize(false,
-                (0, 0),
-                (0, 0),
-                singleColorDesc,
-                splitColorDesc,
-                _bodyColor,
-                _buttonColor);
-
-            base.Connect(controllerId);
-
-            SetLayout(ControllerLayouts.ProController);
-        }
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/Types/BatteryState.cs b/Ryujinx.HLE/Input/Controller/Types/BatteryState.cs
deleted file mode 100644
index 4279d7a03e..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/BatteryState.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public enum BatteryState : int
-    {
-        // TODO : Check if these are the correct states
-        Percent0   = 0,
-        Percent25  = 1,
-        Percent50  = 2,
-        Percent75  = 3,
-        Percent100 = 4
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs
deleted file mode 100644
index 879257f265..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.Input
-{
-    [Flags]
-    public enum ControllerButtons : long
-    {
-        A           = 1 << 0,
-        B           = 1 << 1,
-        X           = 1 << 2,
-        Y           = 1 << 3,
-        StickLeft   = 1 << 4,
-        StickRight  = 1 << 5,
-        L           = 1 << 6,
-        R           = 1 << 7,
-        Zl          = 1 << 8,
-        Zr          = 1 << 9,
-        Plus        = 1 << 10,
-        Minus       = 1 << 11,
-        DpadLeft    = 1 << 12,
-        DpadUp      = 1 << 13,
-        DPadRight   = 1 << 14,
-        DpadDown    = 1 << 15,
-        LStickLeft  = 1 << 16,
-        LStickUp    = 1 << 17,
-        LStickRight = 1 << 18,
-        LStickDown  = 1 << 19,
-        RStickLeft  = 1 << 20,
-        RStickUp    = 1 << 21,
-        RStickRight = 1 << 22,
-        RStickDown  = 1 << 23,
-        Sl          = 1 << 24,
-        Sr          = 1 << 25
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs
deleted file mode 100644
index 526da1ff19..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.Input
-{
-    [Flags]
-    public enum ControllerConnectionState : long
-    {
-        ControllerStateConnected = (1 << 0),
-        ControllerStateWired     = (1 << 1)
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs
deleted file mode 100644
index 45895a1e99..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.Input
-{
-    [StructLayout(LayoutKind.Sequential)]
-    public unsafe struct ControllerDeviceState
-    {
-        public ControllerDeviceType DeviceType;
-        public int                  Padding;
-        public DeviceFlags          DeviceFlags;
-        public int                  UnintendedHomeButtonInputProtectionEnabled;
-        public BatteryState         PowerInfo0BatteryState;
-        public BatteryState         PowerInfo1BatteryState;
-        public BatteryState         PowerInfo2BatteryState;
-        public fixed byte           ControllerMac[16];
-        public fixed byte           ControllerMac2[16];
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceType.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceType.cs
deleted file mode 100644
index 8043d8a0ff..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceType.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.Input
-{
-    [Flags]
-    public enum ControllerDeviceType : int
-    {
-        ProController       = 1 << 0,
-        NPadLeftController  = 1 << 4,
-        NPadRightController = 1 << 5,
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerHeader.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerHeader.cs
deleted file mode 100644
index cbb5b6f560..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerHeader.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.Input
-{
-    [StructLayout(LayoutKind.Sequential)]
-    public struct ControllerHeader
-    {
-        public ControllerStatus           Status;
-        public int                        IsJoyConHalf;
-        public ControllerColorDescription SingleColorDescription;
-        public NpadColor                  SingleBodyColor;
-        public NpadColor                  SingleButtonColor;
-        public ControllerColorDescription SplitColorDescription;
-        public NpadColor                  RightBodyColor;
-        public NpadColor                  RightButtonColor;
-        public NpadColor                  LeftBodyColor;
-        public NpadColor                  LeftButtonColor;
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerId.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerId.cs
deleted file mode 100644
index c82056c68b..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerId.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public enum ControllerId
-    {
-        ControllerPlayer1  = 0,
-        ControllerPlayer2  = 1,
-        ControllerPlayer3  = 2,
-        ControllerPlayer4  = 3,
-        ControllerPlayer5  = 4,
-        ControllerPlayer6  = 5,
-        ControllerPlayer7  = 6,
-        ControllerPlayer8  = 7,
-        ControllerHandheld = 8,
-        ControllerUnknown  = 9
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs
deleted file mode 100644
index fedc0399a9..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public enum ControllerLayouts
-    {
-        ProController  = 0,
-        HandheldJoined = 1,
-        Joined         = 2,
-        Left           = 3,
-        Right          = 4,
-        MainNoAnalog   = 5,
-        Main           = 6
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs
deleted file mode 100644
index 4847438ddf..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.Input
-{
-    [StructLayout(LayoutKind.Sequential)]
-    public struct ControllerState
-    {
-        public long                      SamplesTimestamp;
-        public long                      SamplesTimestamp2;
-        public ControllerButtons         ButtonState;
-        public JoystickPosition          LeftStick;
-        public JoystickPosition          RightStick;
-        public ControllerConnectionState ConnectionState;
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerStateHeader.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerStateHeader.cs
deleted file mode 100644
index f885c00c75..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerStateHeader.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.Input
-{
-    [StructLayout(LayoutKind.Sequential)]
-    public struct ControllerStateHeader
-    {
-        public long Timestamp;
-        public long EntryCount;
-        public long CurrentEntryIndex;
-        public long MaxEntryCount;
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs
deleted file mode 100644
index 9444d7b0e5..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.Input
-{
-    [Flags]
-    public enum ControllerStatus : int
-    {
-        ProController = 1 << 0,
-        Handheld      = 1 << 1,
-        NpadPair      = 1 << 2,
-        NpadLeft      = 1 << 3,
-        NpadRight     = 1 << 4
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs b/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs
deleted file mode 100644
index 5391317570..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.Input
-{
-    [Flags]
-    public enum DeviceFlags : long
-    {
-        PowerInfo0Charging                    = 1 << 0,
-        PowerInfo1Charging                    = 1 << 1,
-        PowerInfo2Charging                    = 1 << 2,
-        PowerInfo0Connected                   = 1 << 3,
-        PowerInfo1Connected                   = 1 << 4,
-        PowerInfo2Connected                   = 1 << 5,
-        UnsupportedButtonPressedNpadSystem    = 1 << 9,
-        UnsupportedButtonPressedNpadSystemExt = 1 << 10,
-        AbxyButtonOriented                    = 1 << 11,
-        SlSrButtonOriented                    = 1 << 12,
-        PlusButtonCapability                  = 1 << 13,
-        MinusButtonCapability                 = 1 << 14,
-        DirectionalButtonsSupported           = 1 << 15
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs b/Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs
deleted file mode 100644
index be76ee1e34..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.Input
-{
-    [Flags]
-    public enum HotkeyButtons
-    {
-        ToggleVSync = 1 << 0,
-    }
-}
diff --git a/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs b/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs
deleted file mode 100644
index a60f94aae9..0000000000
--- a/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public enum NpadColor : int //Thanks to CTCaer
-    {
-        Black = 0,
-
-        BodyGrey          = 0x828282,
-        BodyNeonBlue      = 0x0AB9E6,
-        BodyNeonRed       = 0xFF3C28,
-        BodyNeonYellow    = 0xE6FF00,
-        BodyNeonPink      = 0xFF3278,
-        BodyNeonGreen     = 0x1EDC00,
-        BodyRed           = 0xE10F00,
-
-        ButtonsGrey       = 0x0F0F0F,
-        ButtonsNeonBlue   = 0x001E1E,
-        ButtonsNeonRed    = 0x1E0A0A,
-        ButtonsNeonYellow = 0x142800,
-        ButtonsNeonPink   = 0x28001E,
-        ButtonsNeonGreen  = 0x002800,
-        ButtonsRed        = 0x280A0A
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Hid.cs b/Ryujinx.HLE/Input/Hid.cs
deleted file mode 100644
index 5cb7f09de6..0000000000
--- a/Ryujinx.HLE/Input/Hid.cs
+++ /dev/null
@@ -1,218 +0,0 @@
-using Ryujinx.Common;
-using Ryujinx.Configuration.Hid;
-using Ryujinx.HLE.HOS;
-using System;
-
-namespace Ryujinx.HLE.Input
-{
-    public partial class Hid
-    {
-        private Switch _device;
-
-        private long _touchScreenOffset;
-        private long _touchEntriesOffset;
-        private long _keyboardOffset;
-
-        private TouchHeader    _currentTouchHeader;
-        private KeyboardHeader _currentKeyboardHeader;
-        private KeyboardEntry  _currentKeyboardEntry;
-
-        public BaseController PrimaryController { get; private set; }
-
-        internal long HidPosition;
-
-        public Hid(Switch device, long hidPosition)
-        {
-            _device     = device;
-            HidPosition = hidPosition;
-
-            device.Memory.FillWithZeros(hidPosition, Horizon.HidSize);
-
-            _currentTouchHeader = new TouchHeader()
-            {
-                CurrentEntryIndex = -1,
-            };
-
-            _currentKeyboardHeader = new KeyboardHeader()
-            {
-                CurrentEntryIndex = -1,
-            };
-
-            _currentKeyboardEntry = new KeyboardEntry()
-            {
-                SamplesTimestamp  = -1,
-                SamplesTimestamp2 = -1
-            };
-
-            _touchScreenOffset  = HidPosition + HidTouchScreenOffset;
-            _touchEntriesOffset = _touchScreenOffset + HidTouchHeaderSize;
-            _keyboardOffset     = HidPosition + HidKeyboardOffset;
-        }
-
-        private static ControllerStatus ConvertControllerTypeToState(ControllerType controllerType)
-        {
-            switch (controllerType)
-            {
-                case ControllerType.Handheld:      return ControllerStatus.Handheld;
-                case ControllerType.NpadLeft:      return ControllerStatus.NpadLeft;
-                case ControllerType.NpadRight:     return ControllerStatus.NpadRight;
-                case ControllerType.NpadPair:      return ControllerStatus.NpadPair;
-                case ControllerType.ProController: return ControllerStatus.ProController;
-                default:                           throw new NotImplementedException();
-            }
-        }
-
-        public void InitializePrimaryController(ControllerType controllerType)
-        {
-            ControllerId controllerId = controllerType == ControllerType.Handheld ?
-                ControllerId.ControllerHandheld : ControllerId.ControllerPlayer1;
-
-            if (controllerType == ControllerType.ProController)
-            {
-                PrimaryController = new ProController(_device, NpadColor.Black, NpadColor.Black);
-            }
-            else
-            {
-                PrimaryController = new NpadController(ConvertControllerTypeToState(controllerType),
-                     _device,
-                     (NpadColor.BodyNeonRed,     NpadColor.BodyNeonRed),
-                     (NpadColor.ButtonsNeonBlue, NpadColor.ButtonsNeonBlue));
-            }
-
-            PrimaryController.Connect(controllerId);
-        }
-
-        public ControllerButtons UpdateStickButtons(
-            JoystickPosition leftStick,
-            JoystickPosition rightStick)
-        {
-            ControllerButtons result = 0;
-
-            if (rightStick.Dx < 0)
-            {
-                result |= ControllerButtons.RStickLeft;
-            }
-
-            if (rightStick.Dx > 0)
-            {
-                result |= ControllerButtons.RStickRight;
-            }
-
-            if (rightStick.Dy < 0)
-            {
-                result |= ControllerButtons.RStickDown;
-            }
-
-            if (rightStick.Dy > 0)
-            {
-                result |= ControllerButtons.RStickUp;
-            }
-
-            if (leftStick.Dx < 0)
-            {
-                result |= ControllerButtons.LStickLeft;
-            }
-
-            if (leftStick.Dx > 0)
-            {
-                result |= ControllerButtons.LStickRight;
-            }
-
-            if (leftStick.Dy < 0)
-            {
-                result |= ControllerButtons.LStickDown;
-            }
-
-            if (leftStick.Dy > 0)
-            {
-                result |= ControllerButtons.LStickUp;
-            }
-
-            return result;
-        }
-        public void SetTouchPoints(params TouchPoint[] points)
-        {
-            long timestamp     = GetTimestamp();
-            long sampleCounter = _currentTouchHeader.SamplesTimestamp + 1;
-
-            var newTouchHeader = new TouchHeader
-            {
-                CurrentEntryIndex = (_currentTouchHeader.CurrentEntryIndex + 1) % HidEntryCount,
-                EntryCount        = HidEntryCount,
-                MaxEntries        = HidEntryCount - 1,
-                SamplesTimestamp  = sampleCounter,
-                Timestamp         = timestamp,
-            };
-
-            long currentTouchEntryOffset = _touchEntriesOffset + newTouchHeader.CurrentEntryIndex * HidTouchEntrySize;
-
-            TouchEntry touchEntry = new TouchEntry()
-            {
-                SamplesTimestamp = sampleCounter,
-                TouchCount       = points.Length
-            };
-
-            _device.Memory.WriteStruct(currentTouchEntryOffset, touchEntry);
-
-            currentTouchEntryOffset += HidTouchEntryHeaderSize;
-
-            for (int i = 0; i < points.Length; i++)
-            {
-                TouchData touch = new TouchData()
-                {
-                    Angle           = points[i].Angle,
-                    DiameterX       = points[i].DiameterX,
-                    DiameterY       = points[i].DiameterY,
-                    Index           = i,
-                    SampleTimestamp = sampleCounter,
-                    X               = points[i].X,
-                    Y               = points[i].Y
-                };
-
-                _device.Memory.WriteStruct(currentTouchEntryOffset, touch);
-
-                currentTouchEntryOffset += HidTouchEntryTouchSize;
-            }
-
-            _device.Memory.WriteStruct(_touchScreenOffset, newTouchHeader);
-
-            _currentTouchHeader = newTouchHeader;
-        }
-
-        public unsafe void WriteKeyboard(Keyboard keyboard)
-        {
-            long timestamp = GetTimestamp();
-
-            var newKeyboardHeader = new KeyboardHeader()
-            {
-                CurrentEntryIndex = (_currentKeyboardHeader.CurrentEntryIndex + 1) % HidEntryCount,
-                EntryCount        = HidEntryCount,
-                MaxEntries        = HidEntryCount - 1,
-                Timestamp         = timestamp,
-            };
-
-            _device.Memory.WriteStruct(_keyboardOffset, newKeyboardHeader);
-
-            long keyboardEntryOffset = _keyboardOffset + HidKeyboardHeaderSize;
-            keyboardEntryOffset += newKeyboardHeader.CurrentEntryIndex * HidKeyboardEntrySize;
-
-            var newkeyboardEntry = new KeyboardEntry()
-            {
-                SamplesTimestamp  = _currentKeyboardEntry.SamplesTimestamp + 1,
-                SamplesTimestamp2 = _currentKeyboardEntry.SamplesTimestamp2 + 1,
-                Keys              = keyboard.Keys,
-                Modifier          = keyboard.Modifier,
-            };
-
-            _device.Memory.WriteStruct(keyboardEntryOffset, newkeyboardEntry);
-
-            _currentKeyboardEntry  = newkeyboardEntry;
-            _currentKeyboardHeader = newKeyboardHeader;
-        }
-
-        internal static long GetTimestamp()
-        {
-            return PerformanceCounter.ElapsedMilliseconds * 19200;
-        }
-    }
-}
diff --git a/Ryujinx.HLE/Input/HidValues.cs b/Ryujinx.HLE/Input/HidValues.cs
deleted file mode 100644
index 06fe8fc0d4..0000000000
--- a/Ryujinx.HLE/Input/HidValues.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public partial class Hid
-    {
-        /*
-         * Reference:
-         * https://github.com/reswitched/libtransistor/blob/development/lib/hid.c
-         * https://github.com/reswitched/libtransistor/blob/development/include/libtransistor/hid.h
-         * https://github.com/switchbrew/libnx/blob/master/nx/source/services/hid.c
-         * https://github.com/switchbrew/libnx/blob/master/nx/include/switch/services/hid.h
-         */
-
-        internal const int HidHeaderSize            = 0x400;
-        internal const int HidTouchScreenSize       = 0x3000;
-        internal const int HidMouseSize             = 0x400;
-        internal const int HidKeyboardSize          = 0x400;
-        internal const int HidUnkSection1Size       = 0x400;
-        internal const int HidUnkSection2Size       = 0x400;
-        internal const int HidUnkSection3Size       = 0x400;
-        internal const int HidUnkSection4Size       = 0x400;
-        internal const int HidUnkSection5Size       = 0x200;
-        internal const int HidUnkSection6Size       = 0x200;
-        internal const int HidUnkSection7Size       = 0x200;
-        internal const int HidUnkSection8Size       = 0x800;
-        internal const int HidControllerSerialsSize = 0x4000;
-        internal const int HidControllersSize       = 0x32000;
-        internal const int HidUnkSection9Size       = 0x800;
-
-        internal const int HidKeyboardHeaderSize = 0x20;
-        internal const int HidKeyboardEntrySize  = 0x38;
-
-        internal const int HidTouchHeaderSize = 0x28;
-        internal const int HidTouchEntrySize  = 0x298;
-
-        internal const int HidTouchEntryHeaderSize = 0x10;
-        internal const int HidTouchEntryTouchSize  = 0x28;
-
-        internal const int HidControllerSize        = 0x5000;
-        internal const int HidControllerHeaderSize  = 0x28;
-        internal const int HidControllerLayoutsSize = 0x350;
-
-        internal const int HidControllersLayoutHeaderSize = 0x20;
-        internal const int HidControllersInputEntrySize   = 0x30;
-
-        internal const int HidHeaderOffset            = 0;
-        internal const int HidTouchScreenOffset       = HidHeaderOffset            + HidHeaderSize;
-        internal const int HidMouseOffset             = HidTouchScreenOffset       + HidTouchScreenSize;
-        internal const int HidKeyboardOffset          = HidMouseOffset             + HidMouseSize;
-        internal const int HidUnkSection1Offset       = HidKeyboardOffset          + HidKeyboardSize;
-        internal const int HidUnkSection2Offset       = HidUnkSection1Offset       + HidUnkSection1Size;
-        internal const int HidUnkSection3Offset       = HidUnkSection2Offset       + HidUnkSection2Size;
-        internal const int HidUnkSection4Offset       = HidUnkSection3Offset       + HidUnkSection3Size;
-        internal const int HidUnkSection5Offset       = HidUnkSection4Offset       + HidUnkSection4Size;
-        internal const int HidUnkSection6Offset       = HidUnkSection5Offset       + HidUnkSection5Size;
-        internal const int HidUnkSection7Offset       = HidUnkSection6Offset       + HidUnkSection6Size;
-        internal const int HidUnkSection8Offset       = HidUnkSection7Offset       + HidUnkSection7Size;
-        internal const int HidControllerSerialsOffset = HidUnkSection8Offset       + HidUnkSection8Size;
-        internal const int HidControllersOffset       = HidControllerSerialsOffset + HidControllerSerialsSize;
-        internal const int HidUnkSection9Offset       = HidControllersOffset       + HidControllersSize;
-
-        internal const int HidEntryCount = 17;
-    }
-}
diff --git a/Ryujinx.HLE/Input/IHidDevice.cs b/Ryujinx.HLE/Input/IHidDevice.cs
deleted file mode 100644
index 0b07e767fc..0000000000
--- a/Ryujinx.HLE/Input/IHidDevice.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    interface IHidDevice
-    {
-        long Offset    { get; }
-        bool Connected { get; }
-    }
-}
diff --git a/Ryujinx.HLE/Input/Keyboard/Keyboard.cs b/Ryujinx.HLE/Input/Keyboard/Keyboard.cs
deleted file mode 100644
index 7220e51871..0000000000
--- a/Ryujinx.HLE/Input/Keyboard/Keyboard.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public struct Keyboard
-    {
-        public int   Modifier;
-        public int[] Keys;
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs b/Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs
deleted file mode 100644
index be7d9399d1..0000000000
--- a/Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.Input
-{
-    [StructLayout(LayoutKind.Sequential)]
-    public struct KeyboardEntry
-    {
-        public long SamplesTimestamp;
-        public long SamplesTimestamp2;
-        public long Modifier;
-
-        [MarshalAs(UnmanagedType.ByValArray , SizeConst = 0x8)]
-        public int[] Keys;
-    }
-}
diff --git a/Ryujinx.HLE/Input/Keyboard/KeyboardHeader.cs b/Ryujinx.HLE/Input/Keyboard/KeyboardHeader.cs
deleted file mode 100644
index 882ccbabe3..0000000000
--- a/Ryujinx.HLE/Input/Keyboard/KeyboardHeader.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.Input
-{
-    [StructLayout(LayoutKind.Sequential)]
-    public struct KeyboardHeader
-    {
-        public long Timestamp;
-        public long EntryCount;
-        public long CurrentEntryIndex;
-        public long MaxEntries;
-    }
-}
diff --git a/Ryujinx.HLE/Input/Touch/TouchData.cs b/Ryujinx.HLE/Input/Touch/TouchData.cs
deleted file mode 100644
index 8489ef7095..0000000000
--- a/Ryujinx.HLE/Input/Touch/TouchData.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.Input
-{
-    [StructLayout(LayoutKind.Sequential)]
-    public struct TouchData
-    {
-        public long SampleTimestamp;
-        public int  Padding;
-        public int  Index;
-        public int  X;
-        public int  Y;
-        public int  DiameterX;
-        public int  DiameterY;
-        public int  Angle;
-        public int  Padding2;
-    }
-}
diff --git a/Ryujinx.HLE/Input/Touch/TouchEntry.cs b/Ryujinx.HLE/Input/Touch/TouchEntry.cs
deleted file mode 100644
index 2ef09d7523..0000000000
--- a/Ryujinx.HLE/Input/Touch/TouchEntry.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.Input
-{
-    [StructLayout(LayoutKind.Sequential)]
-    public unsafe struct TouchEntry
-    {
-        public long SamplesTimestamp;
-        public long TouchCount;
-    }
-}
diff --git a/Ryujinx.HLE/Input/Touch/TouchHeader.cs b/Ryujinx.HLE/Input/Touch/TouchHeader.cs
deleted file mode 100644
index dd93137c2b..0000000000
--- a/Ryujinx.HLE/Input/Touch/TouchHeader.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.Input
-{
-    [StructLayout(LayoutKind.Sequential)]
-    public struct TouchHeader
-    {
-        public long Timestamp;
-        public long EntryCount;
-        public long CurrentEntryIndex;
-        public long MaxEntries;
-        public long SamplesTimestamp;
-    }
-}
diff --git a/Ryujinx.HLE/Input/Touch/TouchPoint.cs b/Ryujinx.HLE/Input/Touch/TouchPoint.cs
deleted file mode 100644
index a9b095de2c..0000000000
--- a/Ryujinx.HLE/Input/Touch/TouchPoint.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public struct TouchPoint
-    {
-        public int X;
-        public int Y;
-        public int DiameterX;
-        public int DiameterY;
-        public int Angle;
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs
index 3cd290bd72..040fbf1cf8 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -7,8 +7,8 @@ using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.FileSystem.Content;
 using Ryujinx.HLE.HOS;
 using Ryujinx.HLE.HOS.Services;
+using Ryujinx.HLE.HOS.Services.Hid;
 using Ryujinx.HLE.HOS.SystemState;
-using Ryujinx.HLE.Input;
 using System;
 using System.Threading;
 
@@ -61,6 +61,7 @@ namespace Ryujinx.HLE
             Statistics = new PerformanceStatistics();
 
             Hid = new Hid(this, System.HidBaseAddress);
+            Hid.InitDevices();
 
             VsyncEvent = new AutoResetEvent(true);
         }
diff --git a/Ryujinx/Ui/GLRenderer.cs b/Ryujinx/Ui/GLRenderer.cs
index 1105004a86..f69d88ce01 100644
--- a/Ryujinx/Ui/GLRenderer.cs
+++ b/Ryujinx/Ui/GLRenderer.cs
@@ -7,7 +7,7 @@ using OpenTK.Platform;
 using Ryujinx.Configuration;
 using Ryujinx.Graphics.OpenGL;
 using Ryujinx.HLE;
-using Ryujinx.HLE.Input;
+using Ryujinx.HLE.HOS.Services.Hid;
 using Ryujinx.Ui;
 using System;
 using System.Collections.Generic;
@@ -382,10 +382,10 @@ namespace Ryujinx.Ui
             }
 
             HotkeyButtons currentHotkeyButtons = 0;
-            ControllerButtons currentButton = 0;
+            ControllerKeys currentButton = 0;
             JoystickPosition leftJoystick;
             JoystickPosition rightJoystick;
-            HLE.Input.Keyboard? hidKeyboard = null;
+            KeyboardInput? hidKeyboard = null;
 
             int leftJoystickDx = 0;
             int leftJoystickDy = 0;
@@ -417,7 +417,7 @@ namespace Ryujinx.Ui
 
             if (!hidKeyboard.HasValue)
             {
-                hidKeyboard = new HLE.Input.Keyboard
+                hidKeyboard = new KeyboardInput
                 {
                     Modifier = 0,
                     Keys = new int[0x8]
@@ -489,8 +489,8 @@ namespace Ryujinx.Ui
 
                     TouchPoint currentPoint = new TouchPoint
                     {
-                        X = mX,
-                        Y = mY,
+                        X = (uint)mX,
+                        Y = (uint)mY,
 
                         // Placeholder values till more data is acquired
                         DiameterX = 10,
@@ -500,23 +500,29 @@ namespace Ryujinx.Ui
 
                     hasTouch = true;
 
-                    _device.Hid.SetTouchPoints(currentPoint);
+                    _device.Hid.Touchscreen.Update(currentPoint);
                 }
             }
 
             if (!hasTouch)
             {
-                _device.Hid.SetTouchPoints();
+                _device.Hid.Touchscreen.Update();
             }
 
             if (ConfigurationState.Instance.Hid.EnableKeyboard && hidKeyboard.HasValue)
             {
-                _device.Hid.WriteKeyboard(hidKeyboard.Value);
+                _device.Hid.Keyboard.Update(hidKeyboard.Value);
             }
 
-            BaseController controller = _device.Hid.PrimaryController;
+            _device.Hid.DebugPad.Update();
 
-            controller.SendInput(currentButton, leftJoystick, rightJoystick);
+            _device.Hid.Npads.SetGamepadsInput(new GamepadInput
+            {
+                PlayerId = PlayerIndex.Auto,
+                Buttons = currentButton,
+                LStick = leftJoystick,
+                RStick = rightJoystick
+            });
 
             // Toggle vsync
             if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) &&
diff --git a/Ryujinx/Ui/KeyboardControls.cs b/Ryujinx/Ui/KeyboardControls.cs
index db9c0cda8c..1f19fe32e6 100644
--- a/Ryujinx/Ui/KeyboardControls.cs
+++ b/Ryujinx/Ui/KeyboardControls.cs
@@ -1,32 +1,39 @@
-using OpenTK.Input;
-using Ryujinx.HLE.Input;
+using System;
+using OpenTK.Input;
+using Ryujinx.HLE.HOS.Services.Hid;
 using Ryujinx.UI.Input;
 
 namespace Ryujinx.Ui
 {
+    [Flags]
+    public enum HotkeyButtons
+    {
+        ToggleVSync = 1 << 0,
+    }
+
     public static class KeyboardControls
     {
-        public static ControllerButtons GetButtons(NpadKeyboard npad, KeyboardState keyboard)
+        public static ControllerKeys GetButtons(NpadKeyboard npad, KeyboardState keyboard)
         {
-            ControllerButtons buttons = 0;
+            ControllerKeys buttons = 0;
 
-            if (keyboard[(Key)npad.LeftJoycon.StickButton]) buttons |= ControllerButtons.StickLeft;
-            if (keyboard[(Key)npad.LeftJoycon.DPadUp])      buttons |= ControllerButtons.DpadUp;
-            if (keyboard[(Key)npad.LeftJoycon.DPadDown])    buttons |= ControllerButtons.DpadDown;
-            if (keyboard[(Key)npad.LeftJoycon.DPadLeft])    buttons |= ControllerButtons.DpadLeft;
-            if (keyboard[(Key)npad.LeftJoycon.DPadRight])   buttons |= ControllerButtons.DPadRight;
-            if (keyboard[(Key)npad.LeftJoycon.ButtonMinus]) buttons |= ControllerButtons.Minus;
-            if (keyboard[(Key)npad.LeftJoycon.ButtonL])     buttons |= ControllerButtons.L;
-            if (keyboard[(Key)npad.LeftJoycon.ButtonZl])    buttons |= ControllerButtons.Zl;
+            if (keyboard[(Key)npad.LeftJoycon.StickButton]) buttons |= ControllerKeys.LStick;
+            if (keyboard[(Key)npad.LeftJoycon.DPadUp])      buttons |= ControllerKeys.DpadUp;
+            if (keyboard[(Key)npad.LeftJoycon.DPadDown])    buttons |= ControllerKeys.DpadDown;
+            if (keyboard[(Key)npad.LeftJoycon.DPadLeft])    buttons |= ControllerKeys.DpadLeft;
+            if (keyboard[(Key)npad.LeftJoycon.DPadRight])   buttons |= ControllerKeys.DpadRight;
+            if (keyboard[(Key)npad.LeftJoycon.ButtonMinus]) buttons |= ControllerKeys.Minus;
+            if (keyboard[(Key)npad.LeftJoycon.ButtonL])     buttons |= ControllerKeys.L | ControllerKeys.Sl;
+            if (keyboard[(Key)npad.LeftJoycon.ButtonZl])    buttons |= ControllerKeys.Zl;
             
-            if (keyboard[(Key)npad.RightJoycon.StickButton]) buttons |= ControllerButtons.StickRight;
-            if (keyboard[(Key)npad.RightJoycon.ButtonA])     buttons |= ControllerButtons.A;
-            if (keyboard[(Key)npad.RightJoycon.ButtonB])     buttons |= ControllerButtons.B;
-            if (keyboard[(Key)npad.RightJoycon.ButtonX])     buttons |= ControllerButtons.X;
-            if (keyboard[(Key)npad.RightJoycon.ButtonY])     buttons |= ControllerButtons.Y;
-            if (keyboard[(Key)npad.RightJoycon.ButtonPlus])  buttons |= ControllerButtons.Plus;
-            if (keyboard[(Key)npad.RightJoycon.ButtonR])     buttons |= ControllerButtons.R;
-            if (keyboard[(Key)npad.RightJoycon.ButtonZr])    buttons |= ControllerButtons.Zr;
+            if (keyboard[(Key)npad.RightJoycon.StickButton]) buttons |= ControllerKeys.RStick;
+            if (keyboard[(Key)npad.RightJoycon.ButtonA])     buttons |= ControllerKeys.A;
+            if (keyboard[(Key)npad.RightJoycon.ButtonB])     buttons |= ControllerKeys.B;
+            if (keyboard[(Key)npad.RightJoycon.ButtonX])     buttons |= ControllerKeys.X;
+            if (keyboard[(Key)npad.RightJoycon.ButtonY])     buttons |= ControllerKeys.Y;
+            if (keyboard[(Key)npad.RightJoycon.ButtonPlus])  buttons |= ControllerKeys.Plus;
+            if (keyboard[(Key)npad.RightJoycon.ButtonR])     buttons |= ControllerKeys.R | ControllerKeys.Sr;
+            if (keyboard[(Key)npad.RightJoycon.ButtonZr])    buttons |= ControllerKeys.Zr;
 
             return buttons;
         }
@@ -216,9 +223,9 @@ namespace Ryujinx.Ui
             new KeyMappingEntry { TargetKey = Key.NumLock,      Target = 10 },
         };
 
-        public static HLE.Input.Keyboard GetKeysDown(NpadKeyboard npad, KeyboardState keyboard)
+        public static KeyboardInput GetKeysDown(NpadKeyboard npad, KeyboardState keyboard)
         {
-            HLE.Input.Keyboard hidKeyboard = new HLE.Input.Keyboard
+            KeyboardInput hidKeyboard = new KeyboardInput
             {
                     Modifier = 0,
                     Keys     = new int[0x8]
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index 2415280b69..4bbfc78b82 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -10,6 +10,7 @@ using Ryujinx.Graphics.GAL;
 using Ryujinx.Graphics.OpenGL;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.FileSystem.Content;
+using Ryujinx.HLE.HOS.Services.Hid;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -446,7 +447,19 @@ namespace Ryujinx.Ui
 
         private void CreateGameWindow(HLE.Switch device)
         {
-            device.Hid.InitializePrimaryController(ConfigurationState.Instance.Hid.ControllerType);
+            ControllerType type = (Ryujinx.Configuration.Hid.ControllerType)ConfigurationState.Instance.Hid.ControllerType switch {
+                Ryujinx.Configuration.Hid.ControllerType.ProController => ControllerType.ProController,
+                Ryujinx.Configuration.Hid.ControllerType.Handheld => ControllerType.Handheld,
+                Ryujinx.Configuration.Hid.ControllerType.NpadPair => ControllerType.JoyconPair,
+                Ryujinx.Configuration.Hid.ControllerType.NpadLeft => ControllerType.JoyconLeft,
+                Ryujinx.Configuration.Hid.ControllerType.NpadRight => ControllerType.JoyconRight,
+                _ => ControllerType.Handheld
+            };
+            
+            device.Hid.Npads.AddControllers(new ControllerConfig {
+                Player = PlayerIndex.Player1,
+                Type = type
+            });
 
             _gLWidget = new GLRenderer(_emulationContext);
 
diff --git a/Ryujinx/Ui/NpadController.cs b/Ryujinx/Ui/NpadController.cs
index 67961b4914..b92f687cdd 100644
--- a/Ryujinx/Ui/NpadController.cs
+++ b/Ryujinx/Ui/NpadController.cs
@@ -1,7 +1,7 @@
 using OpenTK;
 using OpenTK.Input;
 using Ryujinx.Common.Configuration.Hid;
-using Ryujinx.HLE.Input;
+using Ryujinx.HLE.HOS.Services.Hid;
 using System;
 
 using InnerNpadController = Ryujinx.Common.Configuration.Hid.NpadController;
@@ -24,7 +24,7 @@ namespace Ryujinx.Ui.Input
             return _inner.Enabled && Joystick.GetState(_inner.Index).IsConnected;
         }
 
-        public ControllerButtons GetButtons()
+        public ControllerKeys GetButtons()
         {
             if (!IsEnabled())
             {
@@ -33,30 +33,30 @@ namespace Ryujinx.Ui.Input
 
             JoystickState joystickState = Joystick.GetState(_inner.Index);
 
-            ControllerButtons buttons = 0;
+            ControllerKeys buttons = 0;
 
-            if (IsActivated(joystickState, _inner.LeftJoycon.DPadUp))       buttons |= ControllerButtons.DpadUp;
-            if (IsActivated(joystickState, _inner.LeftJoycon.DPadDown))     buttons |= ControllerButtons.DpadDown;
-            if (IsActivated(joystickState, _inner.LeftJoycon.DPadLeft))     buttons |= ControllerButtons.DpadLeft;
-            if (IsActivated(joystickState, _inner.LeftJoycon.DPadRight))    buttons |= ControllerButtons.DPadRight;
-            if (IsActivated(joystickState, _inner.LeftJoycon.StickButton))  buttons |= ControllerButtons.StickLeft;
-            if (IsActivated(joystickState, _inner.LeftJoycon.ButtonMinus))  buttons |= ControllerButtons.Minus;
-            if (IsActivated(joystickState, _inner.LeftJoycon.ButtonL))      buttons |= ControllerButtons.L;
-            if (IsActivated(joystickState, _inner.LeftJoycon.ButtonZl))     buttons |= ControllerButtons.Zl;
+            if (IsActivated(joystickState, _inner.LeftJoycon.DPadUp))       buttons |= ControllerKeys.DpadUp;
+            if (IsActivated(joystickState, _inner.LeftJoycon.DPadDown))     buttons |= ControllerKeys.DpadDown;
+            if (IsActivated(joystickState, _inner.LeftJoycon.DPadLeft))     buttons |= ControllerKeys.DpadLeft;
+            if (IsActivated(joystickState, _inner.LeftJoycon.DPadRight))    buttons |= ControllerKeys.DpadRight;
+            if (IsActivated(joystickState, _inner.LeftJoycon.StickButton))  buttons |= ControllerKeys.LStick;
+            if (IsActivated(joystickState, _inner.LeftJoycon.ButtonMinus))  buttons |= ControllerKeys.Minus;
+            if (IsActivated(joystickState, _inner.LeftJoycon.ButtonL))      buttons |= ControllerKeys.L | ControllerKeys.Sl;
+            if (IsActivated(joystickState, _inner.LeftJoycon.ButtonZl))     buttons |= ControllerKeys.Zl;
 
-            if (IsActivated(joystickState, _inner.RightJoycon.ButtonA))     buttons |= ControllerButtons.A;
-            if (IsActivated(joystickState, _inner.RightJoycon.ButtonB))     buttons |= ControllerButtons.B;
-            if (IsActivated(joystickState, _inner.RightJoycon.ButtonX))     buttons |= ControllerButtons.X;
-            if (IsActivated(joystickState, _inner.RightJoycon.ButtonY))     buttons |= ControllerButtons.Y;
-            if (IsActivated(joystickState, _inner.RightJoycon.StickButton)) buttons |= ControllerButtons.StickRight;
-            if (IsActivated(joystickState, _inner.RightJoycon.ButtonPlus))  buttons |= ControllerButtons.Plus;
-            if (IsActivated(joystickState, _inner.RightJoycon.ButtonR))     buttons |= ControllerButtons.R;
-            if (IsActivated(joystickState, _inner.RightJoycon.ButtonZr))    buttons |= ControllerButtons.Zr;
+            if (IsActivated(joystickState, _inner.RightJoycon.ButtonA))     buttons |= ControllerKeys.A;
+            if (IsActivated(joystickState, _inner.RightJoycon.ButtonB))     buttons |= ControllerKeys.B;
+            if (IsActivated(joystickState, _inner.RightJoycon.ButtonX))     buttons |= ControllerKeys.X;
+            if (IsActivated(joystickState, _inner.RightJoycon.ButtonY))     buttons |= ControllerKeys.Y;
+            if (IsActivated(joystickState, _inner.RightJoycon.StickButton)) buttons |= ControllerKeys.RStick;
+            if (IsActivated(joystickState, _inner.RightJoycon.ButtonPlus))  buttons |= ControllerKeys.Plus;
+            if (IsActivated(joystickState, _inner.RightJoycon.ButtonR))     buttons |= ControllerKeys.R | ControllerKeys.Sr;
+            if (IsActivated(joystickState, _inner.RightJoycon.ButtonZr))    buttons |= ControllerKeys.Zr;
 
             return buttons;
         }
 
-        private bool IsActivated(JoystickState joystickState,ControllerInputId controllerInputId)
+        private bool IsActivated(JoystickState joystickState, ControllerInputId controllerInputId)
         {
             if (controllerInputId <= ControllerInputId.Button20)
             {