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
This commit is contained in:
parent
5b5239ab5b
commit
2365ddfc36
105 changed files with 1500 additions and 1044 deletions
29
Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs
Normal file
29
Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs
Normal file
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
24
Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs
Normal file
24
Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
32
Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs
Normal file
32
Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
37
Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs
Normal file
37
Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs
Normal file
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
332
Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
Normal file
332
Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
46
Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
Normal file
46
Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
Normal file
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public struct ControllerConfig
|
||||
{
|
||||
public PlayerIndex Player;
|
||||
public ControllerType Type;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public struct JoystickPosition
|
||||
{
|
||||
public int Dx;
|
||||
public int Dy;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public struct KeyboardInput
|
||||
{
|
||||
public int Modifier;
|
||||
public int[] Keys;
|
||||
}
|
||||
}
|
11
Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
Normal file
11
Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue