aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/Hid/HidDevices
diff options
context:
space:
mode:
authormageven <62494521+mageven@users.noreply.github.com>2020-04-03 05:40:02 +0530
committerGitHub <noreply@github.com>2020-04-03 11:10:02 +1100
commit2365ddfc363e76ac1ac9d2e32ef9b36b85463431 (patch)
tree408bdb4a35e4f625a69ddbd65f22e9f056f7ebec /Ryujinx.HLE/HOS/Services/Hid/HidDevices
parent5b5239ab5b452f991d9fc4f8ad1f9a2880b8bad1 (diff)
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
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Hid/HidDevices')
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs29
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs24
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs32
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs37
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs332
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs46
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/ControllerConfig.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/GamepadInput.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs11
11 files changed, 545 insertions, 0 deletions
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 00000000..59d6dfa3
--- /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 00000000..77e9205f
--- /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 00000000..e8ed6a3e
--- /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 00000000..ee58a563
--- /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 00000000..ff330312
--- /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 00000000..10c34453
--- /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 00000000..e59ba312
--- /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 00000000..2488057e
--- /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/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs
new file mode 100644
index 00000000..6df477d6
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+ public struct JoystickPosition
+ {
+ public int Dx;
+ public int Dy;
+ }
+} \ No newline at end of file
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 00000000..26681270
--- /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 00000000..d1172dd0
--- /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