diff --git a/Ryujinx.HLE/DeviceMemory.cs b/Ryujinx.HLE/DeviceMemory.cs
index 524adb84..3553a6e7 100644
--- a/Ryujinx.HLE/DeviceMemory.cs
+++ b/Ryujinx.HLE/DeviceMemory.cs
@@ -1,5 +1,6 @@
 using ChocolArm64.Memory;
 using System;
+using System.Runtime.InteropServices;
 
 namespace Ryujinx.HLE
 {
@@ -98,6 +99,11 @@ namespace Ryujinx.HLE
             *((ulong*)(_ramPtr + position)) = value;
         }
 
+        public unsafe void WriteStruct<T>(long position, T value)
+        {
+            Marshal.StructureToPtr(value, (IntPtr)(_ramPtr + position), false);
+        }
+
         public void FillWithZeros(long position, int size)
         {
             int size8 = size & ~(8 - 1);
@@ -180,4 +186,4 @@ namespace Ryujinx.HLE
             MemoryManagement.Free(RamPointer);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs b/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs
index 051be7a8..fd540c7c 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs
@@ -5,39 +5,39 @@ namespace Ryujinx.HLE.HOS.Services.Hid
 {
     static class HidUtils
     {
-        public static HidControllerId GetIndexFromNpadIdType(NpadIdType npadIdType)
+        public static ControllerId GetIndexFromNpadIdType(NpadIdType npadIdType)
         {
             switch (npadIdType)
             {
-                case NpadIdType.Player1:  return HidControllerId.ControllerPlayer1;
-                case NpadIdType.Player2:  return HidControllerId.ControllerPlayer2;
-                case NpadIdType.Player3:  return HidControllerId.ControllerPlayer3;
-                case NpadIdType.Player4:  return HidControllerId.ControllerPlayer4;
-                case NpadIdType.Player5:  return HidControllerId.ControllerPlayer5;
-                case NpadIdType.Player6:  return HidControllerId.ControllerPlayer6;
-                case NpadIdType.Player7:  return HidControllerId.ControllerPlayer7;
-                case NpadIdType.Player8:  return HidControllerId.ControllerPlayer8;
-                case NpadIdType.Handheld: return HidControllerId.ControllerHandheld;
-                case NpadIdType.Unknown:  return HidControllerId.ControllerUnknown;
+                case NpadIdType.Player1:  return ControllerId.ControllerPlayer1;
+                case NpadIdType.Player2:  return ControllerId.ControllerPlayer2;
+                case NpadIdType.Player3:  return ControllerId.ControllerPlayer3;
+                case NpadIdType.Player4:  return ControllerId.ControllerPlayer4;
+                case NpadIdType.Player5:  return ControllerId.ControllerPlayer5;
+                case NpadIdType.Player6:  return ControllerId.ControllerPlayer6;
+                case NpadIdType.Player7:  return ControllerId.ControllerPlayer7;
+                case NpadIdType.Player8:  return ControllerId.ControllerPlayer8;
+                case NpadIdType.Handheld: return ControllerId.ControllerHandheld;
+                case NpadIdType.Unknown:  return ControllerId.ControllerUnknown;
 
                 default: throw new ArgumentOutOfRangeException(nameof(npadIdType));
             }
         }
 
-        public static NpadIdType GetNpadIdTypeFromIndex(HidControllerId index)
+        public static NpadIdType GetNpadIdTypeFromIndex(ControllerId index)
         {
             switch (index)
             {
-                case HidControllerId.ControllerPlayer1:  return NpadIdType.Player1;
-                case HidControllerId.ControllerPlayer2:  return NpadIdType.Player2;
-                case HidControllerId.ControllerPlayer3:  return NpadIdType.Player3;
-                case HidControllerId.ControllerPlayer4:  return NpadIdType.Player4;
-                case HidControllerId.ControllerPlayer5:  return NpadIdType.Player5;
-                case HidControllerId.ControllerPlayer6:  return NpadIdType.Player6;
-                case HidControllerId.ControllerPlayer7:  return NpadIdType.Player7;
-                case HidControllerId.ControllerPlayer8:  return NpadIdType.Player8;
-                case HidControllerId.ControllerHandheld: return NpadIdType.Handheld;
-                case HidControllerId.ControllerUnknown:  return NpadIdType.Unknown;
+                case ControllerId.ControllerPlayer1:  return NpadIdType.Player1;
+                case ControllerId.ControllerPlayer2:  return NpadIdType.Player2;
+                case ControllerId.ControllerPlayer3:  return NpadIdType.Player3;
+                case ControllerId.ControllerPlayer4:  return NpadIdType.Player4;
+                case ControllerId.ControllerPlayer5:  return NpadIdType.Player5;
+                case ControllerId.ControllerPlayer6:  return NpadIdType.Player6;
+                case ControllerId.ControllerPlayer7:  return NpadIdType.Player7;
+                case ControllerId.ControllerPlayer8:  return NpadIdType.Player8;
+                case ControllerId.ControllerHandheld: return NpadIdType.Handheld;
+                case ControllerId.ControllerUnknown:  return NpadIdType.Unknown;
 
                 default: throw new ArgumentOutOfRangeException(nameof(index));
             }
diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
index 22bd28f3..7d77ff32 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
@@ -569,8 +569,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetSupportedNpadIdType(nn::applet::AppletResourceUserId, array<NpadIdType, 9>)
         public ResultCode SetSupportedNpadIdType(ServiceCtx context)
         {
-            long appletResourceUserId  = context.RequestData.ReadInt64();
-            HidControllerId npadIdType = (HidControllerId)context.RequestData.ReadInt64();
+            long         appletResourceUserId  = context.RequestData.ReadInt64();
+            ControllerId npadIdType            = (ControllerId)context.RequestData.ReadInt64();
 
             Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType });
 
@@ -687,8 +687,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetNpadJoyAssignmentModeSingleByDefault(uint HidControllerId, nn::applet::AppletResourceUserId)
         public ResultCode SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx context)
         {
-            HidControllerId hidControllerId      = (HidControllerId)context.RequestData.ReadInt32();
-            long            appletResourceUserId = context.RequestData.ReadInt64();
+            ControllerId hidControllerId      = (ControllerId)context.RequestData.ReadInt32();
+            long         appletResourceUserId = context.RequestData.ReadInt64();
 
             _npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Single;
 
@@ -701,7 +701,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetNpadJoyAssignmentModeSingle(uint HidControllerId, nn::applet::AppletResourceUserId, long HidNpadJoyDeviceType)
         public ResultCode SetNpadJoyAssignmentModeSingle(ServiceCtx context)
         {
-            HidControllerId      hidControllerId      = (HidControllerId)context.RequestData.ReadInt32();
+            ControllerId         hidControllerId      = (ControllerId)context.RequestData.ReadInt32();
             long                 appletResourceUserId = context.RequestData.ReadInt64();
             HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64();
 
@@ -716,8 +716,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetNpadJoyAssignmentModeDual(uint HidControllerId, nn::applet::AppletResourceUserId)
         public ResultCode SetNpadJoyAssignmentModeDual(ServiceCtx context)
         {
-            HidControllerId hidControllerId      = (HidControllerId)context.RequestData.ReadInt32();
-            long            appletResourceUserId = context.RequestData.ReadInt64();
+            ControllerId hidControllerId      = (ControllerId)context.RequestData.ReadInt32();
+            long         appletResourceUserId = context.RequestData.ReadInt64();
 
             _npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual;
 
@@ -830,7 +830,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         // SetNpadJoyAssignmentModeSingleWithDestination(uint HidControllerId, long HidNpadJoyDeviceType, nn::applet::AppletResourceUserId) -> bool Unknown0, uint Unknown1
         public ResultCode SetNpadJoyAssignmentModeSingleWithDestination(ServiceCtx context)
         {
-            HidControllerId      hidControllerId      = (HidControllerId)context.RequestData.ReadInt32();
+            ControllerId         hidControllerId      = (ControllerId)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 d6659fd8..d2991d0f 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
@@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
                 return ResultCode.NpadIdOutOfRange;
             }
 
-            HidControllerId irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType);
+            ControllerId irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType);
 
             context.ResponseData.Write((int)irCameraHandle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs
index a1f58dae..3c49ee51 100644
--- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs
@@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
 
         public DeviceState State = DeviceState.Unavailable;
 
-        public HidControllerId Handle;
-        public NpadIdType      NpadIdType;
+        public ControllerId 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
new file mode 100644
index 00000000..dfd54a83
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/BaseController.cs
@@ -0,0 +1,142 @@
+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
new file mode 100644
index 00000000..b4304b8f
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/NpadController.cs
@@ -0,0 +1,68 @@
+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
new file mode 100644
index 00000000..ae574260
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/ProController.cs
@@ -0,0 +1,42 @@
+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
new file mode 100644
index 00000000..4279d7a0
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/Types/BatteryState.cs
@@ -0,0 +1,12 @@
+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/HidControllerButtons.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs
similarity index 95%
rename from Ryujinx.HLE/Input/HidControllerButtons.cs
rename to Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs
index 07a3a118..879257f2 100644
--- a/Ryujinx.HLE/Input/HidControllerButtons.cs
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs
@@ -3,7 +3,7 @@ using System;
 namespace Ryujinx.HLE.Input
 {
     [Flags]
-    public enum HidControllerButtons
+    public enum ControllerButtons : long
     {
         A           = 1 << 0,
         B           = 1 << 1,
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs
new file mode 100644
index 00000000..c31f41a3
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Ryujinx.HLE.Input
+{
+    [Flags]
+    public enum ControllerColorDescription : int
+    {
+        ColorDescriptionColorsNonexistent = (1 << 1)
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/HidControllerConnState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs
similarity index 76%
rename from Ryujinx.HLE/Input/HidControllerConnState.cs
rename to Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs
index ef41cbb8..526da1ff 100644
--- a/Ryujinx.HLE/Input/HidControllerConnState.cs
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs
@@ -3,7 +3,7 @@ using System;
 namespace Ryujinx.HLE.Input
 {
     [Flags]
-    public enum HidControllerConnState
+    public enum ControllerConnectionState : long
     {
         ControllerStateConnected = (1 << 0),
         ControllerStateWired     = (1 << 1)
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs
new file mode 100644
index 00000000..45895a1e
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 00000000..8043d8a0
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceType.cs
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 00000000..cbb5b6f5
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerHeader.cs
@@ -0,0 +1,19 @@
+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/HidControllerId.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerId.cs
similarity index 91%
rename from Ryujinx.HLE/Input/HidControllerId.cs
rename to Ryujinx.HLE/Input/Controller/Types/ControllerId.cs
index 60faf822..c82056c6 100644
--- a/Ryujinx.HLE/Input/HidControllerId.cs
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerId.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.HLE.Input
 {
-    public enum HidControllerId
+    public enum ControllerId
     {
         ControllerPlayer1  = 0,
         ControllerPlayer2  = 1,
diff --git a/Ryujinx.HLE/Input/HidControllerLayouts.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs
similarity index 86%
rename from Ryujinx.HLE/Input/HidControllerLayouts.cs
rename to Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs
index 3548175f..fedc0399 100644
--- a/Ryujinx.HLE/Input/HidControllerLayouts.cs
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.HLE.Input
 {
-    public enum HidControllerLayouts
+    public enum ControllerLayouts
     {
         ProController  = 0,
         HandheldJoined = 1,
diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs
new file mode 100644
index 00000000..4847438d
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs
@@ -0,0 +1,15 @@
+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
new file mode 100644
index 00000000..f885c00c
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerStateHeader.cs
@@ -0,0 +1,13 @@
+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/HidControllerType.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs
similarity index 85%
rename from Ryujinx.HLE/Input/HidControllerType.cs
rename to Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs
index 74bca365..9444d7b0 100644
--- a/Ryujinx.HLE/Input/HidControllerType.cs
+++ b/Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs
@@ -3,7 +3,7 @@ using System;
 namespace Ryujinx.HLE.Input
 {
     [Flags]
-    public enum HidControllerType
+    public enum ControllerStatus : int
     {
         ProController = 1 << 0,
         Handheld      = 1 << 1,
diff --git a/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs b/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs
new file mode 100644
index 00000000..53913175
--- /dev/null
+++ b/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs
@@ -0,0 +1,22 @@
+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/HidHotkeyButtons.cs b/Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs
similarity index 75%
rename from Ryujinx.HLE/Input/HidHotkeyButtons.cs
rename to Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs
index 7fa6ed6d..be76ee1e 100644
--- a/Ryujinx.HLE/Input/HidHotkeyButtons.cs
+++ b/Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs
@@ -3,7 +3,7 @@
 namespace Ryujinx.HLE.Input
 {
     [Flags]
-    public enum HidHotkeyButtons
+    public enum HotkeyButtons
     {
         ToggleVSync = 1 << 0,
     }
diff --git a/Ryujinx.HLE/Input/HidJoystickPosition.cs b/Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs
similarity index 70%
rename from Ryujinx.HLE/Input/HidJoystickPosition.cs
rename to Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs
index a1fe1608..1442bc60 100644
--- a/Ryujinx.HLE/Input/HidJoystickPosition.cs
+++ b/Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.HLE.Input
 {
-    public struct HidJoystickPosition
+    public struct JoystickPosition
     {
         public int Dx;
         public int Dy;
diff --git a/Ryujinx.HLE/Input/NpadColor.cs b/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs
similarity index 92%
rename from Ryujinx.HLE/Input/NpadColor.cs
rename to Ryujinx.HLE/Input/Controller/Types/NpadColor.cs
index b15c45d8..a60f94aa 100644
--- a/Ryujinx.HLE/Input/NpadColor.cs
+++ b/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.HLE.Input
 {
-    public enum NpadColor //Thanks to CTCaer
+    public enum NpadColor : int //Thanks to CTCaer
     {
         Black = 0,
 
diff --git a/Ryujinx.HLE/Input/Hid.cs b/Ryujinx.HLE/Input/Hid.cs
index c42f3b6c..27e6a308 100644
--- a/Ryujinx.HLE/Input/Hid.cs
+++ b/Ryujinx.HLE/Input/Hid.cs
@@ -7,7 +7,15 @@ namespace Ryujinx.HLE.Input
     {
         private Switch _device;
 
-        public HidControllerBase PrimaryController { get; private set; }
+        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;
 
@@ -17,22 +25,42 @@ namespace Ryujinx.HLE.Input
             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;
         }
 
-        public void InitializePrimaryController(HidControllerType controllerType)
+        public void InitializePrimaryController(ControllerStatus controllerType)
         {
-            HidControllerId controllerId = controllerType == HidControllerType.Handheld ?
-                HidControllerId.ControllerHandheld : HidControllerId.ControllerPlayer1;
+            ControllerId controllerId = controllerType == ControllerStatus.Handheld ?
+                ControllerId.ControllerHandheld : ControllerId.ControllerPlayer1;
 
-            if (controllerType == HidControllerType.ProController)
+            if (controllerType == ControllerStatus.ProController)
             {
-                PrimaryController = new HidProController(_device);
+                PrimaryController = new ProController(_device, NpadColor.Black, NpadColor.Black);
             }
             else
             {
-                PrimaryController = new HidNpadController(controllerType,
+                PrimaryController = new NpadController(controllerType,
                      _device,
-                     (NpadColor.BodyNeonRed, NpadColor.BodyNeonRed),
+                     (NpadColor.BodyNeonRed,     NpadColor.BodyNeonRed),
                      (NpadColor.ButtonsNeonBlue, NpadColor.ButtonsNeonBlue));
             }
 
@@ -44,124 +72,132 @@ namespace Ryujinx.HLE.Input
             _device.Memory.FillWithZeros(HidPosition + HidKeyboardOffset, HidKeyboardSize);
         }
 
-        public HidControllerButtons UpdateStickButtons(
-            HidJoystickPosition leftStick,
-            HidJoystickPosition rightStick)
+        public ControllerButtons UpdateStickButtons(
+            JoystickPosition leftStick,
+            JoystickPosition rightStick)
         {
-            HidControllerButtons result = 0;
+            ControllerButtons result = 0;
 
             if (rightStick.Dx < 0)
             {
-                result |= HidControllerButtons.RStickLeft;
+                result |= ControllerButtons.RStickLeft;
             }
 
             if (rightStick.Dx > 0)
             {
-                result |= HidControllerButtons.RStickRight;
+                result |= ControllerButtons.RStickRight;
             }
 
             if (rightStick.Dy < 0)
             {
-                result |= HidControllerButtons.RStickDown;
+                result |= ControllerButtons.RStickDown;
             }
 
             if (rightStick.Dy > 0)
             {
-                result |= HidControllerButtons.RStickUp;
+                result |= ControllerButtons.RStickUp;
             }
 
             if (leftStick.Dx < 0)
             {
-                result |= HidControllerButtons.LStickLeft;
+                result |= ControllerButtons.LStickLeft;
             }
 
             if (leftStick.Dx > 0)
             {
-                result |= HidControllerButtons.LStickRight;
+                result |= ControllerButtons.LStickRight;
             }
 
             if (leftStick.Dy < 0)
             {
-                result |= HidControllerButtons.LStickDown;
+                result |= ControllerButtons.LStickDown;
             }
 
             if (leftStick.Dy > 0)
             {
-                result |= HidControllerButtons.LStickUp;
+                result |= ControllerButtons.LStickUp;
             }
 
             return result;
         }
-
-        public void SetTouchPoints(params HidTouchPoint[] points)
+        public void SetTouchPoints(params TouchPoint[] points)
         {
-            long touchScreenOffset = HidPosition + HidTouchScreenOffset;
-            long lastEntry         = _device.Memory.ReadInt64(touchScreenOffset + 0x10);
-            long currEntry         = (lastEntry + 1) % HidEntryCount;
-            long timestamp         = GetTimestamp();
+            long timestamp     = GetTimestamp();
+            long sampleCounter = _currentTouchHeader.SamplesTimestamp + 1;
 
-            _device.Memory.WriteInt64(touchScreenOffset + 0x00, timestamp);
-            _device.Memory.WriteInt64(touchScreenOffset + 0x08, HidEntryCount);
-            _device.Memory.WriteInt64(touchScreenOffset + 0x10, currEntry);
-            _device.Memory.WriteInt64(touchScreenOffset + 0x18, HidEntryCount - 1);
-            _device.Memory.WriteInt64(touchScreenOffset + 0x20, timestamp);
-
-            long touchEntryOffset = touchScreenOffset + HidTouchHeaderSize;
-            long lastEntryOffset  = touchEntryOffset + lastEntry * HidTouchEntrySize;
-            long sampleCounter    = _device.Memory.ReadInt64(lastEntryOffset) + 1;
-
-            touchEntryOffset += currEntry * HidTouchEntrySize;
-
-            _device.Memory.WriteInt64(touchEntryOffset + 0x00, sampleCounter);
-            _device.Memory.WriteInt64(touchEntryOffset + 0x08, points.Length);
-
-            touchEntryOffset += HidTouchEntryHeaderSize;
-
-            const int padding = 0;
-
-            int index = 0;
-
-            foreach (HidTouchPoint point in points)
+            var newTouchHeader = new TouchHeader
             {
-                _device.Memory.WriteInt64(touchEntryOffset + 0x00, sampleCounter);
-                _device.Memory.WriteInt32(touchEntryOffset + 0x08, padding);
-                _device.Memory.WriteInt32(touchEntryOffset + 0x0c, index++);
-                _device.Memory.WriteInt32(touchEntryOffset + 0x10, point.X);
-                _device.Memory.WriteInt32(touchEntryOffset + 0x14, point.Y);
-                _device.Memory.WriteInt32(touchEntryOffset + 0x18, point.DiameterX);
-                _device.Memory.WriteInt32(touchEntryOffset + 0x1c, point.DiameterY);
-                _device.Memory.WriteInt32(touchEntryOffset + 0x20, point.Angle);
-                _device.Memory.WriteInt32(touchEntryOffset + 0x24, padding);
+                CurrentEntryIndex = (_currentTouchHeader.CurrentEntryIndex + 1) % HidEntryCount,
+                EntryCount        = HidEntryCount,
+                MaxEntries        = HidEntryCount - 1,
+                SamplesTimestamp  = sampleCounter,
+                Timestamp         = timestamp,
+            };
 
-                touchEntryOffset += HidTouchEntryTouchSize;
+            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 void WriteKeyboard(HidKeyboard keyboard)
+        public unsafe void WriteKeyboard(Keyboard keyboard)
         {
-            long keyboardOffset = HidPosition + HidKeyboardOffset;
-            long lastEntry      = _device.Memory.ReadInt64(keyboardOffset + 0x10);
-            long currEntry      = (lastEntry + 1) % HidEntryCount;
-            long timestamp      = GetTimestamp();
+            long timestamp = GetTimestamp();
 
-            _device.Memory.WriteInt64(keyboardOffset + 0x00, timestamp);
-            _device.Memory.WriteInt64(keyboardOffset + 0x08, HidEntryCount);
-            _device.Memory.WriteInt64(keyboardOffset + 0x10, currEntry);
-            _device.Memory.WriteInt64(keyboardOffset + 0x18, HidEntryCount - 1);
-
-            long keyboardEntryOffset = keyboardOffset + HidKeyboardHeaderSize;
-            long lastEntryOffset     = keyboardEntryOffset + lastEntry * HidKeyboardEntrySize;
-            long sampleCounter       = _device.Memory.ReadInt64(lastEntryOffset);
-
-            keyboardEntryOffset += currEntry * HidKeyboardEntrySize;
-            _device.Memory.WriteInt64(keyboardEntryOffset + 0x00, sampleCounter + 1);
-            _device.Memory.WriteInt64(keyboardEntryOffset + 0x08, sampleCounter);
-            _device.Memory.WriteInt64(keyboardEntryOffset + 0x10, keyboard.Modifier);
-
-            for (int i = 0; i < keyboard.Keys.Length; i++)
+            var newKeyboardHeader = new KeyboardHeader()
             {
-                _device.Memory.WriteInt32(keyboardEntryOffset + 0x18 + (i * 4), keyboard.Keys[i]);
-            }
+                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()
diff --git a/Ryujinx.HLE/Input/HidBaseController.cs b/Ryujinx.HLE/Input/HidBaseController.cs
deleted file mode 100644
index 8b29d891..00000000
--- a/Ryujinx.HLE/Input/HidBaseController.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using static Ryujinx.HLE.Input.Hid;
-
-namespace Ryujinx.HLE.Input
-{
-    public abstract class HidControllerBase : IHidDevice
-    {
-        protected HidControllerType HidControllerType;
-        protected Switch            Device;
-        protected HidControllerId   ControllerId;
-
-        public long Offset    { get; private set; }
-        public bool Connected { get; protected set; }
-
-        public HidControllerBase(HidControllerType controllerType, Switch device)
-        {
-            Device = device;
-
-            HidControllerType = controllerType;
-        }
-
-        public virtual void Connect(HidControllerId controllerId)
-        {
-            ControllerId = controllerId;
-
-            Offset = Device.Hid.HidPosition + HidControllersOffset + (int)controllerId * HidControllerSize;
-
-            Device.Memory.FillWithZeros(Offset, 0x5000);
-
-            Device.Memory.WriteInt32(Offset + 0x00, (int)HidControllerType);
-        }
-
-        public abstract void SendInput(
-            HidControllerButtons buttons,
-            HidJoystickPosition  leftStick,
-            HidJoystickPosition  rightStick);
-
-        protected long WriteInput(
-            HidControllerButtons buttons,
-            HidJoystickPosition  leftStick,
-            HidJoystickPosition  rightStick, 
-            HidControllerLayouts controllerLayout)
-        {
-            long controllerOffset = Offset + HidControllerHeaderSize;
-
-            controllerOffset += (int)controllerLayout * HidControllerLayoutsSize;
-
-            long lastEntry = Device.Memory.ReadInt64(controllerOffset + 0x10);
-            long currEntry = (lastEntry + 1) % HidEntryCount;
-            long timestamp = GetTimestamp();
-
-            Device.Memory.WriteInt64(controllerOffset + 0x00, timestamp);
-            Device.Memory.WriteInt64(controllerOffset + 0x08, HidEntryCount);
-            Device.Memory.WriteInt64(controllerOffset + 0x10, currEntry);
-            Device.Memory.WriteInt64(controllerOffset + 0x18, HidEntryCount - 1);
-
-            controllerOffset += HidControllersLayoutHeaderSize;
-
-            long lastEntryOffset = controllerOffset + lastEntry * HidControllersInputEntrySize;
-
-            controllerOffset += currEntry * HidControllersInputEntrySize;
-
-            long sampleCounter = Device.Memory.ReadInt64(lastEntryOffset) + 1;
-
-            Device.Memory.WriteInt64(controllerOffset + 0x00, sampleCounter);
-            Device.Memory.WriteInt64(controllerOffset + 0x08, sampleCounter);
-            Device.Memory.WriteInt64(controllerOffset + 0x10, (uint)buttons);
-
-            Device.Memory.WriteInt32(controllerOffset + 0x18, leftStick.Dx);
-            Device.Memory.WriteInt32(controllerOffset + 0x1c, leftStick.Dy);
-            Device.Memory.WriteInt32(controllerOffset + 0x20, rightStick.Dx);
-            Device.Memory.WriteInt32(controllerOffset + 0x24, rightStick.Dy);
-
-            return controllerOffset;
-        }
-    }
-}
diff --git a/Ryujinx.HLE/Input/HidControllerColorDesc.cs b/Ryujinx.HLE/Input/HidControllerColorDesc.cs
deleted file mode 100644
index 85ece5f1..00000000
--- a/Ryujinx.HLE/Input/HidControllerColorDesc.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.Input
-{
-    [Flags]
-    public enum HidControllerColorDesc
-    {
-        ColorDescColorsNonexistent = (1 << 1)
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/Input/HidNpadController.cs b/Ryujinx.HLE/Input/HidNpadController.cs
deleted file mode 100644
index 0c773e86..00000000
--- a/Ryujinx.HLE/Input/HidNpadController.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public class HidNpadController : HidControllerBase
-    {
-        private (NpadColor Left, NpadColor Right) _npadBodyColors;
-        private (NpadColor Left, NpadColor Right) _npadButtonColors;
-
-        private HidControllerLayouts _currentLayout;
-
-        private bool _isHalf;
-
-        public HidNpadController(
-            HidControllerType      controllerType,
-            Switch                 device,
-            (NpadColor, NpadColor) npadBodyColors,
-            (NpadColor, NpadColor) npadButtonColors) : base(controllerType, device)
-        {
-            _npadBodyColors   = npadBodyColors;
-            _npadButtonColors = npadButtonColors;
-
-            _currentLayout = HidControllerLayouts.HandheldJoined;
-
-            switch (controllerType)
-            {
-                case HidControllerType.NpadLeft:
-                    _currentLayout = HidControllerLayouts.Left;
-                    break;
-                case HidControllerType.NpadRight:
-                    _currentLayout = HidControllerLayouts.Right;
-                    break;
-                case HidControllerType.NpadPair:
-                    _currentLayout = HidControllerLayouts.Joined;
-                    break;
-            }
-        }
-
-        public override void Connect(HidControllerId controllerId)
-        {
-            if (HidControllerType != HidControllerType.NpadLeft && HidControllerType != HidControllerType.NpadRight)
-            {
-                _isHalf = false;
-            }
-
-            base.Connect(_currentLayout == HidControllerLayouts.HandheldJoined ? HidControllerId.ControllerHandheld : controllerId);
-
-            HidControllerColorDesc singleColorDesc =
-                HidControllerColorDesc.ColorDescColorsNonexistent;
-
-            HidControllerColorDesc splitColorDesc = 0;
-
-            NpadColor singleColorBody    = NpadColor.Black;
-            NpadColor singleColorButtons = NpadColor.Black;
-
-            Device.Memory.WriteInt32(Offset + 0x04, _isHalf ? 1 : 0);
-
-            if (_isHalf)
-            {
-                Device.Memory.WriteInt32(Offset + 0x08, (int)singleColorDesc);
-                Device.Memory.WriteInt32(Offset + 0x0c, (int)singleColorBody);
-                Device.Memory.WriteInt32(Offset + 0x10, (int)singleColorButtons);
-                Device.Memory.WriteInt32(Offset + 0x14, (int)splitColorDesc);
-            }
-            else
-            {
-                Device.Memory.WriteInt32(Offset + 0x18, (int)_npadBodyColors.Left);
-                Device.Memory.WriteInt32(Offset + 0x1c, (int)_npadButtonColors.Left);
-                Device.Memory.WriteInt32(Offset + 0x20, (int)_npadBodyColors.Right);
-                Device.Memory.WriteInt32(Offset + 0x24, (int)_npadButtonColors.Right);
-            }
-
-            Connected = true;
-        }
-
-        public override void SendInput
-            (HidControllerButtons buttons,
-            HidJoystickPosition   leftStick,
-            HidJoystickPosition   rightStick)
-        {
-            long controllerOffset = WriteInput(buttons, leftStick, rightStick, _currentLayout);
-
-            Device.Memory.WriteInt64(controllerOffset + 0x28,
-              (Connected ? (uint)HidControllerConnState.ControllerStateConnected : 0) |
-              (_currentLayout == HidControllerLayouts.HandheldJoined ? (uint)HidControllerConnState.ControllerStateWired : 0));
-
-            controllerOffset = WriteInput(buttons, leftStick, rightStick, HidControllerLayouts.Main);
-
-            Device.Memory.WriteInt64(controllerOffset + 0x28,
-              (Connected ? (uint)HidControllerConnState.ControllerStateWired : 0) |
-              (uint)HidControllerConnState.ControllerStateWired);
-        }
-    }
-}
diff --git a/Ryujinx.HLE/Input/HidProController.cs b/Ryujinx.HLE/Input/HidProController.cs
deleted file mode 100644
index e30e9172..00000000
--- a/Ryujinx.HLE/Input/HidProController.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-namespace Ryujinx.HLE.Input
-{
-    public class HidProController : HidControllerBase
-    {
-        bool _wired = false;
-
-        public HidProController(Switch device) : base(HidControllerType.ProController, device)
-        {
-            _wired = true;
-        }
-
-        public override void Connect(HidControllerId controllerId)
-        {
-            base.Connect(controllerId);
-
-            HidControllerColorDesc singleColorDesc =
-                HidControllerColorDesc.ColorDescColorsNonexistent;
-
-            HidControllerColorDesc splitColorDesc = 0;
-
-            NpadColor singleColorBody    = NpadColor.Black;
-            NpadColor singleColorButtons = NpadColor.Black;
-
-            Device.Memory.WriteInt32(Offset + 0x08, (int)singleColorDesc);
-            Device.Memory.WriteInt32(Offset + 0x0c, (int)singleColorBody);
-            Device.Memory.WriteInt32(Offset + 0x10, (int)singleColorButtons);
-            Device.Memory.WriteInt32(Offset + 0x14, (int)splitColorDesc);
-
-            Connected = true;
-        }
-
-        public override void SendInput(
-            HidControllerButtons buttons,
-            HidJoystickPosition  leftStick,
-            HidJoystickPosition  rightStick)
-        {
-            long controllerOffset = WriteInput(buttons, leftStick, rightStick, HidControllerLayouts.ProController);
-
-            Device.Memory.WriteInt64(controllerOffset + 0x28,
-              (Connected ? (uint)HidControllerConnState.ControllerStateConnected : 0) |
-              (_wired ? (uint)HidControllerConnState.ControllerStateWired : 0));
-
-            controllerOffset = WriteInput(buttons, leftStick, rightStick, HidControllerLayouts.Main);
-
-            Device.Memory.WriteInt64(controllerOffset + 0x28,
-              (Connected ? (uint)HidControllerConnState.ControllerStateWired : 0) |
-              (uint)HidControllerConnState.ControllerStateWired);
-        }
-    }
-}
diff --git a/Ryujinx.HLE/Input/HidKeyboard.cs b/Ryujinx.HLE/Input/Keyboard/Keyboard.cs
similarity index 77%
rename from Ryujinx.HLE/Input/HidKeyboard.cs
rename to Ryujinx.HLE/Input/Keyboard/Keyboard.cs
index a5b042a5..7220e518 100644
--- a/Ryujinx.HLE/Input/HidKeyboard.cs
+++ b/Ryujinx.HLE/Input/Keyboard/Keyboard.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.HLE.Input
 {
-    public struct HidKeyboard
+    public struct Keyboard
     {
         public int   Modifier;
         public int[] Keys;
diff --git a/Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs b/Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs
new file mode 100644
index 00000000..be7d9399
--- /dev/null
+++ b/Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs
@@ -0,0 +1,15 @@
+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
new file mode 100644
index 00000000..882ccbab
--- /dev/null
+++ b/Ryujinx.HLE/Input/Keyboard/KeyboardHeader.cs
@@ -0,0 +1,13 @@
+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
new file mode 100644
index 00000000..8489ef70
--- /dev/null
+++ b/Ryujinx.HLE/Input/Touch/TouchData.cs
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 00000000..2ef09d75
--- /dev/null
+++ b/Ryujinx.HLE/Input/Touch/TouchEntry.cs
@@ -0,0 +1,11 @@
+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
new file mode 100644
index 00000000..dd93137c
--- /dev/null
+++ b/Ryujinx.HLE/Input/Touch/TouchHeader.cs
@@ -0,0 +1,14 @@
+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/HidTouchPoint.cs b/Ryujinx.HLE/Input/Touch/TouchPoint.cs
similarity index 84%
rename from Ryujinx.HLE/Input/HidTouchPoint.cs
rename to Ryujinx.HLE/Input/Touch/TouchPoint.cs
index 25412456..a9b095de 100644
--- a/Ryujinx.HLE/Input/HidTouchPoint.cs
+++ b/Ryujinx.HLE/Input/Touch/TouchPoint.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.HLE.Input
 {
-    public struct HidTouchPoint
+    public struct TouchPoint
     {
         public int X;
         public int Y;
diff --git a/Ryujinx.Profiler/ProfileConfig.cs b/Ryujinx.Profiler/ProfileConfig.cs
index d70da602..4271bd2b 100644
--- a/Ryujinx.Profiler/ProfileConfig.cs
+++ b/Ryujinx.Profiler/ProfileConfig.cs
@@ -105,6 +105,21 @@ namespace Ryujinx.Profiler
             };
         }
 
+        public static class Input
+        {
+            public static ProfileConfig ControllerInput = new ProfileConfig
+            {
+                Category     = "Input",
+                SessionGroup = "ControllerInput"
+            };
+
+            public static ProfileConfig TouchInput = new ProfileConfig
+            {
+                Category     = "Input",
+                SessionGroup = "TouchInput"
+            };
+        }
+
         public static class GPU
         {
             public static class Engine2d
diff --git a/Ryujinx/Config.jsonc b/Ryujinx/Config.jsonc
index 4bbdd5a4..fa961d29 100644
--- a/Ryujinx/Config.jsonc
+++ b/Ryujinx/Config.jsonc
@@ -64,7 +64,7 @@
     "controller_type": "Handheld",
 
     // Enable or disable "direct keyboard access (HID) support" (Provides games access to your keyboard as a text entry device).
-    "enable_keyboard": true,
+    "enable_keyboard": false,
 
     // Keyboard Controls
     // https://github.com/opentk/opentk/blob/master/src/OpenTK/Input/Key.cs
diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration.cs
index 77895ac8..72f507de 100644
--- a/Ryujinx/Configuration.cs
+++ b/Ryujinx/Configuration.cs
@@ -120,7 +120,7 @@ namespace Ryujinx
         /// <summary>
         ///  The primary controller's type
         /// </summary>
-        public HidControllerType ControllerType { get; private set; }
+        public ControllerStatus ControllerType { get; private set; }
 
         /// <summary>
         /// Enable or disable keyboard support (Independent from controllers binding)
@@ -135,7 +135,7 @@ namespace Ryujinx
         /// <summary>
         /// Controller control bindings
         /// </summary>
-        public NpadController GamepadControls { get; private set; }
+        public UI.Input.NpadController GamepadControls { get; private set; }
 
         /// <summary>
         /// Loads a configuration file from disk
diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs
index c5772799..33ecc917 100644
--- a/Ryujinx/Ui/GLScreen.cs
+++ b/Ryujinx/Ui/GLScreen.cs
@@ -23,7 +23,7 @@ namespace Ryujinx
 
         private IGalRenderer _renderer;
 
-        private HidHotkeyButtons _prevHotkeyButtons = 0;
+        private HotkeyButtons _prevHotkeyButtons = 0;
 
         private KeyboardState? _keyboard = null;
 
@@ -140,11 +140,11 @@ namespace Ryujinx
 
         private new void UpdateFrame()
         {
-            HidHotkeyButtons     currentHotkeyButtons = 0;
-            HidControllerButtons currentButton = 0;
-            HidJoystickPosition  leftJoystick;
-            HidJoystickPosition  rightJoystick;
-            HidKeyboard?         hidKeyboard = null;
+            HotkeyButtons       currentHotkeyButtons = 0;
+            ControllerButtons   currentButton = 0;
+            JoystickPosition    leftJoystick;
+            JoystickPosition    rightJoystick;
+            HLE.Input.Keyboard? hidKeyboard = null;
 
             int leftJoystickDx  = 0;
             int leftJoystickDy  = 0;
@@ -176,7 +176,7 @@ namespace Ryujinx
 
             if (!hidKeyboard.HasValue)
             {
-                hidKeyboard = new HidKeyboard
+                hidKeyboard = new HLE.Input.Keyboard
                 {
                     Modifier = 0,
                     Keys     = new int[0x8]
@@ -196,13 +196,13 @@ namespace Ryujinx
                 (rightJoystickDx, rightJoystickDy) = Configuration.Instance.GamepadControls.GetRightStick();
             }
 
-            leftJoystick = new HidJoystickPosition
+            leftJoystick = new JoystickPosition
             {
                 Dx = leftJoystickDx,
                 Dy = leftJoystickDy
             };
 
-            rightJoystick = new HidJoystickPosition
+            rightJoystick = new JoystickPosition
             {
                 Dx = rightJoystickDx,
                 Dy = rightJoystickDy
@@ -247,7 +247,7 @@ namespace Ryujinx
                     int mX = (scrnMouseX * TouchScreenWidth)  / scrnWidth;
                     int mY = (scrnMouseY * TouchScreenHeight) / scrnHeight;
 
-                    HidTouchPoint currentPoint = new HidTouchPoint
+                    TouchPoint currentPoint = new TouchPoint
                     {
                         X = mX,
                         Y = mY,
@@ -274,13 +274,13 @@ namespace Ryujinx
                 _device.Hid.WriteKeyboard(hidKeyboard.Value);
             }
 
-            HidControllerBase controller = _device.Hid.PrimaryController;
+            BaseController controller = _device.Hid.PrimaryController;
 
             controller.SendInput(currentButton, leftJoystick, rightJoystick);
 
             // Toggle vsync
-            if (currentHotkeyButtons.HasFlag(HidHotkeyButtons.ToggleVSync) &&
-                !_prevHotkeyButtons.HasFlag(HidHotkeyButtons.ToggleVSync))
+            if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) &&
+                !_prevHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync))
             {
                 _device.EnableDeviceVsync = !_device.EnableDeviceVsync;
             }
diff --git a/Ryujinx/Ui/NpadController.cs b/Ryujinx/Ui/NpadController.cs
index eddf0aa8..71f97fb8 100644
--- a/Ryujinx/Ui/NpadController.cs
+++ b/Ryujinx/Ui/NpadController.cs
@@ -107,7 +107,7 @@ namespace Ryujinx.UI.Input
             Enabled = enabled;
         }
 
-        public HidControllerButtons GetButtons()
+        public ControllerButtons GetButtons()
         {
             if (!Enabled)
             {
@@ -116,25 +116,25 @@ namespace Ryujinx.UI.Input
 
             GamePadState gpState = GamePad.GetState(Index);
 
-            HidControllerButtons buttons = 0;
+            ControllerButtons buttons = 0;
 
-            if (IsPressed(gpState, LeftJoycon.DPadUp))       buttons |= HidControllerButtons.DpadUp;
-            if (IsPressed(gpState, LeftJoycon.DPadDown))     buttons |= HidControllerButtons.DpadDown;
-            if (IsPressed(gpState, LeftJoycon.DPadLeft))     buttons |= HidControllerButtons.DpadLeft;
-            if (IsPressed(gpState, LeftJoycon.DPadRight))    buttons |= HidControllerButtons.DPadRight;
-            if (IsPressed(gpState, LeftJoycon.StickButton))  buttons |= HidControllerButtons.StickLeft;
-            if (IsPressed(gpState, LeftJoycon.ButtonMinus))  buttons |= HidControllerButtons.Minus;
-            if (IsPressed(gpState, LeftJoycon.ButtonL))      buttons |= HidControllerButtons.L;
-            if (IsPressed(gpState, LeftJoycon.ButtonZl))     buttons |= HidControllerButtons.Zl;
+            if (IsPressed(gpState, LeftJoycon.DPadUp))       buttons |= ControllerButtons.DpadUp;
+            if (IsPressed(gpState, LeftJoycon.DPadDown))     buttons |= ControllerButtons.DpadDown;
+            if (IsPressed(gpState, LeftJoycon.DPadLeft))     buttons |= ControllerButtons.DpadLeft;
+            if (IsPressed(gpState, LeftJoycon.DPadRight))    buttons |= ControllerButtons.DPadRight;
+            if (IsPressed(gpState, LeftJoycon.StickButton))  buttons |= ControllerButtons.StickLeft;
+            if (IsPressed(gpState, LeftJoycon.ButtonMinus))  buttons |= ControllerButtons.Minus;
+            if (IsPressed(gpState, LeftJoycon.ButtonL))      buttons |= ControllerButtons.L;
+            if (IsPressed(gpState, LeftJoycon.ButtonZl))     buttons |= ControllerButtons.Zl;
 
-            if (IsPressed(gpState, RightJoycon.ButtonA))     buttons |= HidControllerButtons.A;
-            if (IsPressed(gpState, RightJoycon.ButtonB))     buttons |= HidControllerButtons.B;
-            if (IsPressed(gpState, RightJoycon.ButtonX))     buttons |= HidControllerButtons.X;
-            if (IsPressed(gpState, RightJoycon.ButtonY))     buttons |= HidControllerButtons.Y;
-            if (IsPressed(gpState, RightJoycon.StickButton)) buttons |= HidControllerButtons.StickRight;
-            if (IsPressed(gpState, RightJoycon.ButtonPlus))  buttons |= HidControllerButtons.Plus;
-            if (IsPressed(gpState, RightJoycon.ButtonR))     buttons |= HidControllerButtons.R;
-            if (IsPressed(gpState, RightJoycon.ButtonZr))    buttons |= HidControllerButtons.Zr;
+            if (IsPressed(gpState, RightJoycon.ButtonA))     buttons |= ControllerButtons.A;
+            if (IsPressed(gpState, RightJoycon.ButtonB))     buttons |= ControllerButtons.B;
+            if (IsPressed(gpState, RightJoycon.ButtonX))     buttons |= ControllerButtons.X;
+            if (IsPressed(gpState, RightJoycon.ButtonY))     buttons |= ControllerButtons.Y;
+            if (IsPressed(gpState, RightJoycon.StickButton)) buttons |= ControllerButtons.StickRight;
+            if (IsPressed(gpState, RightJoycon.ButtonPlus))  buttons |= ControllerButtons.Plus;
+            if (IsPressed(gpState, RightJoycon.ButtonR))     buttons |= ControllerButtons.R;
+            if (IsPressed(gpState, RightJoycon.ButtonZr))    buttons |= ControllerButtons.Zr;
 
             return buttons;
         }
diff --git a/Ryujinx/Ui/NpadKeyboard.cs b/Ryujinx/Ui/NpadKeyboard.cs
index 1f758024..79d6330c 100644
--- a/Ryujinx/Ui/NpadKeyboard.cs
+++ b/Ryujinx/Ui/NpadKeyboard.cs
@@ -57,27 +57,27 @@ namespace Ryujinx.UI.Input
         /// </summary>
         public KeyboardHotkeys Hotkeys { get; private set; }
 
-        public HidControllerButtons GetButtons(KeyboardState keyboard)
+        public ControllerButtons GetButtons(KeyboardState keyboard)
         {
-            HidControllerButtons buttons = 0;
+            ControllerButtons buttons = 0;
 
-            if (keyboard[(Key)LeftJoycon.StickButton]) buttons |= HidControllerButtons.StickLeft;
-            if (keyboard[(Key)LeftJoycon.DPadUp])      buttons |= HidControllerButtons.DpadUp;
-            if (keyboard[(Key)LeftJoycon.DPadDown])    buttons |= HidControllerButtons.DpadDown;
-            if (keyboard[(Key)LeftJoycon.DPadLeft])    buttons |= HidControllerButtons.DpadLeft;
-            if (keyboard[(Key)LeftJoycon.DPadRight])   buttons |= HidControllerButtons.DPadRight;
-            if (keyboard[(Key)LeftJoycon.ButtonMinus]) buttons |= HidControllerButtons.Minus;
-            if (keyboard[(Key)LeftJoycon.ButtonL])     buttons |= HidControllerButtons.L;
-            if (keyboard[(Key)LeftJoycon.ButtonZl])    buttons |= HidControllerButtons.Zl;
+            if (keyboard[(Key)LeftJoycon.StickButton]) buttons |= ControllerButtons.StickLeft;
+            if (keyboard[(Key)LeftJoycon.DPadUp])      buttons |= ControllerButtons.DpadUp;
+            if (keyboard[(Key)LeftJoycon.DPadDown])    buttons |= ControllerButtons.DpadDown;
+            if (keyboard[(Key)LeftJoycon.DPadLeft])    buttons |= ControllerButtons.DpadLeft;
+            if (keyboard[(Key)LeftJoycon.DPadRight])   buttons |= ControllerButtons.DPadRight;
+            if (keyboard[(Key)LeftJoycon.ButtonMinus]) buttons |= ControllerButtons.Minus;
+            if (keyboard[(Key)LeftJoycon.ButtonL])     buttons |= ControllerButtons.L;
+            if (keyboard[(Key)LeftJoycon.ButtonZl])    buttons |= ControllerButtons.Zl;
             
-            if (keyboard[(Key)RightJoycon.StickButton]) buttons |= HidControllerButtons.StickRight;
-            if (keyboard[(Key)RightJoycon.ButtonA])     buttons |= HidControllerButtons.A;
-            if (keyboard[(Key)RightJoycon.ButtonB])     buttons |= HidControllerButtons.B;
-            if (keyboard[(Key)RightJoycon.ButtonX])     buttons |= HidControllerButtons.X;
-            if (keyboard[(Key)RightJoycon.ButtonY])     buttons |= HidControllerButtons.Y;
-            if (keyboard[(Key)RightJoycon.ButtonPlus])  buttons |= HidControllerButtons.Plus;
-            if (keyboard[(Key)RightJoycon.ButtonR])     buttons |= HidControllerButtons.R;
-            if (keyboard[(Key)RightJoycon.ButtonZr])    buttons |= HidControllerButtons.Zr;
+            if (keyboard[(Key)RightJoycon.StickButton]) buttons |= ControllerButtons.StickRight;
+            if (keyboard[(Key)RightJoycon.ButtonA])     buttons |= ControllerButtons.A;
+            if (keyboard[(Key)RightJoycon.ButtonB])     buttons |= ControllerButtons.B;
+            if (keyboard[(Key)RightJoycon.ButtonX])     buttons |= ControllerButtons.X;
+            if (keyboard[(Key)RightJoycon.ButtonY])     buttons |= ControllerButtons.Y;
+            if (keyboard[(Key)RightJoycon.ButtonPlus])  buttons |= ControllerButtons.Plus;
+            if (keyboard[(Key)RightJoycon.ButtonR])     buttons |= ControllerButtons.R;
+            if (keyboard[(Key)RightJoycon.ButtonZr])    buttons |= ControllerButtons.Zr;
 
             return buttons;
         }
@@ -108,11 +108,11 @@ namespace Ryujinx.UI.Input
             return (dx, dy);
         }
 
-        public HidHotkeyButtons GetHotkeyButtons(KeyboardState keyboard)
+        public HotkeyButtons GetHotkeyButtons(KeyboardState keyboard)
         {
-            HidHotkeyButtons buttons = 0;
+            HotkeyButtons buttons = 0;
 
-            if (keyboard[(Key)Hotkeys.ToggleVsync]) buttons |= HidHotkeyButtons.ToggleVSync;
+            if (keyboard[(Key)Hotkeys.ToggleVsync]) buttons |= HotkeyButtons.ToggleVSync;
 
             return buttons;
         }
@@ -267,9 +267,9 @@ namespace Ryujinx.UI.Input
             new KeyMappingEntry { TargetKey = Key.NumLock,      Target = 10 },
         };
 
-        public HidKeyboard GetKeysDown(KeyboardState keyboard)
+        public HLE.Input.Keyboard GetKeysDown(KeyboardState keyboard)
         {
-            HidKeyboard hidKeyboard = new HidKeyboard
+            HLE.Input.Keyboard hidKeyboard = new HLE.Input.Keyboard
             {
                     Modifier = 0,
                     Keys     = new int[0x8]